Repository: berty/weshnet
Branch: main
Commit: b4bab092a97a
Files: 353
Total size: 2.3 MB
Directory structure:
gitextract_xdu0swom/
├── .codecov.yml
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_template.yml
│ │ ├── feature_template.yml
│ │ └── question_template.yml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ ├── weekly-digest.yml
│ └── workflows/
│ ├── benchmark.yml
│ ├── buf-push.yml
│ ├── cancel.yml
│ ├── codeql-analysis.yml
│ ├── dependent-issues.yml
│ ├── go.yml
│ ├── protobuf.yml
│ ├── release.yml
│ ├── ssh-runner.yml
│ └── utils/
│ └── variables.json
├── .gitignore
├── .golangci.yml
├── .tool-versions
├── COPYRIGHT
├── INSTALL.md
├── LICENSE-APACHE
├── LICENSE-MIT
├── Makefile
├── README.md
├── account_export.go
├── account_export_test.go
├── api/
│ ├── go-internal/
│ │ ├── buf.yaml
│ │ ├── handshake/
│ │ │ └── handshake.proto
│ │ └── tinder/
│ │ └── records.proto
│ └── protocol/
│ ├── buf.yaml
│ ├── errcode/
│ │ └── errcode.proto
│ ├── outofstoremessagetypes/
│ │ └── outofstoremessage.proto
│ ├── protocoltypes.proto
│ ├── replicationtypes/
│ │ └── bertyreplication.proto
│ └── verifiablecredstypes/
│ └── bertyverifiablecreds.proto
├── api_app.go
├── api_client.go
├── api_contact.go
├── api_contact_request_test.go
├── api_contactrequest.go
├── api_debug.go
├── api_event.go
├── api_group.go
├── api_multimember.go
├── api_replication.go
├── api_verified_credentials.go
├── blackbox_test.go
├── buf.gen.tag.yaml
├── buf.gen.yaml
├── connectedness_manager.go
├── consts.go
├── contact_request_manager.go
├── contact_request_manager_test.go
├── deactivate_test.go
├── doc.go
├── docs/
│ ├── CONTRIBUTING.md
│ ├── Makefile
│ ├── apis/
│ │ ├── protocoltypes.md
│ │ └── protocoltypes.swagger.json
│ ├── architecture/
│ │ ├── 2020-11-27-adr-berty-grpc-bridge.txt
│ │ ├── 2020-11-27-adr-gomobile-ipfs.md
│ │ ├── README.md
│ │ └── messenger-mvp/
│ │ ├── README.md
│ │ └── contact-request.mermaid
│ ├── buf-doc.gen.yaml
│ ├── gen.sum
│ ├── ideas/
│ │ ├── distributed-entropy.md
│ │ └── entropy-pool.md
│ └── protocol/
│ └── README.md
├── events.go
├── events_sig_checkers.go
├── gen.sum
├── go.mod
├── go.sum
├── group.go
├── group_context.go
├── iface_account.go
├── infra/
│ ├── .gitignore
│ ├── README.md
│ ├── rdvp/
│ │ ├── .env
│ │ ├── Makefile
│ │ └── docker-compose.yml
│ └── relay/
│ ├── Dockerfile
│ ├── Makefile
│ ├── config.json
│ └── docker-compose.yml
├── internal/
│ ├── benchmark/
│ │ └── benchmark_test.go
│ ├── bertyversion/
│ │ ├── example_test.go
│ │ └── version.go
│ ├── datastoreutil/
│ │ ├── consts.go
│ │ └── datastore_namespaced.go
│ ├── handshake/
│ │ ├── doc.go
│ │ ├── handshake.go
│ │ ├── handshake.pb.go
│ │ ├── handshake_test.go
│ │ ├── handshake_util_test.go
│ │ ├── request.go
│ │ └── response.go
│ ├── notify/
│ │ ├── notify.go
│ │ └── notify_test.go
│ ├── queue/
│ │ ├── metrics.go
│ │ ├── priority.go
│ │ ├── simple.go
│ │ └── simple_test.go
│ ├── sysutil/
│ │ ├── sysutil.go
│ │ ├── sysutil_unix.go
│ │ └── sysutil_unsupported.go
│ └── tools/
│ ├── example_test.go
│ ├── tools.go
│ └── tools_untool.go
├── message_marshaler.go
├── message_marshaler_test.go
├── orbitdb.go
├── orbitdb_datastore_cache.go
├── orbitdb_many_adds_berty_test.go
├── orbitdb_many_adds_test.go
├── orbitdb_signed_entry_accesscontroller.go
├── orbitdb_signed_entry_identity_provider.go
├── orbitdb_signed_entry_keystore.go
├── orbitdb_test.go
├── orbitdb_utils_test.go
├── pkg/
│ ├── androidnearby/
│ │ ├── bridge_android.go
│ │ ├── bridge_unsupported.go
│ │ ├── const.go
│ │ ├── example_test.go
│ │ ├── init.go
│ │ └── multiaddr.go
│ ├── bertyvcissuer/
│ │ ├── client.go
│ │ ├── urls.go
│ │ └── verifiable_public_key_fetcher.go
│ ├── ble-driver/
│ │ ├── BertyDevice_darwin.h
│ │ ├── BertyDevice_darwin.m
│ │ ├── BleInterface_darwin.h
│ │ ├── BleInterface_darwin.m
│ │ ├── BleManager_darwin.h
│ │ ├── BleManager_darwin.m
│ │ ├── BleQueue.h
│ │ ├── BleQueue.m
│ │ ├── CircularQueue.h
│ │ ├── CircularQueue.m
│ │ ├── ConnectedPeer.h
│ │ ├── ConnectedPeer.m
│ │ ├── CountDownLatch_darwin.h
│ │ ├── CountDownLatch_darwin.m
│ │ ├── Logger.h
│ │ ├── Logger.m
│ │ ├── PeerManager.h
│ │ ├── PeerManager.m
│ │ ├── TaskDelay.h
│ │ ├── TaskDelay.m
│ │ ├── WriteDataCache.h
│ │ ├── WriteDataCache.m
│ │ ├── bridge_android.go
│ │ ├── bridge_darwin.go
│ │ ├── bridge_unsupported.go
│ │ ├── const.go
│ │ ├── example_test.go
│ │ ├── init.go
│ │ └── multiaddr.go
│ ├── cryptoutil/
│ │ ├── cryptoutil.go
│ │ ├── cryptoutil_test.go
│ │ ├── doc.go
│ │ └── signer_wrapper.go
│ ├── errcode/
│ │ ├── doc.go
│ │ ├── errcode.pb.go
│ │ ├── error.go
│ │ ├── error_test.go
│ │ └── stdproto.go
│ ├── grpcutil/
│ │ ├── buf_listener.go
│ │ ├── doc.go
│ │ ├── simple_auth.go
│ │ └── simple_auth_test.go
│ ├── ipfsutil/
│ │ ├── collector_bandwidth.go
│ │ ├── collector_host.go
│ │ ├── conn_logger.go
│ │ ├── conn_manager.go
│ │ ├── consts.go
│ │ ├── doc.go
│ │ ├── extended_core_api.go
│ │ ├── helpers.go
│ │ ├── helpers_test.go
│ │ ├── keystore_datastore.go
│ │ ├── lifecycle.go
│ │ ├── localrecord.go
│ │ ├── metrics.go
│ │ ├── mobile/
│ │ │ ├── host.go
│ │ │ ├── node.go
│ │ │ ├── repo.go
│ │ │ └── routing.go
│ │ ├── mobile.go
│ │ ├── peering.go
│ │ ├── pubsub_adaptater.go
│ │ ├── pubsub_api.go
│ │ ├── pubsub_monitor.go
│ │ ├── repo.go
│ │ ├── testing.go
│ │ └── util.go
│ ├── lifecycle/
│ │ ├── example_test.go
│ │ ├── manager.go
│ │ └── task.go
│ ├── logutil/
│ │ ├── crypto_utils.go
│ │ ├── encoders.go
│ │ ├── example_test.go
│ │ ├── file.go
│ │ ├── file_test.go
│ │ ├── grpc_logger.go
│ │ ├── logger_native.go
│ │ ├── logger_native_android.go
│ │ ├── logger_native_darwin.go
│ │ ├── logger_native_other.go
│ │ ├── logutil.go
│ │ ├── logutil_test.go
│ │ ├── private_field.go
│ │ └── stream.go
│ ├── multipeer-connectivity-driver/
│ │ ├── bridge_darwin.go
│ │ ├── bridge_unsupported.go
│ │ ├── const.go
│ │ ├── driver/
│ │ │ ├── Logger.h
│ │ │ ├── Logger.m
│ │ │ ├── MCManager.h
│ │ │ ├── MCManager.m
│ │ │ ├── cgo_bridge.go
│ │ │ ├── mc-driver.h
│ │ │ └── mc-driver.m
│ │ ├── example_test.go
│ │ ├── init.go
│ │ └── multiaddr.go
│ ├── netmanager/
│ │ ├── connectivity.go
│ │ ├── netmanager.go
│ │ ├── netmanager_noop.go
│ │ └── netmanager_test.go
│ ├── outofstoremessage/
│ │ ├── outofstoremessage_test.go
│ │ └── service_outofstoremessage.go
│ ├── outofstoremessagetypes/
│ │ ├── outofstoremessage.pb.go
│ │ ├── outofstoremessage.pb.gw.go
│ │ └── outofstoremessage_grpc.pb.go
│ ├── protocoltypes/
│ │ ├── contact.go
│ │ ├── doc.go
│ │ ├── events_account.go
│ │ ├── example_test.go
│ │ ├── group.go
│ │ ├── protocoltypes.pb.go
│ │ ├── protocoltypes.pb.gw.go
│ │ └── protocoltypes_grpc.pb.go
│ ├── protoio/
│ │ ├── full.go
│ │ ├── io.go
│ │ ├── uint32.go
│ │ └── varint.go
│ ├── proximitytransport/
│ │ ├── addr.go
│ │ ├── conn.go
│ │ ├── example_test.go
│ │ ├── listener.go
│ │ ├── mplex.go
│ │ ├── proximitydriver.go
│ │ ├── ringBuffer_map.go
│ │ └── transport.go
│ ├── rendezvous/
│ │ ├── emitterio_sync_client.go
│ │ ├── emitterio_sync_provider.go
│ │ ├── emitterio_sync_test.go
│ │ ├── rendezvous.go
│ │ ├── rendezvous_test.go
│ │ └── rotation.go
│ ├── replicationtypes/
│ │ ├── bertyreplication.pb.go
│ │ ├── bertyreplication.pb.gw.go
│ │ ├── bertyreplication_grpc.pb.go
│ │ ├── consts.go
│ │ └── models.go
│ ├── secretstore/
│ │ ├── chain_key.go
│ │ ├── datastore_keys.go
│ │ ├── device_keystore_wrapper.go
│ │ ├── device_keystore_wrapper_test.go
│ │ ├── doc.go
│ │ ├── keys_utils.go
│ │ ├── member_device.go
│ │ ├── secret_store.go
│ │ ├── secret_store_interfaces.go
│ │ ├── secret_store_messages.go
│ │ ├── secret_store_messages_test.go
│ │ └── secret_store_test.go
│ ├── testutil/
│ │ ├── doc.go
│ │ ├── example_test.go
│ │ ├── filters.go
│ │ ├── logging.go
│ │ ├── require.go
│ │ ├── skip.go
│ │ ├── skip_norace.go
│ │ ├── skip_race.go
│ │ └── skip_test.go
│ ├── tinder/
│ │ ├── driver.go
│ │ ├── driver_discovery.go
│ │ ├── driver_localdiscovery.go
│ │ ├── driver_localdiscovery_test.go
│ │ ├── driver_mock.go
│ │ ├── driver_mock_test.go
│ │ ├── driver_rdvp.go
│ │ ├── driver_service_test.go
│ │ ├── filter.go
│ │ ├── notify_network.go
│ │ ├── options.go
│ │ ├── peer_cache.go
│ │ ├── peer_cache_test.go
│ │ ├── records.pb.go
│ │ ├── service.go
│ │ ├── service_adaptater.go
│ │ ├── service_advertises.go
│ │ ├── service_mocked_test.go
│ │ ├── service_subscription.go
│ │ └── testing_test.go
│ ├── tyber/
│ │ ├── context.go
│ │ ├── format.go
│ │ ├── ipfs.go
│ │ ├── log.go
│ │ ├── section.go
│ │ ├── step.go
│ │ └── subscribe.go
│ ├── username/
│ │ ├── android.go
│ │ ├── example_test.go
│ │ ├── ios.go
│ │ ├── others.go
│ │ └── username.go
│ └── verifiablecredstypes/
│ └── bertyverifiablecreds.pb.go
├── scenario_test.go
├── service.go
├── service_client.go
├── service_group.go
├── store_message.go
├── store_message_metrics.go
├── store_message_queue.go
├── store_message_test.go
├── store_metadata.go
├── store_metadata_index.go
├── store_metadata_test.go
├── store_options.go
├── store_utils.go
├── testing.go
├── testing_test.go
├── tinder_swiper.go
├── tinder_swiper_test.go
├── tool/
│ ├── bench-cellular/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── bench.go
│ │ ├── client.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── server.go
│ └── docker-protoc/
│ ├── Dockerfile
│ └── Makefile
└── tyber.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .codecov.yml
================================================
codecov:
notify:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "1...100"
status:
project: no
patch: no
changes: no
ignore:
- "**/*.gen.go"
- "**/generated.go"
- "**/*.pb.go"
- "**/*.pb.gw.go"
- "**/gen/**"
flags:
go.unittests:
carryforward: true
js.unittests:
carryforward: true
================================================
FILE: .dockerignore
================================================
*#
*~
.#*
.DS_Store
.agignore
.env
.projectile
Dockerfile
core-sources.jar
coverage.txt
dist/
gen.sum.tmp
gin-bin
google-services.json
js/
out/
profile.out
vendor/
tool/
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
[*.go]
indent_style = tab
[*.proto]
indent_size = 2
[*.swift]
indent_size = 4
[*.tmpl]
indent_size = 2
[*.{js,jsx,ts,tsx}]
indent_size = 2
indent_style = tab
block_comment_start = /*
block_comment_end = */
[*.hbs]
indent_size = 4
indent_style = tab
block_comment_start = {{!
block_comment_end = }}
[*.html]
indent_size = 2
[*.bat]
end_of_line = crlf
[*.{json,yml}]
indent_size = 2
indent_style = space
[.{babelrc,eslintrc}]
indent_size = 2
[{Fastfile,.buckconfig,BUCK}]
indent_size = 2
[*.diff]
indent_size = 1
[*.m]
indent_size = 1
indent_style = space
block_comment_start = /**
block_comment = *
block_comment_end = */
[*.java]
indent_size = 4
indent_style = space
block_comment_start = /**
block_comment = *
block_comment_end = */
[js/packages/i18n/locale/**/*.{json,yml}]
indent_size = 2
indent_style = tab
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
# Collapse vendored files on GitHub
vendor/* linguist-vendored
*/vendor/* linguist-vendored
client/common/openssl/built/* linguist-vendored
# Collapse generated files on GitHub
gen.sum linguist-generated merge=ours -diff
*.gen.go linguist-generated merge=ours -diff
*.gen.graphql linguist-generated merge=ours -diff
*.gen.js linguist-generated merge=ours -diff
*.gen.json linguist-generated merge=ours -diff
*.gen.ts linguist-generated merge=ours -diff
*.gen.tsx linguist-generated merge=ours -diff
*.gen.yml linguist-generated merge=ours -diff
*.pb.d.ts linguist-generated merge=ours -diff
*.pb.go linguist-generated merge=ours -diff
*.pb.gw.go linguist-generated merge=ours -diff
*.pb.js linguist-generated merge=ours -diff
*pb_test.go linguist-generated merge=ours -diff
docs/apis/*types.md linguist-generated merge=ours -diff
*.swagger.json linguist-generated merge=ours -diff
api/*.yaml linguist-generated merge=ours -diff
/js/packages/store/protocol/grpc-web-gen/** linguist-generated merge=ours -diff
go.sum linguist-generated text
yarn.lock linguist-generated text -diff
Podfile.lock linguist-generated text -diff
package.json linguist-generated
go.mod text
# Collapse snapshot files on GitHub
*.snap linguist-generated
# Reduce conflicts on markdown files
*.md merge=union
# specific for windows script files
*.bat text eol=crlf
================================================
FILE: .github/ISSUE_TEMPLATE/bug_template.yml
================================================
# yamllint disable-line rule:document-start
name: "Bug report"
description: Report a bug found while using weshnet.
labels: ["bug"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: >-
Please search to see if an issue already exists for the bug you
encountered.
options:
- label: I have searched the existing issues
required: true
- type: input
id: package-version
attributes:
label: Package version
description: What version of weshnet are you using?
placeholder: v1.0.3
validations:
required: true
- type: dropdown
id: os
attributes:
label: OS
description: What OS are you seeing the problem on?
options:
- iOS
- Android
- Linux
- macOS
- Windows
- Other
- type: input
id: language-version
attributes:
label: Language version and compiler version
description: What programming language version and compiler are you using?
placeholder: >-
go1.18.4, javac 11.0.12
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Bug description
description: Provide a bug description and a code snippet if applicable.
placeholder: |
1. Set up this environment ...
2. Add this code ...
3. Call this function ...
validations:
required: true
- type: textarea
id: current-behavior
attributes:
label: Current behavior
description: >-
Output after code execution including stack traces, debug logs, etc.
placeholder: Currently ...
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: Please provide what would be your expectation to happen.
placeholder: In this situation, weshnet should ...
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: What is your development environment?
placeholder: macOS 13.1
validations:
required: true
- type: textarea
id: other
attributes:
label: Other
placeholder: Any other details?
================================================
FILE: .github/ISSUE_TEMPLATE/feature_template.yml
================================================
# yamllint disable-line rule:document-start
name: "Feature request"
description: Suggest an idea for this project.
labels: [":rocket: feature-request"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: >-
Please search to see if an issue already exists for this feature
request.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: feature
attributes:
label: Feature request
description: >-
Provide a detailed description of the change or addition you are
proposing.
placeholder: There should be ...
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: >-
Why is this change important to you? How would you use it? How can it
benefit other users?
placeholder: This feature request is important because ...
validations:
required: true
- type: textarea
id: implementation
attributes:
label: Possible implementation
description: >-
Not obligatory, but suggest an idea for implementing addition or change.
placeholder: This feature could be implemented by ...
================================================
FILE: .github/ISSUE_TEMPLATE/question_template.yml
================================================
# yamllint disable-line rule:document-start
name: "Question"
description: Ask a question about this project.
labels: ["question"]
body:
- type: checkboxes
attributes:
label: Asking a question, not reporting a bug
description: >-
If your question is "Why did I get this error?" and you think it is a
bug, then please open a Bug Report at
https://github.com/berty/weshnet/issues/new/
options:
- label: This question is not about a bug
required: true
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: >-
Please search to see if an issue already exists for your question.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: question
attributes:
label: Question
description: >-
Provide your question with enough detail that it is helpful to anyone
reading the question (maybe years later).
placeholder: How do I ...
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: >-
Is it a general question about the design and goals of weshnet, or
about how to use it in an app (or some other context)?
placeholder: This is a question about ...
validations:
required: true
================================================
FILE: .github/dependabot.yml
================================================
version: 2
# @NOTE(gfanton): we use 0 as pull-request-limit to only enable security update.
# see: https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#overriding-the-default-behavior-with-a-configuration-file
updates:
- package-ecosystem: docker
directory: "/tool/docker-protoc"
schedule:
interval: daily
# Disable version updates for docker dependencies (enable only security update)
open-pull-requests-limit: 0
labels:
- "security"
- "t/docker"
- "dependencies"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
# Disable version updates for github dependencies (enable only security update)
open-pull-requests-limit: 0
labels:
- "security"
- "t/github-actions"
- "dependencies"
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
# Disable version updates for gomod dependencies (enable only security update)
open-pull-requests-limit: 0
labels:
- "security"
- "t/golang"
- "dependencies"
================================================
FILE: .github/pull_request_template.md
================================================
================================================
FILE: .github/weekly-digest.yml
================================================
# Configuration for weekly-digest - https://github.com/apps/weekly-digest
publishDay: thu
canPublishIssues: true
canPublishPullRequests: true
canPublishContributors: true
canPublishStargazers: true
canPublishCommits: true
================================================
FILE: .github/workflows/benchmark.yml
================================================
name: Go benchmark
on:
push:
tags:
- v*
branches:
- main
paths:
- "**"
- "!**.md"
- "go.*"
- "**.go"
- ".github/workflows/benchmark.yml"
pull_request:
paths:
- "**"
- "!**.md"
- "go.*"
- "**.go"
- ".github/workflows/benchmark.yml"
jobs:
benchmark:
if: github.event_name == 'DISABLED'
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup Graphviz
uses: ts-graphviz/setup-graphviz@v1
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 50 # this is to make sure we obtain the target base commit#
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
go install golang.org/x/perf/cmd/benchstat@latest
asdf reshim golang
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Run benchmark
run: make go.unittest | tee output_head.txt
working-directory: .
env:
TEST_SPEED: any
GO_TEST_PATH: ./internal/benchmark
GO_TEST_OPTS: -bench=. -test.benchmem -cpuprofile cpu_head.prof -memprofile mem_head.prof -test.timeout=1200s -count=5
- name: Checkout base commit
run: git checkout ${{ github.event.pull_request.base.sha }}
if: github.event_name == 'pull_request'
- name: Cache go modules (main)
uses: actions/cache@v4
if: github.event_name == 'pull_request'
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Run benchmark (main)
run: make go.unittest | tee output_base.txt
if: github.event_name == 'pull_request'
working-directory: .
env:
TEST_SPEED: any
GO_TEST_PATH: ./internal/benchmark
GO_TEST_OPTS: -bench=. -test.benchmem -cpuprofile cpu_base.prof -memprofile mem_base.prof -test.timeout=1200s -count=5
- name: Benchstat
id: benchstat-main
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
run: |
echo 'Benchmark report' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
benchstat output_head.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
working-directory: .
- name: Benchstat PR
id: benchstat-pr
if: github.event_name == 'pull_request'
run: |
echo 'Benchmark report' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
benchstat output_head.txt output_base.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
working-directory: .
- name: Generate pprof html files
id: pprof-html-files-no-relative
working-directory: .
run: |
mkdir -p pprof_html/head/{cpu,mem}/{top,flamegraph,peek,source}
go tool pprof -http 0.0.0.0:9402 -no_browser ./cpu_head.prof < /dev/null & # https://github.com/google/pprof/issues/401#issuecomment-739576424
sleep 2
curl http://localhost:9402/ui/ > pprof_html/head/cpu/index.html
curl http://localhost:9402/ui/top > pprof_html/head/cpu/top/index.html
curl http://localhost:9402/ui/flamegraph > pprof_html/head/cpu/flamegraph/index.html
curl http://localhost:9402/ui/peek > pprof_html/head/cpu/peek/index.html
curl http://localhost:9402/ui/source > pprof_html/head/cpu/source/index.html
pkill pprof
sleep 2
go tool pprof -http 0.0.0.0:9402 -no_browser ./mem_head.prof < /dev/null &
sleep 2
curl http://localhost:9402/ui/ > pprof_html/head/mem/index.html
curl http://localhost:9402/ui/top > pprof_html/head/mem/top/index.html
curl http://localhost:9402/ui/flamegraph > pprof_html/head/mem/flamegraph/index.html
curl http://localhost:9402/ui/peek > pprof_html/head/mem/peek/index.html
curl http://localhost:9402/ui/source > pprof_html/head/mem/source/index.html
pkill pprof
sleep 2
cat << EOF > pprof_html/index.html
pprof output
CPU output
Memory output
EOF
- name: Generate pprof html files (PR)
if: github.event_name == 'pull_request'
id: pprof-html-files-pr
working-directory: .
run: |
mkdir -p pprof_html/base_comp/{cpu,mem}
go tool pprof -http 0.0.0.0:9402 --diff_base=./cpu_base.prof -no_browser ./cpu_head.prof < /dev/null &
sleep 2
curl http://localhost:9402/ui/ > pprof_html/base_comp/cpu/index.html
pkill pprof
sleep 2
go tool pprof -http 0.0.0.0:9402 --diff_base=./mem_base.prof -no_browser ./mem_head.prof < /dev/null &
sleep 2
curl http://localhost:9402/ui/ > pprof_html/base_comp/mem/index.html
pkill pprof
sleep 2
cat << EOF >> pprof_html/index.html
CPU diff against ${{ github.event.pull_request.base.sha }}
Memory diff against ${{ github.event.pull_request.base.sha }}
EOF
- name: Generate pprof html files (footer)
id: pprof-html-files-footer
working-directory: .
run: |
cat << EOF >> pprof_html/index.html
EOF
# upload arifacts
#
- name: upload artifact (main)
uses: actions/upload-artifact@v3
if: github.ref == 'refs/heads/main'
with:
name: "bench-main"
path: go/pprof_html
- name: upload artifact (PR)
uses: actions/upload-artifact@v3
if: github.event_name == 'pull_request'
with:
name: "bench-${{ github.event.pull_request.number }}"
path: go/pprof_html
================================================
FILE: .github/workflows/buf-push.yml
================================================
name: buf-push
on:
push:
branches:
- main
# from https://docs.buf.build/ci-cd/github-actions#buf-push
jobs:
buf-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: bufbuild/buf-setup-action@v1
# @TODO(gfanton): enable this ?
# - uses: bufbuild/buf-lint-action@v1
# - uses: bufbuild/buf-breaking-action@v1
# with:
# # The 'main' branch of the GitHub repository that defines the module.
# against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=main,ref=HEAD~1"
- uses: bufbuild/buf-push-action@v1
with:
input: "api/protocol"
buf_token: ${{ secrets.BUF_TOKEN }}
================================================
FILE: .github/workflows/cancel.yml
================================================
name: Cancel
on:
workflow_run:
workflows: [
"CodeQL",
"Dependent Issues",
"Go",
"Integration",
"macOS Release",
"Protobuf",
]
types:
- requested
jobs:
cancel_pr_prev_push:
name: Cancel previous runs on PR update
if: ${{ github.event_name == 'workflow_run' }}
runs-on: ubuntu-latest
steps:
- uses: styfle/cancel-workflow-action@0.11.0
with:
workflow_id: ${{ github.event.workflow.id }}
================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
paths:
- '**'
- '!**.md'
- 'go.*'
- '**.go'
- '.github/workflows/codeql-analysis.yml'
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
paths:
- '**'
- '!**.md'
- 'go.*'
- '**.go'
- '.github/workflows/codeql-analysis.yml'
schedule:
- cron: '28 12 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
================================================
FILE: .github/workflows/dependent-issues.yml
================================================
name: Dependent Issues
on:
issues:
types:
- opened
- edited
- reopened
pull_request_target:
types:
- opened
- edited
- reopened
- synchronize
schedule:
- cron: "42 2 * * *" # schedule daily check
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: z0al/dependent-issues@v1.5.1
env:
# (Required) The token to use to make API calls to GitHub.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# (Optional) The label to use to mark dependent issues
label: dependent
# (Optional) Enable checking for dependencies in issues. Enable by
# setting the value to "on". Default "off"
check_issues: off
# (Optional) A comma-separated list of keywords. Default
# "depends on, blocked by"
keywords: depends on, blocked by
================================================
FILE: .github/workflows/go.yml
================================================
name: Go
on:
push:
tags:
- v*
branches:
- main
paths:
- "**"
- "!**.md"
- "go.*"
- "**.go"
- ".github/workflows/go.yml"
pull_request:
paths:
- "**"
- "!**.md"
- "go.*"
- "**.go"
- ".github/workflows/go.yml"
jobs:
golangci-lint:
name: Golangci-lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup golang
run: |
asdf plugin add golang
asdf install golang
- name: Setup golangci-lint
run: |
asdf plugin add golangci-lint
asdf install golangci-lint
- name: Run golangci-lint
run: make lint
# this is not very common to have a job that checks the flappy tests.
#
# reason: some tests are flappy, they works, but not always;
# this job checks that they are working sometimes.
# if this job fails, then a test is "broken", not "flappy".
#
# summary: this job checks that "flappy tests" do not become "broken tests".
#
# we hope we can remove this job because all the tests are stable 100% of the time
flappy-tests:
name: Flappy tests (Linux)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Avoid triggering make generate
run: touch gen.sum
- name: Fetch go modules
run: go mod download
- name: Compile the testing binaries
run: |
pushd . && go test -c -o ./tests.bin . && popd
- name: Check go.mod and go.sum
run: |
go mod tidy -v
git --no-pager diff go.mod go.sum
git --no-pager diff --quiet go.mod go.sum
- name: Run fast flappy tests
env:
TEST_SPEED: fast
TEST_STABILITY: flappy
run: make go.flappy-tests
go-tests-on-linux:
name: Stable tests (Linux)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Check go.mod and go.sum
run: |
go mod tidy -v
git --no-pager diff go.mod go.sum
git --no-pager diff --quiet go.mod go.sum
- name: Run fast tests multiple times
env:
TEST_SPEED: fast
GO_TEST_OPTS: -test.timeout=600s -count 1
run: set -o pipefail; make go.unittest | tee test_log.txt
- name: Run all tests
env:
TEST_SPEED: any
GO_TEST_OPTS: -test.timeout=600s -count 1
run: make go.unittest
- name: Run all tests with race flag and generate coverage
env:
TEST_SPEED: any
GO_TEST_OPTS: -test.timeout=1200s -count=1 -race -cover -coverprofile=coverage.txt -covermode=atomic
run: make go.unittest
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.1.1
env:
OS: ${{ runner.os }}
GOLANG: ${{ env.go_version }}
with:
file: ./go/coverage.txt
flags: go.unittests
env_vars: OS,GOLANG
name: codecov-umbrella
fail_ci_if_error: false
go-tests-on-windows:
name: Stable tests (Windows)
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Get go version
shell: bash
run: echo "go_version=$(cat .tool-versions | grep '^golang [0-9]\+\.[0-9]\+\.[0-9]\+.*$' | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: ${{ env.go_version }}
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Check go.mod and go.sum
run: |
go mod tidy -v
git --no-pager diff go.mod go.sum
git --no-pager diff --quiet go.mod go.sum
- name: Run fast tests multiple times
env:
TEST_SPEED: fast
run: go.exe test ./... -buildmode=exe -timeout=600s -count=5
- name: Run all tests
env:
TEST_SPEED: any
run: go.exe test ./... -buildmode=exe -timeout=600s -count=1
go-tests-on-macos:
name: Stable tests (macOS)
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Check go.mod and go.sum
run: |
go mod tidy -v
git --no-pager diff go.mod go.sum
git --no-pager diff --quiet go.mod go.sum
- name: Run fast tests multiple times
env:
TEST_SPEED: fast
GO_TEST_OPTS: -test.timeout=600s -count 1
run: set -o pipefail; make go.unittest | tee test_log.txt
- name: Run all tests
env:
TEST_SPEED: any
GO_TEST_OPTS: -test.timeout=600s -count 1
run: make go.unittest
- name: Run all tests with race flag and generate coverage
env:
TEST_SPEED: any
GO_TEST_OPTS: -test.timeout=1200s -count=1 -race -cover -coverprofile=coverage.txt -covermode=atomic
run: make go.unittest
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.1.1
env:
OS: ${{ runner.os }}
GOLANG: ${{ env.go_version }}
with:
file: ./go/coverage.txt
flags: go.unittests
env_vars: OS,GOLANG
name: codecov-umbrella
fail_ci_if_error: false
# TODO: consider adding various GOARCH check per OS.
# i.e., to validate that we build on 32/64bit.
================================================
FILE: .github/workflows/protobuf.yml
================================================
name: Protobuf
on:
push:
tags:
- v*
branches:
- main
paths:
- "api/**"
- "Makefile"
- "docs/Makefile"
- ".github/workflows/protobuf.yml"
- "**/gen.sum"
- "**.pb.go"
- "**.gen.go"
- "**.gen.graphql"
- "**.gen.yml"
- "**.pb.go"
- "**/pb_test.go"
- "**/docs/*/api.md"
- "**/go.mod"
- "**/go.sum"
pull_request:
paths:
- "api/**"
- "Makefile"
- "docs/Makefile"
- ".github/workflows/protobuf.yml"
- "**/gen.sum"
- "**.pb.go"
- "**.gen.go"
- "**.gen.graphql"
- "**.gen.yml"
- "**.pb.go"
- "**/pb_test.go"
- "**/docs/*/api.md"
- "**/go.mod"
- "**/go.sum"
jobs:
gen-go-and-docs:
if: github.event_name == 'DISABLED' # need to fix it by removing docker for generation
name: Generate go protobuf and docs
runs-on: ubuntu-latest
container: bertytech/buf:1
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Unshallow
run: git fetch --prune --unshallow
- name: Remove lock files
run: find . -name gen.sum -delete
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Setup jq
run: |
asdf plugin add jq
asdf install jq
- name: Cache go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Fetch go modules
run: go mod download
- name: Generate docs
working-directory: docs
run: make generate_local
- name: Generate go protobuf
run: |
make generate_local
git checkout go.mod go.sum
- name: Check diff
run: |
git status | cat
git diff -w | cat
git diff-index -w --quiet HEAD --
- name: Prepare openapi documentation
working-directory: docs
run: make openapi.prepare
- name: Setup apiary
run: apk --no-cache add ruby-dev g++ && gem install apiaryio
- name: Upload API docs to apiary.io
env:
APIARY_API_KEY: "${{ secrets.APIARY_API_KEY }}"
if: ${{ env.APIARY_API_KEY != 0 }}
run: |
apiary publish --api-name=bertyprotocol --path="docs/.tmp/openapi/bertyprotocol.swagger.json" || true
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches:
- main
pull_request:
paths:
# Go
- "**"
- "!**.md"
- ".goreleaser"
- "go.*"
- "**.go"
# CI
- ".github/workflows/release.yml"
jobs:
semantic-release:
name: Semantic release
runs-on: ubuntu-latest
outputs:
new-release-published: ${{ steps.semantic-echo.outputs.new-release-published }}
release-version: ${{ steps.semantic-echo.outputs.release-version }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Unshallow
run: git fetch --prune --unshallow
- name: Run Semantic Release
id: semantic
uses: docker://ghcr.io/codfish/semantic-release-action:v1
with:
branches: |
['main']
plugins: |
[
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
'@semantic-release/github'
]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Export Semantic Release
id: semantic-echo
run: |
echo "::set-output name=new-release-published::${{steps.semantic.outputs.new-release-published}}"
echo "::set-output name=release-version::${{steps.semantic.outputs.release-version}}"
post-semantic-release:
needs: semantic-release
#if: needs.semantic-release.outputs.new-release-published == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Unshallow
run: git fetch --prune --unshallow
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
run: |
asdf plugin add golang
asdf install golang
- name: Register version on pkg.go.dev
if: needs.semantic-release.outputs.new-release-published == 'true'
run: |
package=$(cat go.mod | grep ^module | awk '{print $2}')
version=v${{ needs.semantic-release.outputs.release-version }}
url=https://proxy.golang.org/${package}/@v/${version}.info
set -x +e
curl -i $url
================================================
FILE: .github/workflows/ssh-runner.yml
================================================
name: SSH on runner
on:
workflow_dispatch:
inputs:
os:
description: "Operating System"
required: true
default: ubuntu-latest
type: choice
options:
- ubuntu-latest
- macos-latest
- windows-latest
mod:
description: "Install Go/Node modules"
required: true
default: true
type: boolean
jobs:
setup-ssh:
name: Setup runner and open SSH endpoint
runs-on: ${{ github.event.inputs.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
persist-credentials: false
- name: Load variables from file
uses: antifree/json-to-variables@v1.0.1
with:
filename: .github/workflows/utils/variables.json
- name: Setup asdf
uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
with:
asdf_version: 0.16.7
- name: Setup go
if: runner.os != 'Windows'
run: |
asdf plugin add golang
asdf install golang
echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 2)" >> $GITHUB_ENV
- name: Cache go modules
if: github.event.inputs.mod == 'true' && runner.os != 'Windows'
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-
- name: Fetch go modules
if: github.event.inputs.mod == 'true' && runner.os != 'Windows'
working-directory: .
run: go mod tidy
- name: Install emacs
shell: bash
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
sudo apt-get install -y emacs
elif [ "$RUNNER_OS" == "Windows" ]; then
choco install emacs
else
echo "Already installed!"
fi
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
================================================
FILE: .github/workflows/utils/variables.json
================================================
{
"cache-versions": {
"go": "1"
}
}
================================================
FILE: .gitignore
================================================
*#
*~
.#*
.DS_Store
.agignore
.env
.projectile
.tmp/
.idea/
*.bin
*.swp
.vscode
core-sources.jar
coverage.txt
dist/
gen.sum.tmp
gin-bin
out/
profile.out
vendor/
debug.log
benchmark_result.json
# Delve's binaries
*__debug_bin
# Dev dbs
/*gui.d
================================================
FILE: .golangci.yml
================================================
run:
deadline: 1m
tests: false
issues:
exclude-files:
- ".*\\.pb\\.go$"
- ".*\\.pb\\.gw\\.go$"
- ".*\\.gen\\.go$"
- "_test\\.go$"
- "testing.go$"
- ".*doc\\.go$"
linters-settings:
golint:
min-confidence: 0
maligned:
suggest-new: true
misspell:
locale: US
gci:
sections:
- standard
- default
- prefix(berty.tech)
# - prefix(github.com/libp2p)
# - prefix(github.com/ipfs)
linters:
disable-all: true
enable:
- asciicheck
- bodyclose
#- depguard
- dogsled
- errcheck
#- exhaustive # nice to have
- exportloopref
- gci
- gochecknoinits
#- gocognit # nice to have
#- goconst
- gocritic
#- godot # nice to have
#- goerr113 # nice to have
- gofmt
- gofumpt
- goimports
- revive
#- gomnd # nice to have
- gomodguard
- gosec
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- noctx
#- nolintlint
- exportloopref
- staticcheck
- typecheck
- unconvert
- unparam
- unused
- whitespace
================================================
FILE: .tool-versions
================================================
# To see the date when a version was updated, use git blame:
# https://github.com/berty/weshnet/blame/main/.tool-versions
#-----
# This is simply the most recent version available to date of the lowest
# major version of Go which is allowed by kubo.
# There is no contraindication for updating it.
#-----
golang 1.22.5
#-----
# This is simply the most recent golangci-lint version available to date.
#-----
golangci-lint 1.59.1
#-----
# This is simply the most recent jq version available to date.
# There is no contraindication for updating it.
#-----
jq 1.6
#-----
# This is simply the most recent buf version available to date.
# There is no contraindication for updating it.
#-----
buf 1.39.0
================================================
FILE: COPYRIGHT
================================================
Copyright 2018-2023 Berty Technologies and other Berty Developers.
Intellectual Property Notice
----------------------------
Berty is licensed under the Apache License, Version 2.0
(see LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or
the MIT license (see LICENSE-MIT or http://opensource.org/licenses/MIT),
at your option.
Copyrights and patents in the Berty project are retained
by contributors.
No copyright assignment is required to contribute to Berty
SPDX-License-Identifier: (Apache-2.0 OR MIT)
SPDX usage
----------
Individual files may contain SPDX tags instead of the full license text.
This enables machine processing of license information based on the SPDX
License Identifiers that are available here: https://spdx.org/licenses/
================================================
FILE: INSTALL.md
================================================
# Build weshnet
These are instructions to build weshnet.
## Prerequisites
* Required: asdf
* Required on macOS: Command Line Developer Tools
Following are the steps to install each prerequisite (if it's needed for your
build target).
### macOS 14, macOS 15 and macOS 26
To install the Command Line Developer Tools, in a terminal enter:
xcode-select --install
To install asdf using brew, follow instructions at https://asdf-vm.com . In short,
first install brew following the instructions at https://brew.sh . Then, in
a terminal enter:
brew install asdf gpg
If your terminal is zsh, enter:
echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc
If your terminal is bash, enter:
echo -e "\n. \"$(brew --prefix asdf)/libexec/asdf.sh\"" >> ~/.bash_profile
Start a new terminal to get the changes to .zshrc .
### Ubuntu 18.04, 20.04, 22.04 and 24.04
To install asdf, follow instructions at https://asdf-vm.com . In short, in
a terminal enter:
sudo apt install curl git build-essential
git clone https://github.com/asdf-vm/asdf.git ~/.asdf
echo '. "$HOME/.asdf/asdf.sh"' >> ~/.bashrc
Start a new terminal to get the changes to .bashrc .
## Build
In a terminal, enter:
git clone https://github.com/berty/weshnet
cd weshnet
First time only (or after updating .tool-versions), enter:
make asdf.install_tools
To run the tests, enter:
make test
Or you can make other targets. See:
make help
================================================
FILE: LICENSE-APACHE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. 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.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor 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
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You 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 the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You 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 such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
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. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2021 Berty Technologies
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: LICENSE-MIT
================================================
Copyright (c) 2018-2021 Berty Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
##
## Config
##
GO ?= go
GOPATH ?= $(HOME)/go
GO_TAGS ?= -tags ""
GO_TEST_OPTS ?= -test.timeout=300s -race -cover -coverprofile=coverage.txt -covermode=atomic $(GO_TAGS)
GO_TEST_PATH ?= ./...
GO_TEST_ENV ?=
CI ?= false
BUILD_DATE ?= `date +%s`
VCS_REF ?= `git rev-parse --short HEAD`
VERSION ?= `go run github.com/mdomke/git-semver/v5`
LDFLAGS ?= -ldflags="-X berty.tech/weshnet/internal/bertyversion.VcsRef=$(VCS_REF) -X berty.tech/weshnet/internal/bertyversion.Version=$(VERSION)"
# @FIXME(gfanton): on macOS Monterey (12.0.x) we currently need to set the
# environment variable `MallocNanoZone` to 0 to avoid a SIGABRT or SIGSEGV
# see https://github.com/golang/go/issues/49138
MACOS_VERSION=$(shell defaults read /System/Library/CoreServices/SystemVersion.plist 'ProductVersion' 2>/dev/null | sed 's/\.[0-9]$$//')
ifeq ($(MACOS_VERSION),12.0)
GO_TEST_ENV := MallocNanoZone=0 $(GO_TEST_ENV)
endif
ifeq ($(MACOS_VERSION),12.1)
GO_TEST_ENV := MallocNanoZone=0 $(GO_TEST_ENV)
endif
##
## General rules
##
all: help
.PHONY: all
help:
@echo "Available make commands:"
@cat Makefile | grep '^[a-z]' | grep -v '=' | cut -d: -f1 | sort | sed 's/^/ /'
.PHONY: help
test: unittest lint tidy
.PHONY: test
unittest: go.unittest
.PHONY: unittest
generate: pb.generate docs.generate
.PHONY: generate
regenerate: gen.clean docs.clean generate docs.generate
.PHONY: regenerate
clean: gen.clean docs.clean
rm -rf out/
.PHONY: clean
re: clean generate
.PHONY: re
tidy: go.tidy
.PHONY: tidy
lint: go.lint
.PHONY: lint
lint.fix: go.fmt
.PHONY: lint.fix
##
## Other rules
##
check-program = $(foreach exec,$(1),$(if $(shell PATH="$(PATH)" which $(exec)),,$(error "No $(exec) in PATH")))
go.tidy: pb.generate
$(call check-program, $(GO))
GO111MODULE=on $(GO) mod tidy
.PHONY: go.tidy
go.lint: pb.generate
$(call check-program, golangci-lint)
golangci-lint run --timeout=5m $(if $(filter $(CI), false), --verbose) ./...
.PHONY: go.lint
go.unittest: pb.generate
$(call check-program, $(GO))
$(GO_TEST_ENV) GO111MODULE=on $(GO) test $(GO_TEST_OPTS) $(GO_TEST_PATH)
.PHONY: go.unittest
go.flappy-tests: pb.generate
TEST_STABILITY=flappy go run moul.io/testman test -v -test.v -timeout=600s -retry=10 -run ^TestFlappy ./
TEST_STABILITY=flappy go run moul.io/testman test -v -test.v -timeout=600s -retry=10 -run ^TestScenario_ ./
TEST_STABILITY=flappy go run moul.io/testman test -v -test.v -timeout=600s -retry=10 -run ^TestFlappy ./pkg/tinder
# FIXME: run on other packages too
.PHONY: go.flappy-tests
go.broken-tests: pb.generate
TEST_STABILITY=broken go run moul.io/testman test -continue-on-error -timeout=1200s -test.timeout=60s -retry=5 -run ^TestScenario_ ./
.PHONY: go.broken-tests
print-%:
@echo $* = $($*)
minimum_go_minor_version = 14
validate-go-version:
@if [ ! "x`$(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1`" = "x1" ]; then \
echo "error: Golang version should be \"1.x\". Please use 1.$(minimum_go_minor_version) or more recent."; \
exit 1; \
fi
@if [ `$(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2` -lt $(minimum_go_minor_version) ]; then \
echo "error: Golang version is not supported. Please use 1.$(minimum_go_minor_version) or more recent."; \
exit 1; \
fi
.PHONY: validate-go-version
##
## Code gen
##
protos_src := $(wildcard ../api/*.proto) $(wildcard ../api/go-internal/*.proto)
gen_src := $(protos_src) Makefile
gen_sum := gen.sum
protoc_opts := -I ../api:`go list -m -mod=mod -f {{.Dir}} github.com/grpc-ecosystem/grpc-gateway`/third_party/googleapis:`go list -m -mod=mod -f {{.Dir}} github.com/gogo/protobuf`:/protobuf
pb.generate: gen.sum validate-go-version
$(gen_sum): $(gen_src)
$(call check-program, shasum docker $(GO))
@shasum $(gen_src) | sort -k 2 > $(gen_sum).tmp
@diff -q $(gen_sum).tmp $(gen_sum) || ( \
uid=`id -u`; \
set -xe; \
$(GO) mod download; \
docker run \
--user="$$uid" \
--volume="`go env GOPATH`/pkg/mod:/go/pkg/mod" \
--volume="$(PWD):/go/src/berty.tech/weshnet" \
--workdir="/go/src/berty.tech/weshnet" \
--entrypoint="sh" \
--rm \
bertytech/buf:5 \
-xec 'make generate_local'; \
$(MAKE) tidy \
)
.PHONY: pb.generate
generate_local:
go version
$(call check-program, shasum buf)
buf generate api/go-internal;
buf generate api/protocol;
buf generate --template buf.gen.tag.yaml api/go-internal;
buf generate --template buf.gen.tag.yaml api/protocol;
$(MAKE) go.fmt
shasum $(gen_src) | sort -k 2 > $(gen_sum).tmp
mv $(gen_sum).tmp $(gen_sum)
.PHONY: generate_local
go.fmt:
go run github.com/daixiang0/gci write . \
--skip-generated -s 'standard,default,prefix(berty.tech)'
go run mvdan.cc/gofumpt -w .
.PHONY: go.fmt
pkger.generate:
$(GO) run github.com/markbates/pkger/cmd/pkger -o go/pkg/assets/
.PHONY: pkger.generate
gen.clean:
rm -f gen.sum $(wildcard */*/*.pb.go) $(wildcard */*/*pb_test.go) $(wildcard */*/*pb.gw.go)
.PHONY: gen.clean
pb.push:
buf push api/protocol
##
## Docs gen
##
docs.generate:
cd docs; $(MAKE) generate
.PHONY: docs.generate
docs.clean:
cd docs; $(MAKE) clean
.PHONY: docs.generate
asdf.install_plugins:
$(call check-program, asdf)
@echo "Installing asdf plugins..."
@set -e; \
for PLUGIN in $$(cut -d' ' -f1 .tool-versions | grep "^[^\#]"); do \
asdf plugin add $$PLUGIN || [ $$?==2 ] || exit 1; \
done
.PHONY: asdf.install_plugins
asdf.install_tools: asdf.install_plugins
$(call check-program, asdf)
@echo "Installing asdf tools..."
@asdf install
.PHONY: asdf.install_tools
================================================
FILE: README.md
================================================
# Wesh Network Toolkit
[](https://pkg.go.dev/berty.tech/weshnet)
The Wesh network toolkit lets your application use the
[Wesh protocol](https://berty.tech/docs/protocol) to support privacy-based, off-grid, peer-to-peer communication.
Wesh powers [Berty Messenger](https://github.com/berty/berty#readme), and now you can use
the Wesh network toolkit directly.
Your application interfaces to Wesh based on [gRPC](https://grpc.io). So even though
the core Wesh code is written in Go, Wesh works with your application written in Go, Python
or [other languages](https://grpc.io/docs/languages) supported by gRPC.
For details, see the Wesh website at https://wesh.network .
The website includes [blog tutorials](https://wesh.network/blog) which introduce you to
Wesh and walk you through some example applications and background of the Wesh protocol.
## Usage
```go
import "berty.tech/weshnet"
```
Online API documentation is at https://buf.build/berty-technologies/weshnet .
## Get the code
To get the code and build, see the file
[INSTALL.md](https://github.com/berty/weshnet/blob/master/INSTALL.md).
## Feedback
For bug reports, feature requests or questions, please open a
[GitHub issue](https://github.com/berty/weshnet/issues/new/choose).
================================================
FILE: account_export.go
================================================
package weshnet
import (
"archive/tar"
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"strings"
"github.com/ipfs/go-cid"
cbornode "github.com/ipfs/go-ipld-cbor"
coreiface "github.com/ipfs/kubo/core/coreiface"
mh "github.com/multiformats/go-multihash"
"go.uber.org/multierr"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const (
exportAccountKeyFilename = "account.key"
exportAccountProofKeyFilename = "account_proof.key"
exportOrbitDBEntriesPrefix = "entries/"
exportOrbitDBHeadsPrefix = "heads/"
)
func (s *service) export(ctx context.Context, output io.Writer) error {
tw := tar.NewWriter(output)
defer tw.Close()
if err := s.exportAccountKeys(tw); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
s.lock.RLock()
groups := make([]*GroupContext, len(s.openedGroups))
i := 0
for _, gc := range s.openedGroups {
groups[i] = gc
i++
}
s.lock.RUnlock()
for _, gc := range groups {
if err := s.exportGroupContext(ctx, gc, tw); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
func (s *service) exportGroupContext(ctx context.Context, gc *GroupContext, tw *tar.Writer) error {
if err := s.exportOrbitDBStore(ctx, gc.metadataStore, tw); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if err := s.exportOrbitDBStore(ctx, gc.messageStore, tw); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
metaRawHeads := gc.metadataStore.OpLog().RawHeads()
cidsMeta := make([]cid.Cid, metaRawHeads.Len())
for i, raw := range metaRawHeads.Slice() {
cidsMeta[i] = raw.GetHash()
}
messagesRawHeads := gc.messageStore.OpLog().RawHeads()
cidsMessages := make([]cid.Cid, messagesRawHeads.Len())
for i, raw := range messagesRawHeads.Slice() {
cidsMessages[i] = raw.GetHash()
}
if err := s.exportOrbitDBGroupHeads(gc, cidsMeta, cidsMessages, tw); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
return nil
}
func (s *service) exportOrbitDBStore(ctx context.Context, store orbitdb.Store, tw *tar.Writer) error {
allCIDs := store.OpLog().GetEntries().Keys()
if len(allCIDs) == 0 {
return nil
}
for _, idStr := range allCIDs {
if err := s.exportOrbitDBEntry(ctx, tw, idStr); err != nil {
if clErr := tw.Close(); clErr != nil {
err = multierr.Append(err, clErr)
}
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
func (s *service) exportAccountKeys(tw *tar.Writer) error {
accountPrivateKeyBytes, accountProofPrivateKeyBytes, err := s.secretStore.ExportAccountKeysForBackup()
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
err = exportPrivateKey(tw, accountPrivateKeyBytes, exportAccountKeyFilename)
if err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
err = exportPrivateKey(tw, accountProofPrivateKeyBytes, exportAccountProofKeyFilename)
if err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
return nil
}
func (s *service) exportOrbitDBGroupHeads(gc *GroupContext, headsMetadata []cid.Cid, headsMessages []cid.Cid, tw *tar.Writer) error {
cidsMeta := make([][]byte, len(headsMetadata))
for i, id := range headsMetadata {
cidsMeta[i] = id.Bytes()
}
cidsMessages := make([][]byte, len(headsMessages))
for i, id := range headsMessages {
cidsMessages[i] = id.Bytes()
}
spk, err := gc.group.GetSigningPubKey()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
spkBytes, err := spk.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
linkKeyArr, err := gc.group.GetLinkKeyArray()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
headsExport := &protocoltypes.GroupHeadsExport{
PublicKey: gc.group.PublicKey,
SignPub: spkBytes,
MetadataHeadsCids: cidsMeta,
MessagesHeadsCids: cidsMessages,
LinkKey: linkKeyArr[:],
}
entryName := base64.RawURLEncoding.EncodeToString(gc.group.PublicKey)
data, err := proto.Marshal(headsExport)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
if err := tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: fmt.Sprintf("%s%s", exportOrbitDBHeadsPrefix, entryName),
Mode: 0o600,
Size: int64(len(data)),
}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
size, err := tw.Write(data)
if err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
if size != len(data) {
return errcode.ErrCode_ErrStreamWrite.Wrap(fmt.Errorf("wrote %d bytes instead of %d", size, len(data)))
}
return nil
}
func exportPrivateKey(tw *tar.Writer, marshalledPrivateKey []byte, filename string) error {
if err := tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: filename,
Mode: 0o600,
Size: int64(len(marshalledPrivateKey)),
}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
size, err := tw.Write(marshalledPrivateKey)
if err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
if size != len(marshalledPrivateKey) {
return errcode.ErrCode_ErrStreamWrite.Wrap(fmt.Errorf("wrote %d bytes instead of %d", size, len(marshalledPrivateKey)))
}
return nil
}
func (s *service) exportOrbitDBEntry(ctx context.Context, tw *tar.Writer, idStr string) error {
id, err := cid.Parse(idStr)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
dagNode, err := s.ipfsCoreAPI.Dag().Get(ctx, id)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
dagNodeBytes := dagNode.RawData()
if err := tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: fmt.Sprintf("%s%s", exportOrbitDBEntriesPrefix, idStr),
Mode: 0o600,
Size: int64(len(dagNodeBytes)),
}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
size, err := tw.Write(dagNodeBytes)
if err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
if size != len(dagNodeBytes) {
return errcode.ErrCode_ErrStreamWrite.Wrap(fmt.Errorf("wrote %d bytes instead of %d", size, len(dagNodeBytes)))
}
return nil
}
func readExportSecretKeyFile(expectedSize int64, reader *tar.Reader) ([]byte, error) {
if expectedSize == 0 {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid expected key size"))
}
keyContents := new(bytes.Buffer)
size, err := io.Copy(keyContents, reader)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to read %d bytes: %w", expectedSize, err))
}
if size != expectedSize {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unexpected file size"))
}
return keyContents.Bytes(), nil
}
func readExportOrbitDBGroupHeads(expectedSize int64, reader *tar.Reader) (*protocoltypes.GroupHeadsExport, []cid.Cid, []cid.Cid, error) {
if expectedSize == 0 {
return nil, nil, nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid expected node size"))
}
nodeContents := new(bytes.Buffer)
size, err := io.Copy(nodeContents, reader)
if err != nil {
return nil, nil, nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to read %d bytes: %w", expectedSize, err))
}
if size != expectedSize {
return nil, nil, nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unexpected file size"))
}
groupHeads := &protocoltypes.GroupHeadsExport{}
if err := proto.Unmarshal(nodeContents.Bytes(), groupHeads); err != nil {
return nil, nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
messagesCIDs := make([]cid.Cid, len(groupHeads.MessagesHeadsCids))
for i, cidBytes := range groupHeads.MessagesHeadsCids {
messagesCIDs[i], err = cid.Parse(cidBytes)
if err != nil {
return nil, nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
}
metaCIDs := make([]cid.Cid, len(groupHeads.MetadataHeadsCids))
for i, cidBytes := range groupHeads.MetadataHeadsCids {
metaCIDs[i], err = cid.Parse(cidBytes)
if err != nil {
return nil, nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
}
return groupHeads, metaCIDs, messagesCIDs, nil
}
func readExportCBORNode(expectedSize int64, cidStr string, reader *tar.Reader) (*cbornode.Node, error) {
if expectedSize == 0 {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid expected node size"))
}
nodeContents := new(bytes.Buffer)
expectedCID, err := cid.Parse(cidStr)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(fmt.Errorf("unable to parse CID in filename"))
}
size, err := io.Copy(nodeContents, reader)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to read %d bytes: %w", expectedSize, err))
}
if size != expectedSize {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unexpected file size"))
}
node, err := cbornode.Decode(nodeContents.Bytes(), mh.SHA2_256, -1)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if !node.Cid().Equals(expectedCID) {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("entry CID doesn't match file CID"))
}
return node, nil
}
type RestoreAccountHandler struct {
Handler func(header *tar.Header, reader *tar.Reader) (bool, error)
PostProcess func() error
}
type restoreAccountState struct {
keys map[string][]byte
}
func (state *restoreAccountState) readKey(keyName string) RestoreAccountHandler {
return RestoreAccountHandler{
Handler: func(header *tar.Header, reader *tar.Reader) (bool, error) {
if header.Name != keyName {
return false, nil
}
if state.keys[keyName] != nil {
return false, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("multiple keys found in archive"))
}
var err error
state.keys[keyName], err = readExportSecretKeyFile(header.Size, reader)
if err != nil {
return true, errcode.ErrCode_ErrInternal.Wrap(err)
}
return true, nil
},
}
}
func (state *restoreAccountState) restoreKeys(odb *WeshOrbitDB) RestoreAccountHandler {
return RestoreAccountHandler{
PostProcess: func() error {
if err := odb.secretStore.ImportAccountKeys(state.keys[exportAccountKeyFilename], state.keys[exportAccountProofKeyFilename]); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
return nil
},
}
}
func restoreOrbitDBEntry(ctx context.Context, coreAPI coreiface.CoreAPI) RestoreAccountHandler {
return RestoreAccountHandler{
Handler: func(header *tar.Header, reader *tar.Reader) (bool, error) {
if !strings.HasPrefix(header.Name, exportOrbitDBEntriesPrefix) {
return false, nil
}
cidStr := strings.TrimPrefix(header.Name, exportOrbitDBEntriesPrefix)
node, err := readExportCBORNode(header.Size, cidStr, reader)
if err != nil {
return true, errcode.ErrCode_ErrInternal.Wrap(err)
}
if err := coreAPI.Dag().Add(ctx, node); err != nil {
return true, errcode.ErrCode_ErrInternal.Wrap(err)
}
return true, nil
},
}
}
func restoreOrbitDBHeads(ctx context.Context, odb *WeshOrbitDB) RestoreAccountHandler {
return RestoreAccountHandler{
Handler: func(header *tar.Header, reader *tar.Reader) (bool, error) {
if !strings.HasPrefix(header.Name, exportOrbitDBHeadsPrefix) {
return false, nil
}
heads, metaCIDs, messageCIDs, err := readExportOrbitDBGroupHeads(header.Size, reader)
if err != nil {
return true, errcode.ErrCode_ErrInternal.Wrap(err)
}
if err := odb.setHeadsForGroup(ctx, &protocoltypes.Group{
PublicKey: heads.PublicKey,
SignPub: heads.SignPub,
LinkKey: heads.LinkKey,
}, metaCIDs, messageCIDs); err != nil {
return true, errcode.ErrCode_ErrOrbitDBAppend.Wrap(fmt.Errorf("error while restoring db head: %w", err))
}
return true, nil
},
}
}
func RestoreAccountExport(ctx context.Context, reader io.Reader, coreAPI coreiface.CoreAPI, odb *WeshOrbitDB, logger *zap.Logger, handlers ...RestoreAccountHandler) error {
tr := tar.NewReader(reader)
state := restoreAccountState{
keys: map[string][]byte{},
}
handlers = append(
[]RestoreAccountHandler{
state.readKey(exportAccountKeyFilename),
state.readKey(exportAccountProofKeyFilename),
state.restoreKeys(odb),
restoreOrbitDBEntry(ctx, coreAPI),
restoreOrbitDBHeads(ctx, odb),
},
handlers...,
)
for {
header, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if header.Typeflag != tar.TypeReg {
logger.Warn("invalid entry type", zap.String("filename", header.Name), zap.Any("filename", header.Typeflag))
continue
}
notHandled := true
for _, h := range handlers {
if h.Handler == nil {
continue
}
handled, err := h.Handler(header, tr)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if handled {
notHandled = false
break
}
}
if notHandled {
logger.Warn("unknown export entry", zap.String("filename", header.Name))
}
}
for _, h := range handlers {
if h.PostProcess == nil {
continue
}
if err := h.PostProcess(); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
================================================
FILE: account_export_test.go
================================================
package weshnet
import (
"archive/tar"
"context"
"io"
"os"
"testing"
"github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/pubsub/pubsubraw"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
"berty.tech/weshnet/v2/pkg/tinder"
)
func Test_service_exportAccountKeys(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
msrv := tinder.NewMockDriverServer()
dsA := dsync.MutexWrap(ds.NewMapDatastore())
nodeA, closeNodeA := NewTestingProtocol(ctx, t, &TestingOpts{
Mocknet: mn,
DiscoveryServer: msrv,
}, dsA)
defer closeNodeA()
// time.Sleep(time.Second * 5)
s, ok := nodeA.Service.(*service)
require.True(t, ok)
tmpFile, err := os.CreateTemp(os.TempDir(), "test-export-")
require.NoError(t, err)
defer os.Remove(tmpFile.Name())
tw := tar.NewWriter(tmpFile)
err = s.exportAccountKeys(tw)
require.NoError(t, err)
err = tw.Close()
require.NoError(t, err)
_, err = tmpFile.Seek(0, io.SeekStart)
require.NoError(t, err)
tr := tar.NewReader(tmpFile)
accountPrivateKey := getKeyFromTar(t, tr, exportAccountKeyFilename)
accountProofPrivateKey := getKeyFromTar(t, tr, exportAccountProofKeyFilename)
inStoreAccountPrivateKeyBytes, inStoreAccountProofPrivateKeyBytes, err := s.secretStore.ExportAccountKeysForBackup()
require.NoError(t, err)
require.NotNil(t, inStoreAccountPrivateKeyBytes)
require.NotNil(t, inStoreAccountProofPrivateKeyBytes)
require.Equal(t, accountPrivateKey, inStoreAccountPrivateKeyBytes)
require.Equal(t, accountProofPrivateKey, inStoreAccountProofPrivateKeyBytes)
}
func getKeyFromTar(t *testing.T, tr *tar.Reader, expectedFilename string) []byte {
header, err := tr.Next()
require.NoError(t, err)
require.Equal(t, expectedFilename, header.Name)
keyContents := make([]byte, header.Size)
size, err := tr.Read(keyContents)
require.Equal(t, int(header.Size), size)
return keyContents
}
func TestFlappyRestoreAccount(t *testing.T) {
testutil.FilterStability(t, testutil.Flappy)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
msrv := tinder.NewMockDriverServer()
tmpFile, err := os.CreateTemp(os.TempDir(), "test-export-")
require.NoError(t, err)
expectedMessages := map[cid.Cid][]byte{}
var nodeAInstanceConfig *protocoltypes.ServiceGetConfiguration_Reply
g, _, err := NewGroupMultiMember()
require.NoError(t, err)
defer os.Remove(tmpFile.Name())
{
dsA := dsync.MutexWrap(ds.NewMapDatastore())
nodeA, closeNodeA := NewTestingProtocol(ctx, t, &TestingOpts{
Mocknet: mn,
}, dsA)
serviceA, ok := nodeA.Service.(*service)
require.True(t, ok)
nodeAInstanceConfig, err = nodeA.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, nodeAInstanceConfig)
testPayload1 := []byte("testMessage1")
testPayload2 := []byte("testMessage2")
testPayload3 := []byte("testMessage3")
testPayload4 := []byte("testMessage4")
accountGroup := serviceA.getAccountGroup()
require.NotNil(t, accountGroup)
op, err := accountGroup.messageStore.AddMessage(ctx, testPayload1)
require.NoError(t, err)
expectedMessages[op.GetEntry().GetHash()] = testPayload1
op, err = accountGroup.messageStore.AddMessage(ctx, testPayload2)
require.NoError(t, err)
expectedMessages[op.GetEntry().GetHash()] = testPayload2
_, err = nodeA.Client.MultiMemberGroupJoin(ctx, &protocoltypes.MultiMemberGroupJoin_Request{Group: g})
require.NoError(t, err)
_, err = nodeA.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPk: g.PublicKey})
require.NoError(t, err)
op, err = serviceA.openedGroups[string(g.PublicKey)].messageStore.AddMessage(ctx, testPayload3)
require.NoError(t, err)
expectedMessages[op.GetEntry().GetHash()] = testPayload3
op, err = serviceA.openedGroups[string(g.PublicKey)].messageStore.AddMessage(ctx, testPayload4)
require.NoError(t, err)
expectedMessages[op.GetEntry().GetHash()] = testPayload4
require.NoError(t, serviceA.export(ctx, tmpFile))
closeNodeA()
require.NoError(t, dsA.Close())
}
_, err = tmpFile.Seek(0, io.SeekStart)
require.NoError(t, err)
{
dsB := dsync.MutexWrap(ds.NewMapDatastore())
secretStoreB, err := secretstore.NewSecretStore(dsB, nil)
require.NoError(t, err)
ipfsNodeB := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, &ipfsutil.TestingAPIOpts{
Mocknet: mn,
Datastore: dsB,
})
odb, err := NewWeshOrbitDB(ctx, ipfsNodeB.API(), &NewOrbitDBOptions{
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
PubSub: pubsubraw.NewPubSub(ipfsNodeB.PubSub(), ipfsNodeB.MockNode().PeerHost.ID(), logger, nil),
Logger: logger,
},
Datastore: dsB,
SecretStore: secretStoreB,
})
require.NoError(t, err)
err = RestoreAccountExport(ctx, tmpFile, ipfsNodeB.API(), odb, logger)
require.NoError(t, err)
nodeB, closeNodeB := NewTestingProtocol(ctx, t, &TestingOpts{
Mocknet: mn,
DiscoveryServer: msrv,
SecretStore: secretStoreB,
CoreAPIMock: ipfsNodeB,
OrbitDB: odb,
}, dsB)
defer closeNodeB()
nodeBInstanceConfig, err := nodeB.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, nodeBInstanceConfig)
require.Equal(t, nodeAInstanceConfig.AccountPk, nodeBInstanceConfig.AccountPk)
require.NotEqual(t, nodeAInstanceConfig.DevicePk, nodeBInstanceConfig.DevicePk)
require.Equal(t, nodeAInstanceConfig.AccountGroupPk, nodeBInstanceConfig.AccountGroupPk)
accountGroup := nodeB.Service.(*service).getAccountGroup()
require.NotNil(t, accountGroup)
entries := accountGroup.messageStore.OpLog().GetEntries()
for _, evt := range entries.Slice() {
_, ok := expectedMessages[evt.GetHash()]
require.True(t, ok)
}
_, err = nodeB.Service.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPk: g.PublicKey})
require.NoError(t, err)
for _, gPK := range [][]byte{nodeBInstanceConfig.AccountGroupPk, g.PublicKey} {
sub, err := nodeB.Client.GroupMessageList(
ctx,
&protocoltypes.GroupMessageList_Request{
GroupPk: gPK,
UntilNow: true,
},
)
require.NoError(t, err)
for {
evt, err := sub.Recv()
if err != nil {
require.Equal(t, io.EOF, err)
break
}
id, err := cid.Parse(evt.EventContext.Id)
require.NoError(t, err)
ref, ok := expectedMessages[id]
require.True(t, ok)
require.Equal(t, ref, evt.Message)
delete(expectedMessages, id)
}
}
require.Empty(t, expectedMessages)
}
// TODO: test account metadata entries
}
================================================
FILE: api/go-internal/buf.yaml
================================================
version: v2
name: buf.build/berty-technologies/weshnet
breaking:
use:
- FILE
lint:
use:
- DEFAULT
================================================
FILE: api/go-internal/handshake/handshake.proto
================================================
syntax = "proto3";
package handshake;
option go_package = "berty.tech/weshnet/v2/internal/handshake";
message BoxEnvelope {
bytes box = 1;
}
message HelloPayload {
bytes ephemeral_pub_key = 1;
}
message RequesterAuthenticatePayload {
bytes requester_account_id = 1;
bytes requester_account_sig = 2;
}
message ResponderAcceptPayload {
bytes responder_account_sig = 1;
}
message RequesterAcknowledgePayload {
bool success = 1;
}
================================================
FILE: api/go-internal/tinder/records.proto
================================================
syntax = "proto3";
package tinder;
option go_package = "berty.tech/weshnet/v2/pkg/tinder";
message Records {
repeated Record records = 1;
}
message Record {
string cid = 1;
int64 expire = 2;
}
================================================
FILE: api/protocol/buf.yaml
================================================
version: v2
name: buf.build/berty-technologies/weshnet
deps:
- buf.build/srikrsna/protoc-gen-gotag
breaking:
use:
- FILE
lint:
use:
- DEFAULT
================================================
FILE: api/protocol/errcode/errcode.proto
================================================
syntax = "proto3";
package weshnet.errcode;
option go_package = "berty.tech/weshnet/v2/pkg/errcode";
enum ErrCode {
//----------------
// Special errors
//----------------
Undefined = 0; // default value, should never be set manually
TODO = 666; // indicates that you plan to create an error later
ErrNotImplemented = 777; // indicates that a method is not implemented yet
ErrInternal = 888; // indicates an unknown error (without Code), i.e. in gRPC
//----------------
// Generic errors
//----------------
// Parameters and I/O errors
ErrInvalidInput = 100;
ErrInvalidRange = 101;
ErrMissingInput = 102;
ErrSerialization = 103;
ErrDeserialization = 104;
ErrStreamRead = 105;
ErrStreamWrite = 106;
ErrStreamTransform = 110;
ErrStreamSendAndClose = 111;
ErrStreamHeaderWrite = 112;
ErrStreamHeaderRead = 115;
ErrStreamSink = 113;
ErrStreamCloseAndRecv = 114;
ErrMissingMapKey = 107;
ErrDBWrite = 108;
ErrDBRead = 109;
ErrDBDestroy = 120;
ErrDBMigrate = 121;
ErrDBReplay = 122;
ErrDBRestore = 123;
ErrDBOpen = 124;
ErrDBClose = 125;
// Crypto errors
ErrCryptoRandomGeneration = 200;
ErrCryptoKeyGeneration = 201;
ErrCryptoNonceGeneration = 202;
ErrCryptoSignature = 203;
ErrCryptoSignatureVerification = 204;
ErrCryptoDecrypt = 205;
ErrCryptoDecryptPayload = 206;
ErrCryptoEncrypt = 207;
ErrCryptoKeyConversion = 208;
ErrCryptoCipherInit = 209;
ErrCryptoKeyDerivation = 210;
// Pattern errors
ErrMap = 300;
ErrForEach = 301;
// Keystore errors
ErrKeystoreGet = 400;
ErrKeystorePut = 401;
ErrNotFound = 404; // generic
//-----------------
// Specific errors
//-----------------
// OrbitDB errors
ErrOrbitDBInit = 1000;
ErrOrbitDBOpen = 1001;
ErrOrbitDBAppend = 1002;
ErrOrbitDBDeserialization = 1003;
ErrOrbitDBStoreCast = 1004;
// Handshake errors
ErrHandshakeOwnEphemeralKeyGenSend = 1100;
ErrHandshakePeerEphemeralKeyRecv = 1101;
ErrHandshakeRequesterAuthenticateBoxKeyGen = 1102;
ErrHandshakeResponderAcceptBoxKeyGen = 1103;
ErrHandshakeRequesterHello = 1104;
ErrHandshakeResponderHello = 1105;
ErrHandshakeRequesterAuthenticate = 1106;
ErrHandshakeResponderAccept = 1107;
ErrHandshakeRequesterAcknowledge = 1108;
// Contact Request errors
ErrContactRequestSameAccount = 1200;
ErrContactRequestContactAlreadyAdded = 1201;
ErrContactRequestContactBlocked = 1202;
ErrContactRequestContactUndefined = 1203;
ErrContactRequestIncomingAlreadyReceived = 1204;
// Group errors
ErrGroupMemberLogEventOpen = 1300;
ErrGroupMemberLogEventSignature = 1301;
ErrGroupMemberUnknownGroupID = 1302;
ErrGroupSecretOtherDestMember = 1303;
ErrGroupSecretAlreadySentToMember = 1304;
ErrGroupInvalidType = 1305;
ErrGroupMissing = 1306;
ErrGroupActivate = 1307;
ErrGroupDeactivate = 1308;
ErrGroupInfo = 1309;
ErrGroupUnknown = 1310;
ErrGroupOpen = 1311;
// Message key errors
ErrMessageKeyPersistencePut = 1500;
ErrMessageKeyPersistenceGet = 1501;
// Services Replication
ErrServiceReplication = 4100;
ErrServiceReplicationServer = 4101;
ErrServiceReplicationMissingEndpoint = 4102;
// Services Directory
ErrServicesDirectory = 4200;
ErrServicesDirectoryInvalidVerifiedCredentialSubject = 4201;
ErrServicesDirectoryExistingRecordNotFound = 4202;
ErrServicesDirectoryRecordLockedAndCantBeReplaced = 4203;
ErrServicesDirectoryExplicitReplaceFlagRequired = 4204;
ErrServicesDirectoryInvalidVerifiedCredential = 4205;
ErrServicesDirectoryExpiredVerifiedCredential = 4206;
ErrServicesDirectoryInvalidVerifiedCredentialID = 4207;
}
message ErrDetails { repeated ErrCode codes = 1; }
================================================
FILE: api/protocol/outofstoremessagetypes/outofstoremessage.proto
================================================
syntax = "proto3";
package weshnet.outofstoremessage.v1;
import "protocoltypes.proto";
option go_package = "berty.tech/weshnet/v2/pkg/outofstoremessagetypes";
// OutOfStoreMessageService is the service used to open out-of-store messages (e.g. push notifications)
// It is used to open messages with a lightweight protocol service for mobile backgroup processes.
service OutOfStoreMessageService {
// OutOfStoreReceive parses a payload received outside a synchronized store
rpc OutOfStoreReceive(weshnet.protocol.v1.OutOfStoreReceive.Request) returns (weshnet.protocol.v1.OutOfStoreReceive.Reply);
}
================================================
FILE: api/protocol/protocoltypes.proto
================================================
syntax = "proto3";
package weshnet.protocol.v1;
option go_package = "berty.tech/weshnet/v2/pkg/protocoltypes";
// ProtocolService is the top-level API to manage the Wesh protocol service.
// Each active Wesh protocol service is considered as a Wesh device and is associated with a Wesh user.
service ProtocolService {
// ServiceExportData exports the current data of the protocol service
rpc ServiceExportData (ServiceExportData.Request) returns (stream ServiceExportData.Reply);
// ServiceGetConfiguration gets the current configuration of the protocol service
rpc ServiceGetConfiguration (ServiceGetConfiguration.Request) returns (ServiceGetConfiguration.Reply);
// ContactRequestReference retrieves the information required to create a reference (ie. included in a shareable link) to the current account
rpc ContactRequestReference (ContactRequestReference.Request) returns (ContactRequestReference.Reply);
// ContactRequestDisable disables incoming contact requests
rpc ContactRequestDisable (ContactRequestDisable.Request) returns (ContactRequestDisable.Reply);
// ContactRequestEnable enables incoming contact requests
rpc ContactRequestEnable (ContactRequestEnable.Request) returns (ContactRequestEnable.Reply);
// ContactRequestResetReference changes the contact request reference
rpc ContactRequestResetReference (ContactRequestResetReference.Request) returns (ContactRequestResetReference.Reply);
// ContactRequestSend attempt to send a contact request
rpc ContactRequestSend (ContactRequestSend.Request) returns (ContactRequestSend.Reply);
// ContactRequestAccept accepts a contact request
rpc ContactRequestAccept (ContactRequestAccept.Request) returns (ContactRequestAccept.Reply);
// ContactRequestDiscard ignores a contact request, without informing the other user
rpc ContactRequestDiscard (ContactRequestDiscard.Request) returns (ContactRequestDiscard.Reply);
// ShareContact uses ContactRequestReference to get the contact information for the current account and
// returns the Protobuf encoding of a shareable contact which you can further encode and share. If needed, this
// will reset the contact request reference and enable contact requests. To decode the result, see DecodeContact.
rpc ShareContact (ShareContact.Request) returns (ShareContact.Reply);
// DecodeContact decodes the Protobuf encoding of a shareable contact which was returned by ShareContact.
rpc DecodeContact (DecodeContact.Request) returns (DecodeContact.Reply);
// ContactBlock blocks a contact from sending requests
rpc ContactBlock (ContactBlock.Request) returns (ContactBlock.Reply);
// ContactUnblock unblocks a contact from sending requests
rpc ContactUnblock (ContactUnblock.Request) returns (ContactUnblock.Reply);
// ContactAliasKeySend send an alias key to a contact, the contact will be able to assert that your account is being present on a multi-member group
rpc ContactAliasKeySend (ContactAliasKeySend.Request) returns (ContactAliasKeySend.Reply);
// MultiMemberGroupCreate creates a new multi-member group
rpc MultiMemberGroupCreate (MultiMemberGroupCreate.Request) returns (MultiMemberGroupCreate.Reply);
// MultiMemberGroupJoin joins a multi-member group
rpc MultiMemberGroupJoin (MultiMemberGroupJoin.Request) returns (MultiMemberGroupJoin.Reply);
// MultiMemberGroupLeave leaves a multi-member group
rpc MultiMemberGroupLeave (MultiMemberGroupLeave.Request) returns (MultiMemberGroupLeave.Reply);
// MultiMemberGroupAliasResolverDisclose discloses your alias resolver key
rpc MultiMemberGroupAliasResolverDisclose (MultiMemberGroupAliasResolverDisclose.Request) returns (MultiMemberGroupAliasResolverDisclose.Reply);
// MultiMemberGroupAdminRoleGrant grants an admin role to a group member
rpc MultiMemberGroupAdminRoleGrant (MultiMemberGroupAdminRoleGrant.Request) returns (MultiMemberGroupAdminRoleGrant.Reply);
// MultiMemberGroupInvitationCreate creates an invitation to a multi-member group
rpc MultiMemberGroupInvitationCreate (MultiMemberGroupInvitationCreate.Request) returns (MultiMemberGroupInvitationCreate.Reply);
// AppMetadataSend adds an app event to the metadata store, the message is encrypted using a symmetric key and readable by future group members
rpc AppMetadataSend (AppMetadataSend.Request) returns (AppMetadataSend.Reply);
// AppMessageSend adds an app event to the message store, the message is encrypted using a derived key and readable by current group members
rpc AppMessageSend (AppMessageSend.Request) returns (AppMessageSend.Reply);
// GroupMetadataList replays previous and subscribes to new metadata events from the group
rpc GroupMetadataList (GroupMetadataList.Request) returns (stream GroupMetadataEvent);
// GroupMessageList replays previous and subscribes to new message events from the group
rpc GroupMessageList (GroupMessageList.Request) returns (stream GroupMessageEvent);
// GroupInfo retrieves information about a group
rpc GroupInfo (GroupInfo.Request) returns (GroupInfo.Reply);
// ActivateGroup explicitly opens a group
rpc ActivateGroup (ActivateGroup.Request) returns (ActivateGroup.Reply);
// DeactivateGroup closes a group
rpc DeactivateGroup (DeactivateGroup.Request) returns (DeactivateGroup.Reply);
// GroupDeviceStatus monitor device status
rpc GroupDeviceStatus(GroupDeviceStatus.Request) returns (stream GroupDeviceStatus.Reply);
rpc DebugListGroups (DebugListGroups.Request) returns (stream DebugListGroups.Reply);
rpc DebugInspectGroupStore (DebugInspectGroupStore.Request) returns (stream DebugInspectGroupStore.Reply);
rpc DebugGroup (DebugGroup.Request) returns (DebugGroup.Reply);
rpc SystemInfo (SystemInfo.Request) returns (SystemInfo.Reply);
// CredentialVerificationServiceInitFlow Initialize a credential verification flow
rpc CredentialVerificationServiceInitFlow (CredentialVerificationServiceInitFlow.Request) returns (CredentialVerificationServiceInitFlow.Reply);
// CredentialVerificationServiceCompleteFlow Completes a credential verification flow
rpc CredentialVerificationServiceCompleteFlow (CredentialVerificationServiceCompleteFlow.Request) returns (CredentialVerificationServiceCompleteFlow.Reply);
// VerifiedCredentialsList Retrieves the list of verified credentials
rpc VerifiedCredentialsList (VerifiedCredentialsList.Request) returns (stream VerifiedCredentialsList.Reply);
// ReplicationServiceRegisterGroup Asks a replication service to distribute a group contents
rpc ReplicationServiceRegisterGroup (ReplicationServiceRegisterGroup.Request) returns (ReplicationServiceRegisterGroup.Reply);
// PeerList returns a list of P2P peers
rpc PeerList(PeerList.Request) returns (PeerList.Reply);
// OutOfStoreReceive parses a payload received outside a synchronized store
rpc OutOfStoreReceive(OutOfStoreReceive.Request) returns (OutOfStoreReceive.Reply);
// OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
rpc OutOfStoreSeal(OutOfStoreSeal.Request) returns (OutOfStoreSeal.Reply);
// RefreshContactRequest try to refresh the contact request for the given contact
rpc RefreshContactRequest(RefreshContactRequest.Request) returns (RefreshContactRequest.Reply);
}
enum GroupType {
// GroupTypeUndefined indicates that the value has not been set. For example, happens if group is replicated.
GroupTypeUndefined = 0;
// GroupTypeAccount is the group managing an account, available to all its devices.
GroupTypeAccount = 1;
// GroupTypeContact is the group created between two accounts, available to all their devices.
GroupTypeContact = 2;
// GroupTypeMultiMember is a group containing an undefined number of members.
GroupTypeMultiMember = 3;
// Following group types have not been defined, first is a group with
// only approved writers, second is public group with anyone allowed to
// write, in both cases full history is available to new members.
//
// GroupTypeChannel = 4;
// GroupTypePublic = 5;
}
enum EventType {
// EventTypeUndefined indicates that the value has not been set. Should not happen.
EventTypeUndefined = 0;
// EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group
EventTypeGroupMemberDeviceAdded = 1;
// EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member
EventTypeGroupDeviceChainKeyAdded = 2;
// EventTypeGroupAdditionalRendezvousSeedAdded adds a new rendezvous seed to a group
// Might be implemented later, could be useful for replication services
// EventTypeGroupAdditionalRendezvousSeedAdded = 3;
// EventTypeGroupAdditionalRendezvousSeedRemoved removes a rendezvous seed from a group
// Might be implemented later, could be useful for replication services
// EventTypeGroupAdditionalRendezvousSeedRemoved = 4;
// EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group
EventTypeAccountGroupJoined = 101;
// EventTypeAccountGroupLeft indicates the payload includes that the account has left a group
EventTypeAccountGroupLeft = 102;
// EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests
EventTypeAccountContactRequestDisabled = 103;
// EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests
EventTypeAccountContactRequestEnabled = 104;
// EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed
EventTypeAccountContactRequestReferenceReset = 105;
// EventTypeAccountContactRequestOutgoingEnqueued indicates the payload includes that the account will attempt to send a new contact request
EventTypeAccountContactRequestOutgoingEnqueued = 106;
// EventTypeAccountContactRequestOutgoingSent indicates the payload includes that the account has sent a contact request
EventTypeAccountContactRequestOutgoingSent = 107;
// EventTypeAccountContactRequestIncomingReceived indicates the payload includes that the account has received a contact request
EventTypeAccountContactRequestIncomingReceived = 108;
// EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request
EventTypeAccountContactRequestIncomingDiscarded = 109;
// EventTypeAccountContactRequestIncomingAccepted indicates the payload includes that the account has accepted a contact request
EventTypeAccountContactRequestIncomingAccepted = 110;
// EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact
EventTypeAccountContactBlocked = 111;
// EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact
EventTypeAccountContactUnblocked = 112;
// EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key
EventTypeContactAliasKeyAdded = 201;
// EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof
EventTypeMultiMemberGroupAliasResolverAdded = 301;
// EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner
EventTypeMultiMemberGroupInitialMemberAnnounced = 302;
// EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin
EventTypeMultiMemberGroupAdminRoleGranted = 303;
// EventTypeGroupReplicating indicates that the group has been registered for replication on a server
EventTypeGroupReplicating = 403;
// EventTypeAccountVerifiedCredentialRegistered
EventTypeAccountVerifiedCredentialRegistered = 500;
// EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key
EventTypeGroupMetadataPayloadSent = 1001;
}
// Account describes all the secrets that identifies an Account
message Account {
// group specifies which group is used to manage the account
Group group = 1;
// account_private_key, private part is used to signs handshake, signs device, create contacts group keys via ECDH -- public part is used to have a shareable identity
bytes account_private_key = 2;
// alias_private_key, private part is use to derive group members private keys, signs alias proofs, public part can be shared to contacts to prove identity
bytes alias_private_key = 3;
// public_rendezvous_seed, rendezvous seed used for direct communication
bytes public_rendezvous_seed = 4;
}
// Group define a group and is enough to invite someone to it
message Group {
// public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group
bytes public_key = 1;
// secret is the symmetric secret of the group, which is used to encrypt the metadata
bytes secret = 2;
// secret_sig is the signature of the secret used to ensure the validity of the group
bytes secret_sig = 3;
// group_type specifies the type of the group, used to determine how device chain key is generated
GroupType group_type = 4;
// sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided
bytes sign_pub = 5;
// link_key is the secret key used to exchange group updates and links to attachments, useful for replication services
bytes link_key = 6;
// link_key_sig is the signature of the link_key using the group private key
bytes link_key_sig = 7;
}
message GroupHeadsExport {
// public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group
bytes public_key = 1;
// sign_pub is the signature public key used to verify entries
bytes sign_pub = 2;
// metadata_heads_cids are the heads of the metadata store that should be restored from an export
repeated bytes metadata_heads_cids = 3;
// messages_heads_cids are the heads of the metadata store that should be restored from an export
repeated bytes messages_heads_cids = 4;
// link_key
bytes link_key = 5;
}
// GroupMetadata is used in GroupEnvelope and only readable by invited group members
message GroupMetadata {
// event_type defines which event type is used
EventType event_type = 1;
// the serialization depends on event_type, event is symmetrically encrypted
bytes payload = 2;
// sig is the signature of the payload, it depends on the event_type for the used key
bytes sig = 3;
// protocol_metadata is protocol layer data
ProtocolMetadata protocol_metadata = 4;
}
// GroupEnvelope is a publicly exposed structure containing a group metadata event
message GroupEnvelope {
// nonce is used to encrypt the message
bytes nonce = 1;
// event is encrypted using a symmetric key shared among group members
bytes event = 2;
reserved 3; // repeated bytes encrypted_attachment_cids = 3 ;
}
// MessageHeaders is used in MessageEnvelope and only readable by invited group members
message MessageHeaders {
// counter is the current counter value for the specified device
uint64 counter = 1;
// device_pk is the public key of the device sending the message
bytes device_pk = 2;
// sig is the signature of the encrypted message using the device's private key
bytes sig = 3;
// metadata allow to pass custom informations
map metadata = 4;
}
message ProtocolMetadata {
// attachments_secrets is a list of secret keys used retrieve attachments
reserved 1; //repeated bytes attachments_secrets = 1;
}
// EncryptedMessage is used in MessageEnvelope and only readable by groups members that joined before the message was sent
message EncryptedMessage {
// plaintext is the app layer data
bytes plaintext = 1;
// protocol_metadata is protocol layer data
ProtocolMetadata protocol_metadata = 2;
}
// MessageEnvelope is a publicly exposed structure containing a group secure message
message MessageEnvelope {
// message_headers is an encrypted serialization using a symmetric key of a MessageHeaders message
bytes message_headers = 1;
// message is an encrypted message, only readable by group members who previously received the appropriate chain key
bytes message = 2;
// nonce is a nonce for message headers
bytes nonce = 3;
// encrypted_attachment_cids is a list of attachment CIDs encrypted specifically for replication services
reserved 4; // repeated bytes encrypted_attachment_cids = 4;
}
// ***************************************************************************
// Group event types
// ***************************************************************************
// EventContext adds context (its id, its parents and its attachments) to an event
message EventContext {
// id is the CID of the underlying OrbitDB event
bytes id = 1;
// id are the the CIDs of the underlying parents of the OrbitDB event
repeated bytes parent_ids = 2;
// group_pk receiving the event
bytes group_pk = 3;
// attachment_cids is a list of attachment that can be retrieved
reserved 4; // repeated bytes attachment_cids = 4;
}
// GroupMetadataPayloadSent is an app defined message, accessible to future group members
message GroupMetadataPayloadSent {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// message is the payload
bytes message = 2;
}
// ContactAliasKeyAdded is an event type where ones shares their alias public key
message ContactAliasKeyAdded {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// alias_pk is the alias key which will be used to verify a contact identity
bytes alias_pk = 2;
}
// GroupMemberDeviceAdded is an event which indicates to a group a new device (and eventually a new member) is joining it
// When added on AccountGroup, this event should be followed by appropriate GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events
message GroupMemberDeviceAdded {
// member_pk is the member sending the event
bytes member_pk = 1;
// device_pk is the device sending the event, signs the message
bytes device_pk = 2;
// member_sig is used to prove the ownership of the member pk
bytes member_sig = 3; // TODO: signature of what ??? ensure it can't be replayed
}
// DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
message DeviceChainKey {
// chain_key is the current value of the chain key of the group device
bytes chain_key = 1;
// counter is the current value of the counter of the group device
uint64 counter = 2;
}
// GroupDeviceChainKeyAdded is an event which indicates to a group member a device chain key
message GroupDeviceChainKeyAdded {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// dest_member_pk is the member who should receive the secret
bytes dest_member_pk = 2;
// payload is the serialization of Payload encrypted for the specified member
bytes payload = 3;
}
// MultiMemberGroupAliasResolverAdded indicates that a group member want to disclose their presence in the group to their contacts
message MultiMemberGroupAliasResolverAdded {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// alias_resolver allows contact of an account to resolve the real identity behind an alias (Multi-Member Group Member)
// Generated by both contacts and account independently using: hmac(aliasPK, GroupID)
bytes alias_resolver = 2;
// alias_proof ensures that the associated alias_resolver has been issued by the right account
// Generated using aliasSKSig(GroupID)
bytes alias_proof = 3;
}
// MultiMemberGroupAdminRoleGranted indicates that a group admin allows another group member to act as an admin
message MultiMemberGroupAdminRoleGranted {
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
bytes device_pk = 1;
// grantee_member_pk is the member public key of the member granted of the admin role
bytes grantee_member_pk = 2;
}
// MultiMemberGroupInitialMemberAnnounced indicates that a member is the group creator, this event is signed using the group ID private key
message MultiMemberGroupInitialMemberAnnounced {
// member_pk is the public key of the member who is the group creator
bytes member_pk = 1;
}
// GroupAddAdditionalRendezvousSeed indicates that an additional rendezvous point should be used for data synchronization
message GroupAddAdditionalRendezvousSeed {
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
bytes device_pk = 1;
// seed is the additional rendezvous point seed which should be used
bytes seed = 2;
}
// GroupRemoveAdditionalRendezvousSeed indicates that a previously added rendezvous point should be removed
message GroupRemoveAdditionalRendezvousSeed {
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
bytes device_pk = 1;
// seed is the additional rendezvous point seed which should be removed
bytes seed = 2;
}
// AccountGroupJoined indicates that the account is now part of a new group
message AccountGroupJoined {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// group describe the joined group
Group group = 2;
}
// AccountGroupLeft indicates that the account has left a group
message AccountGroupLeft {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// group_pk references the group left
bytes group_pk = 2;
}
// AccountContactRequestDisabled indicates that the account should not be advertised on a public rendezvous point
message AccountContactRequestDisabled {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
}
// AccountContactRequestEnabled indicates that the account should be advertised on a public rendezvous point
message AccountContactRequestEnabled {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
}
// AccountContactRequestReferenceReset indicates that the account should be advertised on different public rendezvous points
message AccountContactRequestReferenceReset {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// public_rendezvous_seed is the new rendezvous point seed
bytes public_rendezvous_seed = 2;
}
// This event should be followed by an AccountGroupJoined event
// This event should be followed by a GroupMemberDeviceAdded event within the AccountGroup
// This event should be followed by a GroupDeviceChainKeyAdded event within the AccountGroup
// AccountContactRequestOutgoingEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
message AccountContactRequestOutgoingEnqueued {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// group_pk is the 1to1 group with the requested user
bytes group_pk = 2;
// contact is a message describing how to connect to the other account
ShareableContact contact = 3;
// own_metadata is the identifying metadata that will be shared to the other account
bytes own_metadata = 4;
}
// AccountContactRequestOutgoingSent indicates that the account has sent a contact request
message AccountContactRequestOutgoingSent {
// device_pk is the device sending the account event, signs the message
bytes device_pk = 1;
// contact_pk is the contacted account
bytes contact_pk = 2;
}
// AccountContactRequestIncomingReceived indicates that the account has received a new contact request
message AccountContactRequestIncomingReceived {
// device_pk is the device sending the account event (which received the contact request), signs the message
bytes device_pk = 1;
// contact_pk is the account sending the request
bytes contact_pk = 2;
// TODO: is this necessary?
// contact_rendezvous_seed is the rendezvous seed of the contact sending the request
bytes contact_rendezvous_seed = 3;
// TODO: is this necessary?
// contact_metadata is the metadata specific to the app to identify the contact for the request
bytes contact_metadata = 4;
}
// AccountContactRequestIncomingDiscarded indicates that a contact request has been refused
message AccountContactRequestIncomingDiscarded {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// contact_pk is the contact whom request is refused
bytes contact_pk = 2;
}
// This event should be followed by an AccountGroupJoined event
// This event should be followed by GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events within the AccountGroup
// AccountContactRequestIncomingAccepted indicates that a contact request has been accepted
message AccountContactRequestIncomingAccepted {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// contact_pk is the contact whom request is accepted
bytes contact_pk = 2;
// group_pk is the 1to1 group with the requester user
bytes group_pk = 3;
}
// AccountContactBlocked indicates that a contact is blocked
message AccountContactBlocked {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// contact_pk is the contact blocked
bytes contact_pk = 2;
}
// AccountContactUnblocked indicates that a contact is unblocked
message AccountContactUnblocked {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// contact_pk is the contact unblocked
bytes contact_pk = 2;
}
message GroupReplicating {
// device_pk is the device sending the event, signs the message
bytes device_pk = 1;
// authentication_url indicates which server has been used for authentication
string authentication_url = 2;
// replication_server indicates which server will be used for replication
string replication_server = 3;
}
// ***************************************************************************
// RPC methods inputs and outputs
// ***************************************************************************
message ServiceExportData {
message Request {}
message Reply {
bytes exported_data = 1;
}
}
message ServiceGetConfiguration {
enum SettingState {
Unknown = 0;
Enabled = 1;
Disabled = 2;
Unavailable = 3;
}
message Request {}
message Reply {
// account_pk is the public key of the current account
bytes account_pk = 1;
// device_pk is the public key of the current device
bytes device_pk = 2;
// account_group_pk is the public key of the account group
bytes account_group_pk = 3;
// peer_id is the peer ID of the current IPFS node
string peer_id = 4;
// listeners is the list of swarm listening addresses of the current IPFS node
repeated string listeners = 5;
SettingState ble_enabled = 6;
SettingState wifi_p2p_enabled = 7; // MultiPeerConnectivity for Darwin and Nearby for Android
SettingState mdns_enabled = 8;
SettingState relay_enabled = 9;
}
}
message ContactRequestReference {
message Request {}
message Reply {
// public_rendezvous_seed is the rendezvous seed used by the current account
bytes public_rendezvous_seed = 1;
// enabled indicates if incoming contact requests are enabled
bool enabled = 2;
}
}
message ContactRequestDisable {
message Request {}
message Reply {}
}
message ContactRequestEnable {
message Request {}
message Reply {
// public_rendezvous_seed is the rendezvous seed used by the current account
bytes public_rendezvous_seed = 1;
}
}
message ContactRequestResetReference {
message Request {}
message Reply {
// public_rendezvous_seed is the rendezvous seed used by the current account
bytes public_rendezvous_seed = 1;
}
}
message ContactRequestSend {
message Request {
// contact is a message describing how to connect to the other account
ShareableContact contact = 1;
// own_metadata is the identifying metadata that will be shared to the other account
bytes own_metadata = 2;
}
message Reply {}
}
message ContactRequestAccept {
message Request {
// contact_pk is the identifier of the contact to accept the request from
bytes contact_pk = 1;
}
message Reply {}
}
message ContactRequestDiscard {
message Request {
// contact_pk is the identifier of the contact to ignore the request from
bytes contact_pk = 1;
}
message Reply {}
}
message ShareContact {
message Request {}
message Reply {
// encoded_contact is the Protobuf encoding of the ShareableContact. You can further encode the bytes for sharing, such as base58 or QR code.
bytes encoded_contact = 1;
}
}
message DecodeContact {
message Request {
// encoded_contact is the Protobuf encoding of the shareable contact (as returned by ShareContact).
bytes encoded_contact = 1;
}
message Reply {
// shareable_contact is the decoded shareable contact.
ShareableContact contact = 1;
}
}
message ContactBlock {
message Request {
// contact_pk is the identifier of the contact to block
bytes contact_pk = 1;
}
message Reply {}
}
message ContactUnblock {
message Request {
// contact_pk is the identifier of the contact to unblock
bytes contact_pk = 1;
}
message Reply {}
}
message ContactAliasKeySend {
message Request {
// contact_pk is the identifier of the contact to send the alias public key to
bytes group_pk = 1;
}
message Reply {}
}
message MultiMemberGroupCreate {
message Request {}
message Reply {
// group_pk is the identifier of the newly created group
bytes group_pk = 1;
}
}
message MultiMemberGroupJoin {
message Request {
// group is the information of the group to join
Group group = 1;
}
message Reply {}
}
message MultiMemberGroupLeave {
message Request {
bytes group_pk = 1;
}
message Reply {}
}
message MultiMemberGroupAliasResolverDisclose {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
}
message Reply {}
}
message MultiMemberGroupAdminRoleGrant {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// member_pk is the identifier of the member which will be granted the admin role
bytes member_pk = 2;
}
message Reply {}
}
message MultiMemberGroupInvitationCreate {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
}
message Reply {
// group is the invitation to the group
Group group = 1;
}
}
message AppMetadataSend {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// payload is the payload to send
bytes payload = 2;
// attachment_cids is a list of attachment cids
reserved 3; // repeated bytes attachment_cids = 3;
}
message Reply {
bytes cid = 1;
}
}
message AppMessageSend {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// payload is the payload to send
bytes payload = 2;
// attachment_cids is a list of attachment cids
reserved 3; // repeated bytes attachment_cids = 3;
}
message Reply {
bytes cid = 1;
}
}
message GroupMetadataEvent {
// event_context contains context information about the event
EventContext event_context = 1;
// metadata contains the newly available metadata
GroupMetadata metadata = 2;
// event_clear clear bytes for the event
bytes event = 3;
}
message GroupMessageEvent {
// event_context contains context information about the event
EventContext event_context = 1;
// headers contains headers of the secure message
MessageHeaders headers = 2;
// message contains the secure message payload
bytes message = 3;
}
message GroupMetadataList {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// since is the lower ID bound used to filter events
// if not set, will return events since the beginning
bytes since_id = 2;
// since_now will list only new event to come
// since_id must not be set
bool since_now = 3;
// until is the upper ID bound used to filter events
// if not set, will subscribe to new events to come
bytes until_id = 4;
// until_now will not list new event to come
// until_id must not be set
bool until_now = 5;
// reverse_order indicates whether the previous events should be returned in
// reverse chronological order
bool reverse_order = 6;
}
}
message GroupMessageList {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// since is the lower ID bound used to filter events
// if not set, will return events since the beginning
bytes since_id = 2;
// since_now will list only new event to come
// since_id must not be set
bool since_now = 3;
// until is the upper ID bound used to filter events
// if not set, will subscribe to new events to come
bytes until_id = 4;
// until_now will not list new event to come
// until_id must not be set
bool until_now = 5;
// reverse_order indicates whether the previous events should be returned in
// reverse chronological order
bool reverse_order = 6;
}
}
message GroupInfo {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// contact_pk is the identifier of the contact
bytes contact_pk = 2;
}
message Reply {
// group is the group invitation, containing the group pk and its type
Group group = 1;
// member_pk is the identifier of the current member in the group
bytes member_pk = 2;
// device_pk is the identifier of the current device in the group
bytes device_pk = 3;
}
}
message ActivateGroup {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// local_only will open the group without enabling network interactions
// with other members
bool local_only = 2;
}
message Reply {
}
}
message DeactivateGroup {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
}
message Reply {
}
}
message GroupDeviceStatus {
enum Type {
TypeUnknown = 0;
TypePeerDisconnected = 1;
TypePeerConnected = 2;
TypePeerReconnecting = 3;
}
enum Transport {
TptUnknown = 0;
TptLAN = 1;
TptWAN = 2;
TptProximity = 3;
}
message Request {
bytes group_pk = 1;
}
message Reply {
message PeerConnected {
string peer_id = 1;
bytes device_pk = 2;
repeated Transport transports = 3;
repeated string maddrs = 4;
}
message PeerReconnecting {
string peer_id = 1;
}
message PeerDisconnected {
string peer_id = 1;
}
Type type = 1;
bytes event = 2;
}
}
message DebugListGroups {
message Request {
}
message Reply {
// group_pk is the public key of the group
bytes group_pk = 1;
// group_type is the type of the group
GroupType group_type = 2;
// contact_pk is the contact public key if appropriate
bytes contact_pk = 3;
}
}
message DebugInspectGroupStore {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
// log_type is the log to inspect
DebugInspectGroupLogType log_type = 2;
}
message Reply {
// cid is the CID of the IPFS log entry
bytes cid = 1;
// parent_cids is the list of the parent entries
repeated bytes parent_cids = 2 ;
// event_type metadata event type if subscribed to metadata events
EventType metadata_event_type = 3;
// device_pk is the public key of the device signing the entry
bytes device_pk = 4;
// payload is the un encrypted entry payload if available
bytes payload = 6;
}
}
message DebugGroup {
message Request {
// group_pk is the identifier of the group
bytes group_pk = 1;
}
message Reply {
// peer_ids is the list of peer ids connected to the same group
repeated string peer_ids = 1 ;
}
}
enum DebugInspectGroupLogType {
DebugInspectGroupLogTypeUndefined = 0;
DebugInspectGroupLogTypeMessage = 1;
DebugInspectGroupLogTypeMetadata = 2;
}
enum ContactState {
ContactStateUndefined = 0;
ContactStateToRequest = 1;
ContactStateReceived = 2;
ContactStateAdded = 3;
ContactStateRemoved = 4;
ContactStateDiscarded = 5;
ContactStateBlocked = 6;
}
message ShareableContact {
// pk is the account to send a contact request to
bytes pk = 1;
// public_rendezvous_seed is the rendezvous seed used by the account to send a contact request to
bytes public_rendezvous_seed = 2;
// metadata is the metadata specific to the app to identify the contact for the request
bytes metadata = 3;
}
message ServiceTokenSupportedService {
string service_type = 1;
string service_endpoint = 2;
}
message ServiceToken {
string token = 1;
string authentication_url = 2 ;
repeated ServiceTokenSupportedService supported_services = 3;
int64 expiration = 4;
}
message CredentialVerificationServiceInitFlow {
message Request {
string service_url = 1;
bytes public_key = 2;
string link = 3;
}
message Reply {
string url = 1;
bool secure_url = 2;
}
}
message CredentialVerificationServiceCompleteFlow {
message Request {
string callback_uri = 1;
}
message Reply {
string identifier = 1;
}
}
message VerifiedCredentialsList {
message Request {
string filter_identifier = 1;
string filter_issuer = 2;
bool exclude_expired = 3;
}
message Reply {
AccountVerifiedCredentialRegistered credential = 1;
}
}
message ReplicationServiceRegisterGroup {
message Request{
bytes group_pk = 1;
string token = 2;
string authentication_url = 3;
string replication_server = 4;
}
message Reply{}
}
message ReplicationServiceReplicateGroup {
message Request {
Group group = 1;
}
message Reply {
bool ok = 1;
}
}
message SystemInfo {
message Request {}
message Reply {
Process process = 1;
P2P p2p = 2;
OrbitDB orbitdb = 3;
repeated string warns = 4;
}
message OrbitDB {
ReplicationStatus account_metadata = 1;
message ReplicationStatus {
int64 progress = 1;
int64 maximum = 2;
int64 buffered = 3;
int64 queued = 4;
}
}
message P2P {
int64 connected_peers = 1;
}
message Process {
string version = 1;
string vcs_ref = 2;
int64 uptime_ms = 3;
int64 user_cpu_time_ms = 10;
int64 system_cpu_time_ms = 11;
int64 started_at = 12;
uint64 rlimit_cur = 13;
int64 num_goroutine = 14;
int64 nofile = 15;
bool too_many_open_files = 16;
int64 num_cpu = 17;
string go_version = 18;
string operating_system = 19;
string host_name = 20;
string arch = 21;
uint64 rlimit_max = 22;
int64 pid = 23;
int64 ppid = 24;
int64 priority = 25;
int64 uid = 26;
string working_dir = 27;
string system_username = 28;
}
}
message PeerList {
message Request {}
message Reply {
repeated Peer peers = 1;
}
message Peer {
// id is the libp2p.PeerID.
string id = 1;
// routes are the list of active and known maddr.
repeated Route routes = 2;
// errors is a list of errors related to the peer.
repeated string errors = 3;
// Features is a list of available features.
repeated Feature features = 4;
// MinLatency is the minimum latency across all the peer routes.
int64 min_latency = 5;
// IsActive is true if at least one of the route is active.
bool is_active = 6;
// Direction is the aggregate of all the routes's direction.
Direction direction = 7;
}
message Route {
// IsActive indicates whether the address is currently used or just known.
bool is_active = 1;
// Address is the multiaddress via which we are connected with the peer.
string address = 2;
// Direction is which way the connection was established.
Direction direction = 3;
// Latency is the last known round trip time to the peer in ms.
int64 latency = 4;
// Streams returns list of streams established with the peer.
repeated Stream streams = 5;
}
message Stream {
// id is an identifier used to write protocol headers in streams.
string id = 1;
}
enum Feature {
UnknownFeature = 0;
WeshFeature = 1;
BLEFeature = 2;
LocalFeature = 3;
TorFeature = 4;
QuicFeature = 5;
}
}
enum Direction {
UnknownDir = 0;
InboundDir = 1;
OutboundDir = 2;
BiDir = 3;
}
// Progress define a generic object that can be used to display a progress bar for long-running actions.
message Progress {
string state = 1;
string doing = 2;
float progress = 3;
uint64 completed = 4;
uint64 total = 5;
uint64 delay = 6;
}
message OutOfStoreMessage {
bytes cid = 1;
bytes device_pk = 2;
fixed64 counter = 3;
bytes sig = 4;
fixed32 flags = 5;
bytes encrypted_payload = 6;
bytes nonce = 7;
}
message OutOfStoreMessageEnvelope {
bytes nonce = 1;
bytes box = 2;
bytes group_reference = 3;
}
message OutOfStoreReceive {
message Request {
bytes payload = 1;
}
message Reply {
OutOfStoreMessage message = 1;
bytes cleartext = 2;
bytes group_public_key = 3;
bool already_received = 4;
}
}
message OutOfStoreSeal {
message Request {
bytes cid = 1;
bytes group_public_key = 2;
}
message Reply {
bytes encrypted = 1;
}
}
message AccountVerifiedCredentialRegistered {
// device_pk is the public key of the device sending the message
bytes device_pk = 1;
bytes signed_identity_public_key = 2;
string verified_credential = 3;
int64 registration_date = 4;
int64 expiration_date = 5;
string identifier = 6;
string issuer = 7;
}
message FirstLastCounters {
uint64 first = 1;
uint64 last = 2;
}
// OrbitDBMessageHeads is the payload sent on orbitdb to share peer's heads
message OrbitDBMessageHeads {
message Box {
string address = 1;
bytes heads = 2;
bytes device_pk = 3;
bytes peer_id = 4;
}
// sealed box should contain encrypted Box
bytes sealed_box = 2;
// current topic used
bytes raw_rotation = 3;
}
message RefreshContactRequest {
message Peer {
// id is the libp2p.PeerID.
string id = 1;
// list of peers multiaddrs.
repeated string addrs = 2;
}
message Request {
bytes contact_pk = 1;
// timeout in second
int64 timeout = 2;
}
message Reply {
// peers found and successfully connected.
repeated Peer peers_found = 1;
}
}
================================================
FILE: api/protocol/replicationtypes/bertyreplication.proto
================================================
syntax = "proto3";
package weshnet.replication.v1;
import "protocoltypes.proto";
import "tagger/tagger.proto";
option go_package = "berty.tech/weshnet/v2/pkg/replicationtypes";
// ReplicationService
service ReplicationService {
// ReplicateGroup
rpc ReplicateGroup(ReplicationServiceReplicateGroup.Request) returns (ReplicationServiceReplicateGroup.Reply);
rpc ReplicateGlobalStats(ReplicateGlobalStats.Request) returns (ReplicateGlobalStats.Reply);
rpc ReplicateGroupStats(ReplicateGroupStats.Request) returns (ReplicateGroupStats.Reply);
}
message ReplicatedGroup {
string public_key = 1 [(tagger.tags) = "gorm:\"primaryKey\""];
string sign_pub = 2;
string link_key = 3;
int64 created_at = 100;
int64 updated_at = 101;
int64 metadata_entries_count = 102;
string metadata_latest_head = 103;
int64 message_entries_count = 104;
string message_latest_head = 105;
}
message ReplicatedGroupToken {
string replicated_group_public_key = 1 [(tagger.tags) = "gorm:\"index;primaryKey;autoIncrement:false\""];
ReplicatedGroup replicated_group = 2;
string token_issuer = 3 [(tagger.tags) = "gorm:\"primaryKey;autoIncrement:false\""];
string token_id = 4 [(tagger.tags) = "gorm:\"primaryKey;autoIncrement:false\""];
int64 created_at = 5;
}
message ReplicationServiceReplicateGroup {
message Request {
weshnet.protocol.v1.Group group = 1;
}
message Reply {
bool ok = 1;
}
}
message ReplicateGlobalStats {
message Request {}
message Reply {
int64 started_at = 1;
int64 replicated_groups = 2;
int64 total_metadata_entries = 3;
int64 total_message_entries = 4;
}
}
message ReplicateGroupStats {
message Request {
string group_public_key = 1;
}
message Reply {
ReplicatedGroup group = 1;
}
}
================================================
FILE: api/protocol/verifiablecredstypes/bertyverifiablecreds.proto
================================================
syntax = "proto3";
package weshnet.account.v1;
option go_package = "berty.tech/weshnet/v2/pkg/verifiablecredstypes";
// StateChallenge serialized and signed state used when requesting a challenge
message StateChallenge {
bytes timestamp = 1;
bytes nonce = 2;
string berty_link = 3;
string redirect_uri = 4;
string state = 5;
}
// StateCode serialized and signed state used when requesting a code
message StateCode {
bytes timestamp = 1;
string berty_link = 2;
CodeStrategy code_strategy = 3;
string identifier = 4;
string code = 5;
string redirect_uri = 6;
string state = 7;
}
message AccountCryptoChallenge {
string challenge = 1;
}
enum FlowType {
FlowTypeUndefined = 0;
// FlowTypeCode asks users a code sent on a side channel
FlowTypeCode = 1;
// FlowTypeAuth currently unimplemented
FlowTypeAuth = 2;
// FlowTypeProof currently unimplemented
FlowTypeProof = 3;
}
enum CodeStrategy {
CodeStrategyUndefined = 0;
// CodeStrategy6Digits currently unimplemented
CodeStrategy6Digits = 1;
// CodeStrategy10Chars currently unimplemented
CodeStrategy10Chars = 2;
// CodeStrategyMocked6Zeroes must only be used in testing
CodeStrategyMocked6Zeroes = 999;
}
================================================
FILE: api_app.go
================================================
package weshnet
import (
"context"
"encoding/base64"
"fmt"
"github.com/ipfs/go-cid"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
func (s *service) AppMetadataSend(ctx context.Context, req *protocoltypes.AppMetadataSend_Request) (_ *protocoltypes.AppMetadataSend_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, fmt.Sprintf("Sending app metadata to group %s", base64.RawURLEncoding.EncodeToString(req.GroupPk)))
defer func() { endSection(err, "") }()
gc, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMissing.Wrap(err)
}
tyberLogGroupContext(ctx, s.logger, gc)
op, err := gc.MetadataStore().SendAppMetadata(ctx, req.Payload)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.AppMetadataSend_Reply{Cid: op.GetEntry().GetHash().Bytes()}, nil
}
func (s *service) AppMessageSend(ctx context.Context, req *protocoltypes.AppMessageSend_Request) (_ *protocoltypes.AppMessageSend_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, fmt.Sprintf("Sending message to group %s", base64.RawURLEncoding.EncodeToString(req.GroupPk)))
defer func() { endSection(err, "") }()
gc, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMissing.Wrap(err)
}
tyberLogGroupContext(ctx, s.logger, gc)
op, err := gc.MessageStore().AddMessage(ctx, req.Payload)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.AppMessageSend_Reply{Cid: op.GetEntry().GetHash().Bytes()}, nil
}
// OutOfStoreReceive parses a payload received outside a synchronized store
func (s *service) OutOfStoreReceive(ctx context.Context, request *protocoltypes.OutOfStoreReceive_Request) (*protocoltypes.OutOfStoreReceive_Reply, error) {
outOfStoreMessage, group, clearPayload, alreadyDecrypted, err := s.secretStore.OpenOutOfStoreMessage(ctx, request.Payload)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
return &protocoltypes.OutOfStoreReceive_Reply{
Message: outOfStoreMessage,
Cleartext: clearPayload,
GroupPublicKey: group.PublicKey,
AlreadyReceived: alreadyDecrypted,
}, nil
}
// OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
func (s *service) OutOfStoreSeal(ctx context.Context, request *protocoltypes.OutOfStoreSeal_Request) (*protocoltypes.OutOfStoreSeal_Reply, error) {
gc, err := s.GetContextGroupForID(request.GroupPublicKey)
if err != nil {
return nil, err
}
_, c, err := cid.CidFromBytes(request.Cid)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
sealedMessageEnvelope, err := gc.messageStore.GetOutOfStoreMessageEnvelope(ctx, c)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
sealedMessageEnvelopeBytes, err := proto.Marshal(sealedMessageEnvelope)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return &protocoltypes.OutOfStoreSeal_Reply{
Encrypted: sealedMessageEnvelopeBytes,
}, nil
}
func tyberLogGroupContext(ctx context.Context, logger *zap.Logger, gc *GroupContext) {
memberPK, err := gc.MemberPubKey().Raw()
if err != nil {
memberPK = []byte{}
}
logger.Debug("Got group context", tyber.FormatStepLogFields(ctx, []tyber.Detail{
{Name: "GroupType", Description: gc.Group().GetGroupType().String()},
{Name: "GroupPK", Description: base64.RawURLEncoding.EncodeToString(gc.Group().PublicKey)},
{Name: "MemberPK", Description: base64.RawURLEncoding.EncodeToString(memberPK)},
})...)
}
================================================
FILE: api_client.go
================================================
package weshnet
import (
"context"
"io"
"sync"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
func (s *service) ServiceExportData(_ *protocoltypes.ServiceExportData_Request, server protocoltypes.ProtocolService_ServiceExportDataServer) (err error) {
ctx, _, endSection := tyber.Section(server.Context(), s.logger, "Exporting protocol instance data")
defer func() { endSection(err, "") }()
r, w := io.Pipe()
var exportErr error
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer func() { _ = r.Close() }()
defer wg.Done()
for {
contents := make([]byte, 4096)
l, err := r.Read(contents)
if err == io.EOF {
break
} else if err != nil {
exportErr = errcode.ErrCode_ErrStreamRead.Wrap(err)
break
}
if err := server.Send(&protocoltypes.ServiceExportData_Reply{ExportedData: contents[:l]}); err != nil {
exportErr = errcode.ErrCode_ErrStreamWrite.Wrap(err)
break
}
}
}()
if err := s.export(ctx, w); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
_ = w.Close()
wg.Wait()
if exportErr != nil {
return exportErr
}
return nil
}
func (s *service) ServiceGetConfiguration(ctx context.Context, _ *protocoltypes.ServiceGetConfiguration_Request) (*protocoltypes.ServiceGetConfiguration_Reply, error) {
key, err := s.ipfsCoreAPI.Key().Self(ctx)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
maddrs, err := s.ipfsCoreAPI.Swarm().ListenAddrs(ctx)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
listeners := make([]string, len(maddrs))
for i, addr := range maddrs {
listeners[i] = addr.String()
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
member, err := accountGroup.MemberPubKey().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
device, err := accountGroup.DevicePubKey().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return &protocoltypes.ServiceGetConfiguration_Reply{
AccountPk: member,
DevicePk: device,
AccountGroupPk: accountGroup.Group().PublicKey,
PeerId: key.ID().String(),
Listeners: listeners,
}, nil
}
================================================
FILE: api_contact.go
================================================
package weshnet
import (
"context"
"fmt"
"time"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
func (s *service) ContactAliasKeySend(ctx context.Context, req *protocoltypes.ContactAliasKeySend_Request) (_ *protocoltypes.ContactAliasKeySend_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Sending contact alias key")
defer func() { endSection(err, "") }()
g, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMissing.Wrap(err)
}
if _, err := g.MetadataStore().ContactSendAliasKey(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactAliasKeySend_Reply{}, nil
}
func (s *service) ContactBlock(ctx context.Context, req *protocoltypes.ContactBlock_Request) (_ *protocoltypes.ContactBlock_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Blocking contact")
defer func() { endSection(err, "") }()
pk, err := crypto.UnmarshalEd25519PublicKey(req.ContactPk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if _, err := s.getAccountGroup().MetadataStore().ContactBlock(ctx, pk); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactBlock_Reply{}, nil
}
func (s *service) ContactUnblock(ctx context.Context, req *protocoltypes.ContactUnblock_Request) (_ *protocoltypes.ContactUnblock_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Unblocking contact")
defer func() { endSection(err, "") }()
pk, err := crypto.UnmarshalEd25519PublicKey(req.ContactPk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if _, err := s.getAccountGroup().MetadataStore().ContactUnblock(ctx, pk); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactUnblock_Reply{}, nil
}
func (s *service) RefreshContactRequest(ctx context.Context, req *protocoltypes.RefreshContactRequest_Request) (*protocoltypes.RefreshContactRequest_Reply, error) {
if len(req.ContactPk) == 0 {
return nil, errcode.ErrCode_ErrInternal
}
var cancel context.CancelFunc
if req.Timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, time.Duration(req.Timeout)*time.Second)
} else {
ctx, cancel = context.WithCancel(ctx)
}
defer cancel()
key := string(req.ContactPk)
s.muRefreshprocess.Lock()
if clfn, ok := s.refreshprocess[key]; ok {
clfn() // close previous refresh method
}
s.refreshprocess[key] = cancel
s.muRefreshprocess.Unlock()
peers, err := s.swiper.RefreshContactRequest(ctx, req.ContactPk)
if err != nil {
return nil, fmt.Errorf("unable to refresh group: %w", err)
}
res := &protocoltypes.RefreshContactRequest_Reply{
PeersFound: []*protocoltypes.RefreshContactRequest_Peer{},
}
for _, p := range peers {
// check if we can connect to this peers
if err := s.host.Connect(ctx, p); err != nil {
continue
}
addrs := make([]string, len(p.Addrs))
for i, addr := range p.Addrs {
addrs[i] = addr.String()
}
res.PeersFound = append(res.PeersFound, &protocoltypes.RefreshContactRequest_Peer{
Id: p.ID.String(),
Addrs: addrs,
})
}
return res, nil
}
================================================
FILE: api_contact_request_test.go
================================================
package weshnet
import (
"context"
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestShareContact(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
opts := TestingOpts{
Mocknet: mocknet.New(),
Logger: logger,
}
pts, cleanup := NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
binaryContact, err := pts[0].Client.ShareContact(ctx, &protocoltypes.ShareContact_Request{})
require.NoError(t, err)
// Check that ShareContact reset the contact request reference and enabled contact requests.
contactRequestRef, err := pts[0].Client.ContactRequestReference(ctx,
&protocoltypes.ContactRequestReference_Request{})
require.NoError(t, err)
require.NotEqual(t, 0, len(contactRequestRef.PublicRendezvousSeed))
require.Equal(t, true, contactRequestRef.Enabled)
// Decode.
contact, err := pts[0].Client.DecodeContact(ctx, &protocoltypes.DecodeContact_Request{
EncodedContact: binaryContact.EncodedContact,
})
require.NoError(t, err)
// Check for the expected info.
config, err := pts[0].Client.ServiceGetConfiguration(ctx,
&protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.Equal(t, contact.Contact.Pk, config.AccountPk)
require.Equal(t, contact.Contact.PublicRendezvousSeed, contactRequestRef.PublicRendezvousSeed)
}
================================================
FILE: api_contactrequest.go
================================================
package weshnet
import (
"context"
"github.com/libp2p/go-libp2p/core/crypto"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
// ContactRequestReference retrieves the necessary information to create a contact link
func (s *service) ContactRequestReference(context.Context, *protocoltypes.ContactRequestReference_Request) (*protocoltypes.ContactRequestReference_Reply, error) {
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
enabled, shareableContact := accountGroup.MetadataStore().GetIncomingContactRequestsStatus()
rdvSeed := []byte(nil)
if shareableContact != nil {
rdvSeed = shareableContact.PublicRendezvousSeed
}
return &protocoltypes.ContactRequestReference_Reply{
PublicRendezvousSeed: rdvSeed,
Enabled: enabled,
}, nil
}
// ContactRequestDisable disables incoming contact requests
func (s *service) ContactRequestDisable(ctx context.Context, _ *protocoltypes.ContactRequestDisable_Request) (_ *protocoltypes.ContactRequestDisable_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Disabling contact requests")
defer func() { endSection(err, "") }()
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestDisable(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactRequestDisable_Reply{}, nil
}
// ContactRequestEnable enables incoming contact requests
func (s *service) ContactRequestEnable(ctx context.Context, _ *protocoltypes.ContactRequestEnable_Request) (_ *protocoltypes.ContactRequestEnable_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Enabling contact requests")
defer func() { endSection(err, "") }()
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestEnable(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
_, shareableContact := accountGroup.MetadataStore().GetIncomingContactRequestsStatus()
rdvSeed := []byte(nil)
if shareableContact != nil {
rdvSeed = shareableContact.PublicRendezvousSeed
}
return &protocoltypes.ContactRequestEnable_Reply{
PublicRendezvousSeed: rdvSeed,
}, nil
}
// ContactRequestResetReference generates a new contact request reference
func (s *service) ContactRequestResetReference(ctx context.Context, _ *protocoltypes.ContactRequestResetReference_Request) (_ *protocoltypes.ContactRequestResetReference_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Resetting contact requests reference")
defer func() { endSection(err, "") }()
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestReferenceReset(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
_, shareableContact := accountGroup.MetadataStore().GetIncomingContactRequestsStatus()
rdvSeed := []byte(nil)
if shareableContact != nil {
rdvSeed = shareableContact.PublicRendezvousSeed
}
return &protocoltypes.ContactRequestResetReference_Reply{
PublicRendezvousSeed: rdvSeed,
}, nil
}
// ContactRequestSend enqueues a new contact request to be sent
func (s *service) ContactRequestSend(ctx context.Context, req *protocoltypes.ContactRequestSend_Request) (_ *protocoltypes.ContactRequestSend_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Sending contact request")
defer func() { endSection(err, "") }()
s.logger.Debug("Contact request info", tyber.FormatStepLogFields(ctx, []tyber.Detail{}, tyber.WithJSONDetail("Request", req))...)
shareableContact := req.Contact
if shareableContact == nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestOutgoingEnqueue(ctx, shareableContact, req.OwnMetadata); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactRequestSend_Reply{}, nil
}
// ContactRequestAccept accepts a contact request
func (s *service) ContactRequestAccept(ctx context.Context, req *protocoltypes.ContactRequestAccept_Request) (_ *protocoltypes.ContactRequestAccept_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Accepting contact request")
defer func() { endSection(err, "") }()
pk, err := crypto.UnmarshalEd25519PublicKey(req.ContactPk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
group, err := s.secretStore.GetGroupForContact(pk)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestIncomingAccept(ctx, pk); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
if err = s.secretStore.PutGroup(ctx, group); err != nil {
return nil, err
}
return &protocoltypes.ContactRequestAccept_Reply{}, nil
}
// ContactRequestDiscard ignores a contact request without informing the request sender
func (s *service) ContactRequestDiscard(ctx context.Context, req *protocoltypes.ContactRequestDiscard_Request) (_ *protocoltypes.ContactRequestDiscard_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Discarding contact request")
defer func() { endSection(err, "") }()
pk, err := crypto.UnmarshalEd25519PublicKey(req.ContactPk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().ContactRequestIncomingDiscard(ctx, pk); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.ContactRequestDiscard_Reply{}, nil
}
// ShareContact uses ContactRequestReference to get the contact information for the current account and
// returns the Protobuf encoding which you can further encode and share. If needed, his will reset the
// contact request reference and enable contact requests.
func (s *service) ShareContact(ctx context.Context, _ *protocoltypes.ShareContact_Request) (_ *protocoltypes.ShareContact_Reply, err error) {
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
enabled, shareableContact := accountGroup.MetadataStore().GetIncomingContactRequestsStatus()
rdvSeed := []byte(nil)
if shareableContact != nil {
rdvSeed = shareableContact.PublicRendezvousSeed
}
if !enabled || len(rdvSeed) == 0 {
// We need to enable and reset the contact request reference.
if _, err := accountGroup.MetadataStore().ContactRequestEnable(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
if _, err := accountGroup.MetadataStore().ContactRequestReferenceReset(ctx); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
// Refresh the info.
_, shareableContact = accountGroup.MetadataStore().GetIncomingContactRequestsStatus()
rdvSeed = []byte(nil)
if shareableContact != nil {
rdvSeed = shareableContact.PublicRendezvousSeed
}
}
// Get the client's AccountPK.
member, err := accountGroup.MemberPubKey().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
encodedContact, err := proto.Marshal(&protocoltypes.ShareableContact{
Pk: member,
PublicRendezvousSeed: rdvSeed,
})
if err != nil {
return nil, err
}
return &protocoltypes.ShareContact_Reply{
EncodedContact: encodedContact,
}, nil
}
// DecodeContact decodes the Protobuf encoding of a shareable contact which was returned by ShareContact.
func (s *service) DecodeContact(_ context.Context, req *protocoltypes.DecodeContact_Request) (_ *protocoltypes.DecodeContact_Reply, err error) {
contact := &protocoltypes.ShareableContact{}
if err := proto.Unmarshal(req.EncodedContact, contact); err != nil {
panic(err)
}
return &protocoltypes.DecodeContact_Reply{
Contact: contact,
}, nil
}
================================================
FILE: api_debug.go
================================================
package weshnet
import (
"context"
"fmt"
"strings"
"time"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/multierr"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/v2/internal/sysutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func (s *service) DebugListGroups(_ *protocoltypes.DebugListGroups_Request, srv protocoltypes.ProtocolService_DebugListGroupsServer) error {
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return errcode.ErrCode_ErrGroupMissing
}
if err := srv.SendMsg(&protocoltypes.DebugListGroups_Reply{
GroupPk: accountGroup.group.PublicKey,
GroupType: accountGroup.group.GroupType,
}); err != nil {
return err
}
for _, c := range accountGroup.MetadataStore().ListContactsByStatus(protocoltypes.ContactState_ContactStateAdded) {
pk, err := crypto.UnmarshalEd25519PublicKey(c.Pk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
group, err := s.secretStore.GetGroupForContact(pk)
if err != nil {
return errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
if err := srv.SendMsg(&protocoltypes.DebugListGroups_Reply{
GroupPk: group.PublicKey,
GroupType: group.GroupType,
ContactPk: c.Pk,
}); err != nil {
return err
}
}
for _, g := range accountGroup.MetadataStore().ListMultiMemberGroups() {
if err := srv.SendMsg(&protocoltypes.DebugListGroups_Reply{
GroupPk: g.PublicKey,
GroupType: g.GroupType,
}); err != nil {
return err
}
}
return nil
}
func (s *service) DebugInspectGroupStore(req *protocoltypes.DebugInspectGroupStore_Request, srv protocoltypes.ProtocolService_DebugInspectGroupStoreServer) error {
if req.LogType == protocoltypes.DebugInspectGroupLogType_DebugInspectGroupLogTypeUndefined {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid log type specified"))
}
cg, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
switch req.LogType {
case protocoltypes.DebugInspectGroupLogType_DebugInspectGroupLogTypeMessage:
for _, e := range cg.messageStore.OpLog().GetEntries().Slice() {
var (
payload = []byte(nil)
devicePK = []byte(nil)
nexts = make([][]byte, len(e.GetNext()))
)
if evt, err := cg.messageStore.openMessage(srv.Context(), e); err != nil {
s.logger.Error("unable to open message", zap.Error(err))
} else {
devicePK = evt.Headers.DevicePk
payload = evt.Message
}
for i, n := range e.GetNext() {
nexts[i] = n.Bytes()
}
if err := srv.SendMsg(&protocoltypes.DebugInspectGroupStore_Reply{
Cid: e.GetHash().Bytes(),
ParentCids: nexts,
DevicePk: devicePK,
Payload: payload,
}); err != nil {
return err
}
}
case protocoltypes.DebugInspectGroupLogType_DebugInspectGroupLogTypeMetadata:
log := cg.metadataStore.OpLog()
for _, e := range log.GetEntries().Slice() {
var (
eventType protocoltypes.EventType
payload = []byte(nil)
devicePK = []byte(nil)
nexts = make([][]byte, len(e.GetNext()))
)
if op, err := operation.ParseOperation(e); err != nil {
s.logger.Error("unable to parse operation", zap.Error(err))
} else if meta, event, err := openGroupEnvelope(cg.group, op.GetValue()); err != nil {
s.logger.Error("unable to open group envelope", zap.Error(err))
} else if metaEvent, err := newGroupMetadataEventFromEntry(log, e, meta, event, cg.group); err != nil {
s.logger.Error("unable to get group metadata event from entry", zap.Error(err))
} else {
payload = metaEvent.Event
eventType = metaEvent.Metadata.EventType
if typeData, ok := eventTypesMapper[metaEvent.Metadata.EventType]; ok {
p := proto.Clone(typeData.Message)
if err := proto.Unmarshal(metaEvent.Event, p); err == nil {
if msg, ok := p.(eventDeviceSigned); ok {
devicePK = msg.GetDevicePk()
}
}
} else {
s.logger.Error("unable to get message struct for event type", zap.String("event_type", metaEvent.Metadata.EventType.String()))
}
}
for i, n := range e.GetNext() {
nexts[i] = n.Bytes()
}
if err := srv.SendMsg(&protocoltypes.DebugInspectGroupStore_Reply{
Cid: e.GetHash().Bytes(),
ParentCids: nexts,
Payload: payload,
MetadataEventType: eventType,
DevicePk: devicePK,
}); err != nil {
return err
}
}
}
return nil
}
func (s *service) DebugGroup(ctx context.Context, request *protocoltypes.DebugGroup_Request) (*protocoltypes.DebugGroup_Reply, error) {
rep := &protocoltypes.DebugGroup_Reply{}
peers, err := s.ipfsCoreAPI.Swarm().Peers(ctx)
if err != nil {
return nil, err
}
topic := fmt.Sprintf("grp_%s", string(request.GroupPk))
for _, p := range peers {
tagInfo := s.ipfsCoreAPI.ConnMgr().GetTagInfo(p.ID())
if _, ok := tagInfo.Tags[topic]; ok {
rep.PeerIds = append(rep.PeerIds, p.ID().String())
}
}
return rep, nil
}
func (s *service) SystemInfo(ctx context.Context, _ *protocoltypes.SystemInfo_Request) (*protocoltypes.SystemInfo_Reply, error) {
reply := protocoltypes.SystemInfo_Reply{}
// process
process, errs := sysutil.SystemInfoProcess()
reply.Process = process
reply.Process.StartedAt = s.startedAt.Unix()
reply.Process.UptimeMs = time.Since(s.startedAt).Milliseconds()
// gRPC
// TODO
// p2p
{
reply.P2P = &protocoltypes.SystemInfo_P2P{}
// swarm metrics
if api := s.IpfsCoreAPI(); api != nil {
peers, err := api.Swarm().Peers(ctx)
reply.P2P.ConnectedPeers = int64(len(peers))
errs = multierr.Append(errs, err)
} else {
errs = multierr.Append(errs, fmt.Errorf("no such IPFS core API"))
}
// pubsub metrics
// TODO
// BLE metrics
}
// OrbitDB
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
status := accountGroup.metadataStore.ReplicationStatus()
reply.Orbitdb = &protocoltypes.SystemInfo_OrbitDB{
AccountMetadata: &protocoltypes.SystemInfo_OrbitDB_ReplicationStatus{
Progress: int64(status.GetProgress()),
Maximum: int64(status.GetMax()),
},
}
// FIXME: compute more stores
// warns
if errs != nil {
reply.Warns = []string{}
for _, err := range multierr.Errors(errs) {
reply.Warns = append(reply.Warns, err.Error())
}
}
return &reply, nil
}
func (s *service) PeerList(ctx context.Context, _ *protocoltypes.PeerList_Request) (*protocoltypes.PeerList_Reply, error) {
reply := protocoltypes.PeerList_Reply{}
api := s.IpfsCoreAPI()
if api == nil {
return nil, errcode.ErrCode_TODO.Wrap(fmt.Errorf("IPFS Core API is not available"))
}
swarmPeers, err := api.Swarm().Peers(ctx) // https://pkg.go.dev/github.com/ipfs/interface-go-ipfs-core#ConnectionInfo
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
peers := map[peer.ID]*protocoltypes.PeerList_Peer{}
// each peer in the swarm should be visible
for _, swarmPeer := range swarmPeers {
peers[swarmPeer.ID()] = &protocoltypes.PeerList_Peer{
Id: swarmPeer.ID().String(),
Errors: []string{},
Routes: []*protocoltypes.PeerList_Route{},
}
}
// FIXME: do not restrict on swarm peers, also print some other important ones (old, etc)
// append peer addrs from peerstore
for peerID, peer := range peers {
info := s.host.Peerstore().PeerInfo(peerID)
for _, addr := range info.Addrs {
peer.Routes = append(peer.Routes, &protocoltypes.PeerList_Route{
Address: addr.String(),
})
}
}
// append more info for active connections
for _, swarmPeer := range swarmPeers {
peer, ok := peers[swarmPeer.ID()]
if !ok {
peer = &protocoltypes.PeerList_Peer{
Id: swarmPeer.ID().String(),
Errors: []string{},
Routes: []*protocoltypes.PeerList_Route{},
}
peer.Errors = append(peer.Errors, "peer in swarm peers, but not in peerstore")
peers[swarmPeer.ID()] = peer
}
address := swarmPeer.Address().String()
found := false
var selectedRoute *protocoltypes.PeerList_Route
for _, route := range peer.Routes {
if route.Address == address {
found = true
selectedRoute = route
}
}
if !found {
newRoute := protocoltypes.PeerList_Route{Address: address}
peer.Routes = append(peer.Routes, &newRoute)
selectedRoute = &newRoute
}
selectedRoute.IsActive = true
// latency
{
latency, err := swarmPeer.Latency()
if err != nil {
peer.Errors = append(peer.Errors, err.Error())
} else {
selectedRoute.Latency = latency.Milliseconds()
}
}
// direction
{
switch swarmPeer.Direction() {
case network.DirInbound:
selectedRoute.Direction = protocoltypes.Direction_InboundDir
case network.DirOutbound:
selectedRoute.Direction = protocoltypes.Direction_OutboundDir
}
}
// streams
{
peerStreams, err := swarmPeer.Streams()
if err != nil {
peer.Errors = append(peer.Errors, err.Error())
} else {
selectedRoute.Streams = []*protocoltypes.PeerList_Stream{}
for _, peerStream := range peerStreams {
if peerStream == "" {
continue
}
selectedRoute.Streams = append(selectedRoute.Streams, &protocoltypes.PeerList_Stream{
Id: string(peerStream),
})
}
}
}
}
// compute features
for _, peer := range peers {
features := map[protocoltypes.PeerList_Feature]bool{}
for _, route := range peer.Routes {
// FIXME: use the multiaddr library instead of string comparisons
if strings.Contains(route.Address, "/quic") {
features[protocoltypes.PeerList_QuicFeature] = true
}
if strings.Contains(route.Address, "/mc/") {
features[protocoltypes.PeerList_BLEFeature] = true
features[protocoltypes.PeerList_WeshFeature] = true
}
if strings.Contains(route.Address, "/tor/") {
features[protocoltypes.PeerList_TorFeature] = true
}
for _, stream := range route.Streams {
if stream.Id == "/wesh/contact_req/1.0.0" {
features[protocoltypes.PeerList_WeshFeature] = true
}
if stream.Id == "/rendezvous/1.0.0" {
features[protocoltypes.PeerList_WeshFeature] = true
}
}
}
for feature := range features {
peer.Features = append(peer.Features, feature)
}
}
// compute peer-level aggregates
for _, peer := range peers {
// aggregate direction
for _, route := range peer.Routes {
if route.Direction == protocoltypes.Direction_UnknownDir {
continue
}
switch {
case peer.Direction == protocoltypes.Direction_UnknownDir: // first route with a direction
peer.Direction = route.Direction
case peer.Direction == protocoltypes.Direction_BiDir: // peer aggregate is already maximal
// noop
case route.Direction == peer.Direction: // another route with the same direction
// noop
case route.Direction == protocoltypes.Direction_InboundDir && peer.Direction == protocoltypes.Direction_OutboundDir:
peer.Direction = protocoltypes.Direction_BiDir
case route.Direction == protocoltypes.Direction_OutboundDir && peer.Direction == protocoltypes.Direction_InboundDir:
peer.Direction = protocoltypes.Direction_BiDir
default:
peer.Errors = append(peer.Errors, "failed to compute direction aggregate")
}
}
// aggregate latency
for _, route := range peer.Routes {
if route.Latency == 0 {
continue
}
switch {
case peer.MinLatency == 0: // first route with a latency
peer.MinLatency = route.Latency
case peer.MinLatency > route.Latency: // smaller value
peer.MinLatency = route.Latency
}
}
// aggregate isActive
for _, route := range peer.Routes {
if route.IsActive {
peer.IsActive = true
break
}
}
}
// FIXME: compute pubsub peers too?
// FIXME: add metrics about "amount of times seen", "first time seen", "bandwidth"
// use protobuf format
for _, peer := range peers {
reply.Peers = append(reply.Peers, peer)
}
return &reply, nil
}
================================================
FILE: api_event.go
================================================
package weshnet
import (
"context"
"errors"
"fmt"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func checkParametersConsistency(sinceID, untilID []byte, sinceNow, untilNow, reverseOrder bool) error {
// Since can't be both set to an ID and to now
if sinceID != nil && sinceNow {
return errcode.ErrCode_ErrInvalidInput.Wrap(errors.New("params SinceNow and SinceID are both set"))
}
// Until can't be both set to an ID and to now
if untilID != nil && untilNow {
return errcode.ErrCode_ErrInvalidInput.Wrap(errors.New("params UntilNow and UntilID are both set"))
}
// Since and Until can't be both set to now at the same time
if sinceNow && untilNow {
return errcode.ErrCode_ErrInvalidInput.Wrap(errors.New("params SinceNow and UntilNow are both set"))
}
// Can't reverse events orders if subscribed to new events
if untilID == nil && !untilNow && reverseOrder {
return errcode.ErrCode_ErrInvalidInput.Wrap(errors.New("reverse chronological order requested while subscribing to new events"))
}
return nil
}
// GroupMetadataList replays previous and subscribes to new metadata events from the group
func (s *service) GroupMetadataList(req *protocoltypes.GroupMetadataList_Request, sub protocoltypes.ProtocolService_GroupMetadataListServer) error {
ctx, cancel := context.WithCancel(sub.Context())
defer cancel()
// Get group context / check if the group is opened
cg, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
// Check parameters consistency
if err := checkParametersConsistency(req.SinceId, req.UntilId, req.SinceNow, req.UntilNow, req.ReverseOrder); err != nil {
return err
}
// Subscribe to new metadata events if requested
var newEvents <-chan any
if req.UntilId == nil && !req.UntilNow {
sub, err := cg.MetadataStore().EventBus().Subscribe([]any{
// new(stores.EventReplicated),
new(*protocoltypes.GroupMetadataEvent),
}, eventbus.Name("weshnet/api/group-metadata-list"), eventbus.BufSize(32))
if err != nil {
return fmt.Errorf("unable to subscribe to new events")
}
defer sub.Close()
newEvents = sub.Out()
}
// Subscribe to previous metadata events and stream them if requested
previousEvents := make(chan *protocoltypes.GroupMetadataEvent)
if !req.SinceNow {
pevt, err := cg.MetadataStore().ListEvents(ctx, req.SinceId, req.UntilId, req.ReverseOrder)
if err != nil {
return err
}
go func() {
for {
var evt *protocoltypes.GroupMetadataEvent
select {
case <-ctx.Done():
return
case evt = <-pevt:
}
if evt == nil {
// if we don't want to stream new event, cancel the process
if req.UntilNow {
cancel()
} else {
previousEvents <- &protocoltypes.GroupMetadataEvent{EventContext: nil}
}
cg.logger.Debug("GroupMetadataList: previous events stream ended")
return
}
previousEvents <- evt
}
}()
}
// Subscribe to new metadata events and stream them if requested
for {
var event any
select {
case <-ctx.Done():
return nil
case event = <-previousEvents:
case event = <-newEvents:
}
msg := event.(*protocoltypes.GroupMetadataEvent)
if msg.EventContext == nil {
continue
}
if err := sub.Send(msg); err != nil {
return err
}
cg.logger.Info("service - metadata store - sent 1 event from log subscription")
}
}
// GroupMessageList replays previous and subscribes to new message events from the group
func (s *service) GroupMessageList(req *protocoltypes.GroupMessageList_Request, sub protocoltypes.ProtocolService_GroupMessageListServer) error {
ctx, cancel := context.WithCancel(sub.Context())
defer cancel()
// Get group context / check if the group is opened
cg, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
// Check parameters consistency
if err := checkParametersConsistency(req.SinceId, req.UntilId, req.SinceNow, req.UntilNow, req.ReverseOrder); err != nil {
return err
}
// Subscribe to new message events if requested
var newEvents <-chan any
if req.UntilId == nil && !req.UntilNow {
messageStoreSub, err := cg.MessageStore().EventBus().Subscribe([]any{
new(*protocoltypes.GroupMessageEvent),
}, eventbus.Name("weshnet/api/group-message-list"))
if err != nil {
return fmt.Errorf("unable to subscribe to new events")
}
defer messageStoreSub.Close()
newEvents = messageStoreSub.Out()
}
// Subscribe to previous message events and stream them if requested
previousEvents := make(chan *protocoltypes.GroupMessageEvent)
if !req.SinceNow {
pevt, err := cg.MessageStore().ListEvents(ctx, req.SinceId, req.UntilId, req.ReverseOrder)
if err != nil {
return err
}
go func() {
for {
var evt *protocoltypes.GroupMessageEvent
select {
case <-ctx.Done():
return
case evt = <-pevt:
}
if evt == nil {
// if we don't want to stream new event, cancel the process
if req.UntilNow {
cancel()
} else {
previousEvents <- &protocoltypes.GroupMessageEvent{EventContext: nil}
}
cg.logger.Debug("GroupMessageList: previous events stream ended")
return
}
previousEvents <- evt
}
}()
}
// Subscribe to new message events and stream them if requested
for {
var event any
select {
case <-ctx.Done():
return nil
case event = <-previousEvents:
case event = <-newEvents:
}
msg := event.(*protocoltypes.GroupMessageEvent)
if msg.EventContext == nil {
continue
}
if err := sub.Send(msg); err != nil {
return err
}
cg.logger.Info("service - message store - sent 1 event from log subscription")
}
}
================================================
FILE: api_group.go
================================================
package weshnet
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
manet "github.com/multiformats/go-multiaddr/net"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func (s *service) GroupInfo(ctx context.Context, req *protocoltypes.GroupInfo_Request) (*protocoltypes.GroupInfo_Reply, error) {
var (
g *protocoltypes.Group
err error
)
switch {
case req.GroupPk != nil:
pk, err := crypto.UnmarshalEd25519PublicKey(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
g, err = s.getGroupForPK(ctx, pk)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
case req.ContactPk != nil:
pk, err := crypto.UnmarshalEd25519PublicKey(req.ContactPk)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
g, err = s.getContactGroup(pk)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
default:
return nil, errcode.ErrCode_ErrInvalidInput
}
memberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
member, err := memberDevice.Member().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
device, err := memberDevice.Device().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return &protocoltypes.GroupInfo_Reply{
Group: g,
MemberPk: member,
DevicePk: device,
}, nil
}
func (s *service) ActivateGroup(ctx context.Context, req *protocoltypes.ActivateGroup_Request) (*protocoltypes.ActivateGroup_Reply, error) {
pk, err := crypto.UnmarshalEd25519PublicKey(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
err = s.activateGroup(ctx, pk, req.LocalOnly)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return &protocoltypes.ActivateGroup_Reply{}, nil
}
func (s *service) DeactivateGroup(_ context.Context, req *protocoltypes.DeactivateGroup_Request) (*protocoltypes.DeactivateGroup_Reply, error) {
pk, err := crypto.UnmarshalEd25519PublicKey(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
if err := s.deactivateGroup(pk); err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return &protocoltypes.DeactivateGroup_Reply{}, nil
}
func (s *service) GroupDeviceStatus(req *protocoltypes.GroupDeviceStatus_Request, srv protocoltypes.ProtocolService_GroupDeviceStatusServer) error {
ctx := srv.Context()
gkey := hex.EncodeToString(req.GroupPk)
peers := PeersConnectedness{}
logger := s.logger.Named("pstatus")
logger.Debug("start monitor device status group", logutil.PrivateString("group_key", gkey))
for {
updated, ok := s.peerStatusManager.WaitForConnectednessChange(ctx, gkey, peers)
if !ok {
return nil // server context has expired
}
// send updated peers
var err error
for _, peer := range updated {
var evt protocoltypes.GroupDeviceStatus_Reply
switch peers[peer] {
case ConnectednessTypeConnected:
evt.Type = protocoltypes.GroupDeviceStatus_TypePeerConnected
var connected *protocoltypes.GroupDeviceStatus_Reply_PeerConnected
if connected, err = s.craftPeerConnectedMessage(peer); err == nil {
evt.Event, err = proto.Marshal(connected)
logger.Debug("peer connected",
logutil.PrivateString("group_key", gkey),
logutil.PrivateString("peer", connected.PeerId),
logutil.PrivateString("devicePK", base64.URLEncoding.EncodeToString(connected.GetDevicePk())))
}
case ConnectednessTypeDisconnected:
evt.Type = protocoltypes.GroupDeviceStatus_TypePeerDisconnected
disconnected := s.craftDeviceDisconnectedMessage(peer)
logger.Debug("peer disconnected",
logutil.PrivateString("group_key", gkey),
logutil.PrivateString("peer", disconnected.PeerId))
evt.Event, err = proto.Marshal(disconnected)
case ConnectednessTypeReconnecting:
evt.Type = protocoltypes.GroupDeviceStatus_TypePeerConnected
reconnecting := s.craftDeviceReconnectedMessage(peer)
logger.Debug("peer reconnecting",
logutil.PrivateString("group_key", gkey),
logutil.PrivateString("peer", reconnecting.PeerId))
evt.Event, err = proto.Marshal(reconnecting)
default:
evt.Type = protocoltypes.GroupDeviceStatus_TypeUnknown
}
if err != nil {
logger.Error("GroupDeviceStatus: unable to handle event", zap.Error(err))
continue
}
if err := srv.Send(&evt); err != nil {
logger.Debug("GroupDeviceStatus: failed to send event", zap.Error(err))
return err
}
}
}
}
func (s *service) craftPeerConnectedMessage(peer peer.ID) (*protocoltypes.GroupDeviceStatus_Reply_PeerConnected, error) {
pdg, ok := s.odb.GetDevicePKForPeerID(peer)
if !ok {
return nil, fmt.Errorf("PeerDeviceGroup unknown")
}
devicePKRaw, err := pdg.DevicePK.Raw()
if err != nil {
return nil, fmt.Errorf("unable to get raw devicePK: %w", err)
}
connected := protocoltypes.GroupDeviceStatus_Reply_PeerConnected{
PeerId: peer.String(),
DevicePk: devicePKRaw,
}
activeConns := s.host.Network().ConnsToPeer(peer)
connected.Transports = make([]protocoltypes.GroupDeviceStatus_Transport, len(activeConns))
connected.Maddrs = make([]string, len(activeConns))
CONN_LOOP:
for i, conn := range activeConns {
connected.Maddrs[i] = conn.RemoteMultiaddr().String()
// check for proximity transport
protocols := conn.RemoteMultiaddr().Protocols()
for _, protocol := range protocols {
switch protocol.Name {
case "nearby", "mc", "ble":
connected.Transports[i] = protocoltypes.GroupDeviceStatus_TptProximity
continue CONN_LOOP
}
}
// otherwise, check for WAN/LAN addr
if manet.IsPrivateAddr(conn.RemoteMultiaddr()) {
connected.Transports[i] = protocoltypes.GroupDeviceStatus_TptLAN
} else {
connected.Transports[i] = protocoltypes.GroupDeviceStatus_TptWAN
}
}
return &connected, nil
}
func (s *service) craftDeviceDisconnectedMessage(peer peer.ID) *protocoltypes.GroupDeviceStatus_Reply_PeerDisconnected {
return &protocoltypes.GroupDeviceStatus_Reply_PeerDisconnected{
PeerId: peer.String(),
}
}
func (s *service) craftDeviceReconnectedMessage(peer peer.ID) *protocoltypes.GroupDeviceStatus_Reply_PeerReconnecting {
return &protocoltypes.GroupDeviceStatus_Reply_PeerReconnecting{
PeerId: peer.String(),
}
}
================================================
FILE: api_multimember.go
================================================
package weshnet
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
// MultiMemberGroupCreate creates a new MultiMember group
func (s *service) MultiMemberGroupCreate(ctx context.Context, _ *protocoltypes.MultiMemberGroupCreate_Request) (_ *protocoltypes.MultiMemberGroupCreate_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Creating MultiMember group")
defer func() { endSection(err, "") }()
group, groupPrivateKey, err := NewGroupMultiMember()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
_, err = accountGroup.MetadataStore().GroupJoin(ctx, group)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
if err := s.secretStore.PutGroup(ctx, group); err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
err = s.activateGroup(ctx, groupPrivateKey.GetPublic(), false)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to activate group: %w", err))
}
cg, err := s.GetContextGroupForID(group.PublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
_, err = cg.MetadataStore().ClaimGroupOwnership(ctx, groupPrivateKey)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.MultiMemberGroupCreate_Reply{
GroupPk: group.PublicKey,
}, nil
}
// MultiMemberGroupJoin joins an existing MultiMember group using an invitation
func (s *service) MultiMemberGroupJoin(ctx context.Context, req *protocoltypes.MultiMemberGroupJoin_Request) (_ *protocoltypes.MultiMemberGroupJoin_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Joining MultiMember group")
defer func() { endSection(err, "") }()
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if _, err := accountGroup.MetadataStore().GroupJoin(ctx, req.Group); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.MultiMemberGroupJoin_Reply{}, nil
}
// MultiMemberGroupLeave leaves a previously joined MultiMember group
func (s *service) MultiMemberGroupLeave(ctx context.Context, req *protocoltypes.MultiMemberGroupLeave_Request) (_ *protocoltypes.MultiMemberGroupLeave_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Leaving MultiMember group")
defer func() { endSection(err, "") }()
pk, err := crypto.UnmarshalEd25519PublicKey(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
_, err = accountGroup.MetadataStore().GroupLeave(ctx, pk)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
if err := s.deactivateGroup(pk); err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.MultiMemberGroupLeave_Reply{}, nil
}
// MultiMemberGroupAliasResolverDisclose sends an deviceKeystore identity proof to the group members
func (s *service) MultiMemberGroupAliasResolverDisclose(ctx context.Context, req *protocoltypes.MultiMemberGroupAliasResolverDisclose_Request) (*protocoltypes.MultiMemberGroupAliasResolverDisclose_Reply, error) {
cg, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
_, err = cg.MetadataStore().SendAliasProof(ctx)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
return &protocoltypes.MultiMemberGroupAliasResolverDisclose_Reply{}, nil
}
// MultiMemberGroupAdminRoleGrant grants admin role to another member of the group
func (s *service) MultiMemberGroupAdminRoleGrant(context.Context, *protocoltypes.MultiMemberGroupAdminRoleGrant_Request) (*protocoltypes.MultiMemberGroupAdminRoleGrant_Reply, error) {
return nil, errcode.ErrCode_ErrNotImplemented
}
// MultiMemberGroupInvitationCreate creates a group invitation
func (s *service) MultiMemberGroupInvitationCreate(_ context.Context, req *protocoltypes.MultiMemberGroupInvitationCreate_Request) (*protocoltypes.MultiMemberGroupInvitationCreate_Reply, error) {
cg, err := s.GetContextGroupForID(req.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
return &protocoltypes.MultiMemberGroupInvitationCreate_Reply{
Group: cg.Group(),
}, nil
}
================================================
FILE: api_replication.go
================================================
package weshnet
import (
"context"
"crypto/tls"
"encoding/base64"
"fmt"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/grpcutil"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/replicationtypes"
"berty.tech/weshnet/v2/pkg/tyber"
)
func FilterGroupForReplication(m *protocoltypes.Group) (*protocoltypes.Group, error) {
groupSigPK, err := m.GetSigningPubKey()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
groupSigPKBytes, err := groupSigPK.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
linkKey, err := m.GetLinkKeyArray()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return &protocoltypes.Group{
PublicKey: m.PublicKey,
SignPub: groupSigPKBytes,
LinkKey: linkKey[:],
LinkKeySig: m.LinkKeySig,
}, nil
}
func (s *service) ReplicationServiceRegisterGroup(ctx context.Context, request *protocoltypes.ReplicationServiceRegisterGroup_Request) (_ *protocoltypes.ReplicationServiceRegisterGroup_Reply, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "Registering replication service for group")
defer func() { endSection(err, "") }()
if request.GroupPk == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid GroupPK"))
}
if request.Token == "" {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid token"))
}
if request.ReplicationServer == "" {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid replication server"))
}
gc, err := s.GetContextGroupForID(request.GroupPk)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
replGroup, err := FilterGroupForReplication(gc.group)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
gopts := []grpc.DialOption{
grpc.WithPerRPCCredentials(grpcutil.NewUnsecureSimpleAuthAccess("bearer", request.Token)),
}
if s.grpcInsecure {
gopts = append(gopts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
tlsconfig := credentials.NewTLS(&tls.Config{
MinVersion: tls.VersionTLS12,
})
gopts = append(gopts, grpc.WithTransportCredentials(tlsconfig))
}
cc, err := grpc.NewClient("passthrough://"+request.ReplicationServer, gopts...)
if err != nil {
return nil, errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
client := replicationtypes.NewReplicationServiceClient(cc)
if _, err = client.ReplicateGroup(ctx, &replicationtypes.ReplicationServiceReplicateGroup_Request{
Group: replGroup,
}); err != nil {
return nil, errcode.ErrCode_ErrServiceReplicationServer.Wrap(err)
}
s.logger.Info("group will be replicated", logutil.PrivateString("public-key", base64.RawURLEncoding.EncodeToString(request.GroupPk)))
if _, err := gc.metadataStore.SendGroupReplicating(ctx, request.AuthenticationUrl, request.ReplicationServer); err != nil {
s.logger.Error("error while notifying group about replication", zap.Error(err))
}
return &protocoltypes.ReplicationServiceRegisterGroup_Reply{}, nil
}
================================================
FILE: api_verified_credentials.go
================================================
package weshnet
import (
"bytes"
"context"
"fmt"
"strings"
"time"
"berty.tech/weshnet/v2/pkg/bertyvcissuer"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func (s *service) CredentialVerificationServiceInitFlow(ctx context.Context, request *protocoltypes.CredentialVerificationServiceInitFlow_Request) (*protocoltypes.CredentialVerificationServiceInitFlow_Reply, error) {
s.lock.Lock()
s.vcClient = bertyvcissuer.NewClient(request.ServiceUrl)
client := s.vcClient
s.lock.Unlock()
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
defer cancel()
// TODO: allow selection of alt-scoped keys
// TODO: avoid exporting account keys
pkRaw, err := s.accountGroupCtx.ownMemberDevice.Member().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
if !bytes.Equal(pkRaw, request.PublicKey) {
return nil, errcode.ErrCode_ErrInvalidInput
}
url, err := client.Init(ctx, request.Link, cryptoutil.NewFuncSigner(s.accountGroupCtx.ownMemberDevice.Member(), s.accountGroupCtx.ownMemberDevice.MemberSign))
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return &protocoltypes.CredentialVerificationServiceInitFlow_Reply{
Url: url,
SecureUrl: strings.HasPrefix(url, "https://"),
}, nil
}
func (s *service) CredentialVerificationServiceCompleteFlow(ctx context.Context, request *protocoltypes.CredentialVerificationServiceCompleteFlow_Request) (*protocoltypes.CredentialVerificationServiceCompleteFlow_Reply, error) {
s.lock.Lock()
client := s.vcClient
s.lock.Unlock()
if client == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("a verification flow needs to be started first"))
}
credentials, identifier, parsedCredential, err := client.Complete(request.CallbackUri)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
_, err = s.accountGroupCtx.metadataStore.SendAccountVerifiedCredentialAdded(ctx, &protocoltypes.AccountVerifiedCredentialRegistered{
VerifiedCredential: credentials,
RegistrationDate: parsedCredential.Issued.UnixNano(),
ExpirationDate: parsedCredential.Expired.UnixNano(),
Identifier: identifier,
Issuer: parsedCredential.Issuer.ID,
})
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return &protocoltypes.CredentialVerificationServiceCompleteFlow_Reply{
Identifier: identifier,
}, nil
}
func (s *service) VerifiedCredentialsList(request *protocoltypes.VerifiedCredentialsList_Request, server protocoltypes.ProtocolService_VerifiedCredentialsListServer) error {
now := time.Now().UnixNano()
credentials := s.accountGroupCtx.metadataStore.ListVerifiedCredentials()
for _, credential := range credentials {
if request.FilterIdentifier != "" && credential.Identifier != request.FilterIdentifier {
continue
}
if request.ExcludeExpired && credential.ExpirationDate < now {
continue
}
if request.FilterIssuer != "" && credential.Issuer != request.FilterIssuer {
continue
}
if err := server.Send(&protocoltypes.VerifiedCredentialsList_Reply{
Credential: credential,
}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
}
return nil
}
================================================
FILE: blackbox_test.go
================================================
package weshnet_test
import (
"context"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestTestingClient_impl(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
secretStore, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
client, cleanup := weshnet.TestingService(ctx, t, weshnet.Opts{
Logger: logger,
SecretStore: secretStore,
})
defer cleanup()
// test service
_, _ = client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
status := client.Status()
expected := weshnet.Status{}
assert.Equal(t, expected, status)
}
func ExampleNewInMemoryServiceClient_basic() {
// disable resources manager for test
os.Setenv("LIBP2P_RCMGR", "false")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
client, err := weshnet.NewInMemoryServiceClient()
if err != nil {
panic(err)
}
defer client.Close()
ret, err := client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
if err != nil {
panic(err)
}
for _, listener := range ret.Listeners {
if listener == "/p2p-circuit" {
fmt.Println(listener)
}
}
// Output:
// /p2p-circuit
}
func ExampleNewPersistentServiceClient_basic() {
// disable resources manager for test
os.Setenv("LIBP2P_RCMGR", "false")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// create a temporary path to host data of our persistent service
path, err := os.MkdirTemp("", "weshnet-test-persistent")
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
var peerid string
// open once
{
client, err := weshnet.NewPersistentServiceClient(path)
if err != nil {
panic(err)
}
ret, err := client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
if err != nil {
panic(err)
}
peerid = ret.PeerId
if err := client.Close(); err != nil {
panic(err)
}
}
// open twice
{
client, err := weshnet.NewPersistentServiceClient(path)
if err != nil {
panic(err)
}
defer client.Close()
ret, err := client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
if err != nil {
panic(err)
}
if peerid != ret.PeerId {
panic("peerid should be identical")
}
}
// Output:
}
func ExampleNewServiceClient_basic() {
// disable resources manager for test
os.Setenv("LIBP2P_RCMGR", "false")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
client, err := weshnet.NewServiceClient(weshnet.Opts{})
if err != nil {
panic(err)
}
defer client.Close()
ret, err := client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
if err != nil {
panic(err)
}
for _, listener := range ret.Listeners {
if listener == "/p2p-circuit" {
fmt.Println(listener)
}
}
// Output:
// /p2p-circuit
}
func ExampleNewService_basic() {
// disable resources manager for test
os.Setenv("LIBP2P_RCMGR", "false")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
client, err := weshnet.NewService(weshnet.Opts{})
if err != nil {
panic(err)
}
defer client.Close()
ret, err := client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
if err != nil {
panic(err)
}
for _, listener := range ret.Listeners {
if listener == "/p2p-circuit" {
fmt.Println(listener)
}
}
// Output:
// /p2p-circuit
}
// FIXME: create examples that actually use groups and contacts
================================================
FILE: buf.gen.tag.yaml
================================================
version: v1
plugins:
- name: gotag
out: ./
opt: module=berty.tech/weshnet/v2
================================================
FILE: buf.gen.yaml
================================================
version: v2
plugins:
- local: protoc-gen-go
out: ./
opt: module=berty.tech/weshnet/v2
- local: protoc-gen-go-grpc
out: ./
opt: module=berty.tech/weshnet/v2
- local: protoc-gen-grpc-gateway
out: ./
opt:
- module=berty.tech/weshnet/v2
- generate_unbound_methods=true
================================================
FILE: connectedness_manager.go
================================================
package weshnet
import (
"context"
"sync"
peer "github.com/libp2p/go-libp2p/core/peer"
"berty.tech/weshnet/v2/internal/notify"
)
type ConnectednessType int
const (
ConnectednessTypeDisconnected ConnectednessType = iota
ConnectednessTypeReconnecting
ConnectednessTypeConnected
)
type ConnectednessUpdate struct {
Peer peer.ID
Status ConnectednessType
}
type PeersConnectedness map[peer.ID]ConnectednessType
type GroupStatus struct {
peers map[peer.ID]*PeerStatus
notify *notify.Notify
}
type PeerStatus struct {
groups map[string]*GroupStatus
status ConnectednessType
}
type ConnectednessManager struct {
peerState map[peer.ID]*PeerStatus
groupState map[string]*GroupStatus
muState sync.Mutex
}
func NewConnectednessManager() *ConnectednessManager {
return &ConnectednessManager{
peerState: make(map[peer.ID]*PeerStatus),
groupState: make(map[string]*GroupStatus),
}
}
// AssociatePeer associate a peer to a group
func (m *ConnectednessManager) AssociatePeer(group string, peer peer.ID) {
m.muState.Lock()
defer m.muState.Unlock()
sg := m.getGroupStatus(group)
sp := m.getPeerStatus(peer)
sg.notify.L.Lock()
if _, ok := sg.peers[peer]; !ok {
// we got a new peer, update and signal an update
sg.peers[peer] = sp
sp.groups[group] = sg
sg.notify.Broadcast()
}
sg.notify.L.Unlock()
}
// UpdateState update peer current connectedness state
func (m *ConnectednessManager) UpdateState(peer peer.ID, update ConnectednessType) {
m.muState.Lock()
defer m.muState.Unlock()
sp := m.getPeerStatus(peer)
if sp.status != update {
sp.status = update
// notify each group that need an update
for _, g := range sp.groups {
g.notify.Broadcast()
}
}
}
// WaitForConnectednessChange wait until the given `current` peers status differ from `local` peers state
func (m *ConnectednessManager) WaitForConnectednessChange(ctx context.Context, gkey string, current PeersConnectedness) ([]peer.ID, bool) {
m.muState.Lock()
sg := m.getGroupStatus(gkey)
m.muState.Unlock()
ok := true
sg.notify.L.Lock()
var updated []peer.ID
for ok {
// check if there are some diff between local state and the current state
if updated = m.updateStatus(sg, current); len(updated) > 0 {
break // we got some update, leave the loop
}
// wait until there is an update on this group or context expire
// unlock notify locker
ok = sg.notify.Wait(ctx)
}
sg.notify.L.Unlock()
return updated, ok
}
func (m *ConnectednessManager) getGroupStatus(gkey string) *GroupStatus {
s, ok := m.groupState[gkey]
if !ok {
s = &GroupStatus{
peers: make(map[peer.ID]*PeerStatus),
notify: notify.New(&sync.Mutex{}),
}
m.groupState[gkey] = s
}
return s
}
func (m *ConnectednessManager) getPeerStatus(peer peer.ID) *PeerStatus {
s, ok := m.peerState[peer]
if !ok {
s = &PeerStatus{
groups: make(map[string]*GroupStatus),
}
m.peerState[peer] = s
}
return s
}
func (m *ConnectednessManager) updateStatus(group *GroupStatus, current PeersConnectedness) []peer.ID {
m.muState.Lock()
updated := []peer.ID{}
for peer := range group.peers {
if ourPeer, ok := m.peerState[peer]; ok {
theirStatus, ok := current[peer]
if ok && ourPeer.status == theirStatus {
continue // we share the same state for that peer, skip
}
// update peer status
current[peer] = ourPeer.status
updated = append(updated, peer)
}
}
m.muState.Unlock()
return updated
}
================================================
FILE: consts.go
================================================
package weshnet
import (
"berty.tech/go-orbit-db/cache/cacheleveldown"
)
const (
NamespaceOrbitDBDatastore = "orbitdb_datastore"
NamespaceOrbitDBDirectory = "orbitdb"
NamespaceIPFSDatastore = "ipfs_datastore"
)
var InMemoryDirectory = cacheleveldown.InMemoryDirectory
================================================
FILE: contact_request_manager.go
================================================
package weshnet
import (
"bytes"
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"sync"
"time"
ipfscid "github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/internal/handshake"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/tyber"
)
const contactRequestV1 = "/wesh/contact_req/1.0.0"
type contactRequestsManager struct {
muManager sync.Mutex
ctx context.Context
cancel context.CancelFunc
announceCancel context.CancelFunc
lookupProcess map[string]context.CancelFunc
muLookupProcess sync.Mutex
logger *zap.Logger
enabled bool
ownRendezvousSeed []byte
accountPrivateKey crypto.PrivKey
ipfs ipfsutil.ExtendedCoreAPI
swiper *Swiper
metadataStore *MetadataStore
}
func newContactRequestsManager(s *Swiper, store *MetadataStore, ipfs ipfsutil.ExtendedCoreAPI, logger *zap.Logger) (*contactRequestsManager, error) {
accountPrivateKey, err := store.secretStore.GetAccountPrivateKey()
if err != nil {
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
cm := &contactRequestsManager{
lookupProcess: make(map[string]context.CancelFunc),
metadataStore: store,
ipfs: ipfs,
logger: logger.Named("req-mngr"),
accountPrivateKey: accountPrivateKey,
ctx: ctx,
cancel: cancel,
swiper: s,
}
go cm.metadataWatcher(ctx)
return cm, nil
}
func (c *contactRequestsManager) close() {
if c.isClosed() {
c.logger.Warn("contactRequestsManager already closed")
return
}
c.cancel()
c.muManager.Lock()
defer c.muManager.Unlock()
c.enabled = false
c.disableAnnounce()
c.ipfs.RemoveStreamHandler(contactRequestV1)
}
func (c *contactRequestsManager) isClosed() bool {
select {
case <-c.ctx.Done():
return true
default:
return false
}
}
func (c *contactRequestsManager) metadataWatcher(ctx context.Context) {
handlers := map[protocoltypes.EventType]func(context.Context, *protocoltypes.GroupMetadataEvent) error{
protocoltypes.EventType_EventTypeAccountContactRequestDisabled: c.metadataRequestDisabled,
protocoltypes.EventType_EventTypeAccountContactRequestEnabled: c.metadataRequestEnabled,
protocoltypes.EventType_EventTypeAccountContactRequestReferenceReset: c.metadataRequestReset,
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued: c.metadataRequestEnqueued,
// @FIXME: looks like we don't need those events
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingSent: c.metadataRequestSent,
protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived: c.metadataRequestReceived,
}
// subscribe to new event
sub, err := c.metadataStore.EventBus().Subscribe(new(*protocoltypes.GroupMetadataEvent),
eventbus.Name("weshnet/rqmngr/metadata-watcher"))
if err != nil {
c.logger.Warn("unable to subscribe to group metadata event", zap.Error(err))
return
}
// recreate previous contact request state
enabled, contact := c.metadataStore.GetIncomingContactRequestsStatus()
if contact != nil {
c.ownRendezvousSeed = contact.PublicRendezvousSeed
}
c.muManager.Lock()
if enabled {
if err := c.enableContactRequest(ctx); err != nil {
c.logger.Warn("unable to enable contact request", zap.Error(err))
}
}
c.muManager.Unlock()
// enqueue all contact with the `ToRequest` state
for _, contact := range c.metadataStore.ListContactsByStatus(protocoltypes.ContactState_ContactStateToRequest) {
if err := c.enqueueRequest(ctx, contact); err != nil {
c.logger.Warn("unable to enqueue contact request", logutil.PrivateBinary("pk", contact.Pk), zap.Error(err))
}
}
defer sub.Close()
for {
var evt any
select {
case evt = <-sub.Out():
case <-ctx.Done():
return
}
// handle new events
e := evt.(*protocoltypes.GroupMetadataEvent)
typ := e.GetMetadata().GetEventType()
hctx, _, endSection := tyber.Section(ctx, c.logger, fmt.Sprintf("handling event - %s", typ.String()))
c.muManager.Lock()
var err error
if handler, ok := handlers[typ]; ok {
if err = handler(hctx, e); err != nil {
c.logger.Error("metadata store event handler", zap.String("event", typ.String()), zap.Error(err))
}
}
c.muManager.Unlock()
endSection(err, "")
}
}
func (c *contactRequestsManager) metadataRequestDisabled(_ context.Context, _ *protocoltypes.GroupMetadataEvent) error {
if !c.enabled {
c.logger.Warn("contact request already disabled")
return nil
}
c.enabled = false
c.disableAnnounce()
c.ipfs.RemoveStreamHandler(contactRequestV1)
return nil
}
func (c *contactRequestsManager) metadataRequestEnabled(ctx context.Context, evt *protocoltypes.GroupMetadataEvent) error {
e := &protocoltypes.AccountContactRequestEnabled{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return c.enableContactRequest(ctx)
}
func (c *contactRequestsManager) enableContactRequest(ctx context.Context) error {
if c.enabled {
c.logger.Warn("contact request already enabled")
return nil
}
pkBytes, err := c.accountPrivateKey.GetPublic().Raw()
if err != nil {
return fmt.Errorf("unable to get raw pk: %w", err)
}
c.ipfs.SetStreamHandler(contactRequestV1, func(s network.Stream) {
ctx, _, endSection := tyber.Section(c.ctx, c.logger, "receiving incoming contact request")
if err := c.handleIncomingRequest(ctx, s); err != nil {
c.logger.Error("unable to handle incoming contact request", zap.Error(err))
}
endSection(err, "")
if err := s.Reset(); err != nil {
c.logger.Error("unable to reset stream", zap.Error(err))
}
})
c.enabled = true
tyber.LogStep(ctx, c.logger, "enabled contact request")
// announce on swiper if we already got seed
if c.ownRendezvousSeed != nil {
return c.enableAnnounce(ctx, c.ownRendezvousSeed, pkBytes)
}
c.logger.Warn("no seed registered, reset will be needed before announcing")
return nil
}
func (c *contactRequestsManager) metadataRequestReset(ctx context.Context, evt *protocoltypes.GroupMetadataEvent) error {
e := &protocoltypes.AccountContactRequestReferenceReset{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
accPK, err := c.accountPrivateKey.GetPublic().Raw()
if err != nil {
return fmt.Errorf("unable to get raw pk: %w", err)
}
switch {
case e.PublicRendezvousSeed == nil:
return fmt.Errorf("unable to reset with an empty seed")
case bytes.Equal(e.PublicRendezvousSeed, c.ownRendezvousSeed):
return fmt.Errorf("unable to reset twice with the same seed")
}
// updating rendezvous seed
tyber.LogStep(ctx, c.logger, "update rendezvous seed")
c.ownRendezvousSeed = e.PublicRendezvousSeed
// if contact request manager is disable don't run announce
if !c.enabled {
return nil
}
return c.enableAnnounce(ctx, c.ownRendezvousSeed, accPK)
}
func (c *contactRequestsManager) metadataRequestEnqueued(ctx context.Context, evt *protocoltypes.GroupMetadataEvent) error {
ctx = tyber.ContextWithConstantTraceID(ctx, "msgrcvd-"+cidBytesString(evt.EventContext.Id))
traceName := fmt.Sprintf("Received %s on group %s",
strings.TrimPrefix(evt.Metadata.EventType.String(), "EventType"), base64.RawURLEncoding.EncodeToString(evt.EventContext.GroupPk))
c.logger.Debug(traceName, tyber.FormatStepLogFields(ctx, []tyber.Detail{}, tyber.UpdateTraceName(traceName))...)
e := &protocoltypes.AccountContactRequestOutgoingEnqueued{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
return tyber.LogError(ctx, c.logger, "Failed to unmarshal event", err)
}
// enqueue contact request
if err := c.enqueueRequest(ctx, e.Contact); err != nil {
return tyber.LogError(ctx, c.logger, "Failed to enqueue request", err)
}
return nil
}
func (c *contactRequestsManager) metadataRequestSent(_ context.Context, evt *protocoltypes.GroupMetadataEvent) error {
e := &protocoltypes.AccountContactRequestOutgoingSent{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
// another device may have successfully sent contact request, try to cancel
// lookup if needed
c.cancelContactLookup(e.ContactPk)
return nil
}
func (c *contactRequestsManager) metadataRequestReceived(_ context.Context, evt *protocoltypes.GroupMetadataEvent) error {
e := &protocoltypes.AccountContactRequestIncomingReceived{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
// another device may have successfully sent contact request, try to cancel
// lookup if needed
c.cancelContactLookup(e.ContactPk)
return nil
}
func (c *contactRequestsManager) registerContactLookup(ctx context.Context, contactPK []byte) context.Context {
c.muLookupProcess.Lock()
key := hex.EncodeToString(contactPK)
// make sure to only have one process for this pk running
ctx, cancel := context.WithCancel(ctx)
if cancelProvious, ok := c.lookupProcess[key]; ok {
cancelProvious() // cancel previous lookup if needed
}
c.lookupProcess[key] = cancel
c.muLookupProcess.Unlock()
return ctx
}
func (c *contactRequestsManager) cancelContactLookup(contactPK []byte) {
c.muLookupProcess.Lock()
key := hex.EncodeToString(contactPK)
// cancel current lookup if needed
if cancel, ok := c.lookupProcess[key]; ok {
cancel()
delete(c.lookupProcess, key)
}
c.muLookupProcess.Unlock()
}
func (c *contactRequestsManager) enableAnnounce(ctx context.Context, seed, accPK []byte) error {
if seed == nil {
return fmt.Errorf("announcing with empty seed")
}
if c.announceCancel != nil { // is already enable
tyber.LogStep(ctx, c.logger, "canceling previous announce")
c.announceCancel()
}
ctx, c.announceCancel = context.WithCancel(ctx)
c.enabled = true
tyber.LogStep(ctx, c.logger, "announcing on swipper")
// start announcing on swiper, this method should take care ton announce as
// many time as needed
c.swiper.Announce(ctx, accPK, seed)
return nil
}
func (c *contactRequestsManager) disableAnnounce() {
if c.announceCancel != nil {
c.announceCancel()
c.announceCancel = nil
}
}
func (c *contactRequestsManager) enqueueRequest(ctx context.Context, to *protocoltypes.ShareableContact) (err error) {
ctx, _, endSection := tyber.Section(ctx, c.logger, "Enqueue contact request: "+base64.RawURLEncoding.EncodeToString(to.Pk))
otherPK, err := crypto.UnmarshalEd25519PublicKey(to.Pk)
if err != nil {
return err
}
if ok := c.metadataStore.checkContactStatus(otherPK, protocoltypes.ContactState_ContactStateAdded); ok {
err = fmt.Errorf("contact already added")
endSection(err, "")
// contact already added,
return err
}
// register lookup process
ctx = c.registerContactLookup(ctx, to.Pk)
// start watching topic on swiper, this method should take care of calling
// `FindPeer` as many times as needed
cpeers := c.swiper.WatchTopic(ctx, to.Pk, to.PublicRendezvousSeed)
go func() {
var err error
for peer := range cpeers {
// get our sharable contact to send to other contact
if err = c.SendContactRequest(ctx, to, otherPK, peer); err != nil {
c.logger.Warn("unable to send contact request", zap.Error(err))
} else {
// successfully send contact request, leave the loop and cancel lookup
break
}
// wait one second to avoid infinity loop on send contact request
// ex: when we dont have any network, send request can fail instantly
time.Sleep(time.Second)
}
// cancel lookup process
c.cancelContactLookup(to.Pk)
endSection(err, "")
}()
return nil
}
// SendContactRequest try to perform contact request with the given remote peer
func (c *contactRequestsManager) SendContactRequest(ctx context.Context, to *protocoltypes.ShareableContact, otherPK crypto.PubKey, peer peer.AddrInfo) (err error) {
ctx, _, endSection := tyber.Section(ctx, c.logger, "sending contact request")
defer func() {
endSection(err, "")
}()
_, own := c.metadataStore.GetIncomingContactRequestsStatus()
if own == nil {
err = fmt.Errorf("unable to retrieve own contact information")
return err
}
// get own metadata for contact
ownMetadata, err := c.metadataStore.GetRequestOwnMetadataForContact(to.Pk)
if err != nil {
c.logger.Warn("unable to get own metadata for contact", zap.Error(err))
ownMetadata = nil
}
own.Metadata = ownMetadata
// make sure to have connection with the remote peer
if err := c.ipfs.Swarm().Connect(ctx, peer); err != nil {
return fmt.Errorf("unable to connect: %w", err)
}
// create a new stream with the remote peer
stream, err := c.ipfs.NewStream(network.WithAllowLimitedConn(ctx, "req_mngr"), peer.ID, contactRequestV1)
if err != nil {
return fmt.Errorf("unable to open stream: %w", err)
}
defer func() {
if err := stream.Close(); err != nil {
c.logger.Warn("error while closing stream with other peer", zap.Error(err))
}
}()
reader := protoio.NewDelimitedReader(stream, 2048)
writer := protoio.NewDelimitedWriter(stream)
c.logger.Debug("performing handshake")
tyber.LogStep(ctx, c.logger, "performing handshake")
if err := handshake.RequestUsingReaderWriter(ctx, c.logger, reader, writer, c.accountPrivateKey, otherPK); err != nil {
return fmt.Errorf("an error occurred during handshake: %w", err)
}
tyber.LogStep(ctx, c.logger, "sending own contact")
// send own contact information
if err := writer.WriteMsg(own); err != nil {
return fmt.Errorf("an error occurred while sending own contact information: %w", err)
}
tyber.LogStep(ctx, c.logger, "mark contact request has sent")
// mark this contact request as sent
if _, err := c.metadataStore.ContactRequestOutgoingSent(ctx, otherPK); err != nil {
return fmt.Errorf("an error occurred while marking contact request as sent: %w", err)
}
return nil
}
func (c *contactRequestsManager) handleIncomingRequest(ctx context.Context, stream network.Stream) (err error) {
reader := protoio.NewDelimitedReader(stream, 2048)
writer := protoio.NewDelimitedWriter(stream)
tyber.LogStep(ctx, c.logger, "responding to handshake")
otherPK, err := handshake.ResponseUsingReaderWriter(ctx, c.logger, reader, writer, c.accountPrivateKey)
if err != nil {
return fmt.Errorf("handshake failed: %w", err)
}
otherPKBytes, err := otherPK.Raw()
if err != nil {
return fmt.Errorf("failed to marshal contact public key: %w", err)
}
contact := &protocoltypes.ShareableContact{}
tyber.LogStep(ctx, c.logger, "checking remote contact information")
// read remote contact information
if err := reader.ReadMsg(contact); err != nil {
return fmt.Errorf("failed to read contact information: %w", err)
}
// validate contact pk
if !bytes.Equal(otherPKBytes, contact.Pk) {
return fmt.Errorf("contact information does not match handshake data")
}
// check contact information format
if err := contact.CheckFormat(protocoltypes.ShareableContactOptionsAllowMissingRDVSeed); err != nil {
return fmt.Errorf("invalid contact information format: %w", err)
}
tyber.LogStep(ctx, c.logger, "marking contact request has received")
// mark contact request as received
_, err = c.metadataStore.ContactRequestIncomingReceived(ctx, &protocoltypes.ShareableContact{
Pk: otherPKBytes,
PublicRendezvousSeed: contact.PublicRendezvousSeed,
Metadata: contact.Metadata,
})
if err != nil {
return fmt.Errorf("invalid contact information format: %w", err)
}
return nil
}
func cidBytesString(bytes []byte) string {
cid, err := ipfscid.Cast(bytes)
if err != nil {
return "error"
}
return cid.String()
}
================================================
FILE: contact_request_manager_test.go
================================================
package weshnet
import (
"context"
"io"
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestContactRequestFlow(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
opts := TestingOpts{
Mocknet: mocknet.New(),
Logger: logger,
}
metadataSender1 := []byte("sender_1")
pts, cleanup := NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
_, err := pts[0].Client.ContactRequestEnable(ctx, &protocoltypes.ContactRequestEnable_Request{})
require.NoError(t, err)
_, err = pts[1].Client.ContactRequestEnable(ctx, &protocoltypes.ContactRequestEnable_Request{})
require.NoError(t, err)
config0, err := pts[0].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config0)
config1, err := pts[1].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config1)
ref0, err := pts[0].Client.ContactRequestResetReference(ctx, &protocoltypes.ContactRequestResetReference_Request{})
require.NoError(t, err)
require.NotNil(t, ref0)
ref1, err := pts[1].Client.ContactRequestResetReference(ctx, &protocoltypes.ContactRequestResetReference_Request{})
require.NoError(t, err)
require.NotNil(t, ref1)
subCtx, subCancel := context.WithCancel(ctx)
defer subCancel()
subMeta0, err := pts[0].Client.GroupMetadataList(subCtx, &protocoltypes.GroupMetadataList_Request{
GroupPk: config0.AccountGroupPk,
})
require.NoError(t, err)
found := false
_, err = pts[1].Client.ContactRequestSend(ctx, &protocoltypes.ContactRequestSend_Request{
Contact: &protocoltypes.ShareableContact{
Pk: config0.AccountPk,
PublicRendezvousSeed: ref0.PublicRendezvousSeed,
},
OwnMetadata: metadataSender1,
})
require.NoError(t, err)
for {
evt, err := subMeta0.Recv()
if err == io.EOF || subMeta0.Context().Err() != nil {
break
}
require.NoError(t, err)
if evt == nil || evt.Metadata.EventType != protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived {
continue
}
req := &protocoltypes.AccountContactRequestIncomingReceived{}
err = proto.Unmarshal(evt.Event, req)
require.NoError(t, err)
require.Equal(t, config1.AccountPk, req.ContactPk)
require.Equal(t, metadataSender1, req.ContactMetadata)
found = true
subCancel()
}
require.True(t, found)
_, err = pts[1].Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: config0.AccountPk,
})
require.Error(t, err)
_, err = pts[1].Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: config1.AccountPk,
})
require.Error(t, err)
_, err = pts[0].Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: config0.AccountPk,
})
require.Error(t, err)
_, err = pts[0].Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: config1.AccountPk,
})
require.NoError(t, err)
grpInfo, err := pts[0].Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
ContactPk: config1.AccountPk,
})
require.NoError(t, err)
_, err = pts[0].Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: grpInfo.Group.PublicKey,
})
require.NoError(t, err)
_, err = pts[1].Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: grpInfo.Group.PublicKey,
})
require.NoError(t, err)
}
func TestContactRequestFlowWithoutIncoming(t *testing.T) {
t.Skip("KUBO: this test timeout, disable it for now")
testutil.FilterSpeed(t, testutil.Slow)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
opts := TestingOpts{
Mocknet: mn,
Logger: logger,
}
metadataSender1 := []byte("sender_1")
pts, cleanup := NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
_, err := pts[0].Client.ContactRequestEnable(ctx, &protocoltypes.ContactRequestEnable_Request{})
require.NoError(t, err)
config0, err := pts[0].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config0)
config1, err := pts[1].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config1)
ref0, err := pts[0].Client.ContactRequestResetReference(ctx, &protocoltypes.ContactRequestResetReference_Request{})
require.NoError(t, err)
require.NotNil(t, ref0)
subCtx, subCancel := context.WithCancel(ctx)
defer subCancel()
subMeta0, err := pts[0].Client.GroupMetadataList(subCtx, &protocoltypes.GroupMetadataList_Request{
GroupPk: config0.AccountGroupPk,
})
require.NoError(t, err)
found := false
_, err = pts[1].Client.ContactRequestSend(ctx, &protocoltypes.ContactRequestSend_Request{
Contact: &protocoltypes.ShareableContact{
Pk: config0.AccountPk,
PublicRendezvousSeed: ref0.PublicRendezvousSeed,
},
OwnMetadata: metadataSender1,
})
require.NoError(t, err)
for {
evt, err := subMeta0.Recv()
if err != nil {
assert.NoError(t, err)
break
}
require.NoError(t, err)
if evt == nil || evt.Metadata.EventType != protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived {
continue
}
req := &protocoltypes.AccountContactRequestIncomingReceived{}
err = proto.Unmarshal(evt.Event, req)
require.NoError(t, err)
require.Equal(t, config1.AccountPk, req.ContactPk)
require.Equal(t, metadataSender1, req.ContactMetadata)
found = true
subCancel()
}
require.True(t, found)
_, err = pts[0].Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: config1.AccountPk,
})
require.NoError(t, err)
_, err = pts[0].Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
ContactPk: config1.AccountPk,
})
require.NoError(t, err)
}
================================================
FILE: deactivate_test.go
================================================
package weshnet_test
import (
"context"
"testing"
"time"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
"berty.tech/weshnet/v2/pkg/tinder"
)
func TestReactivateAccountGroup(t *testing.T) {
testutil.FilterStability(t, testutil.Flappy)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
msrv := tinder.NewMockDriverServer()
// Setup 3 nodes
dsA := dsync.MutexWrap(ds.NewMapDatastore())
nodeA, closeNodeA := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{
Logger: logger.Named("nodeA"),
Mocknet: mn,
DiscoveryServer: msrv,
}, dsA)
defer closeNodeA()
dsB := dsync.MutexWrap(ds.NewMapDatastore())
nodeB, closeNodeB := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{
Logger: logger.Named("nodeB"),
Mocknet: mn,
DiscoveryServer: msrv,
}, dsB)
defer closeNodeB()
dsC := dsync.MutexWrap(ds.NewMapDatastore())
nodeC, closeNodeC := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{
Logger: logger.Named("nodeC"),
Mocknet: mn,
DiscoveryServer: msrv,
}, dsC)
defer closeNodeC()
// make connections
err := mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
// test communication between nodeA and nodeB
nodes := []*weshnet.TestingProtocol{nodeA, nodeB}
addAsContact(ctx, t, nodes, nodes)
sendMessageToContact(ctx, t, []string{"pre-deactivate nodeA-nodeB"}, nodes)
// reactivate nodeA account group
nodeACfg, err := nodeA.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, nodeACfg)
_, err = nodeA.Client.DeactivateGroup(ctx, &protocoltypes.DeactivateGroup_Request{
GroupPk: nodeACfg.AccountGroupPk,
})
require.NoError(t, err)
_, err = nodeA.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: nodeACfg.AccountGroupPk,
})
require.NoError(t, err)
// test communication between nodeA and nodeC
nodes = []*weshnet.TestingProtocol{nodeA, nodeC}
addAsContact(ctx, t, nodes, nodes)
sendMessageToContact(ctx, t, []string{"post reactivate nodeA-nodeC"}, nodes)
}
func TestRaceReactivateAccountGroup(t *testing.T) {
testutil.FilterStability(t, testutil.Flappy)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
msrv := tinder.NewMockDriverServer()
// Setup 2 nodes
dsA := dsync.MutexWrap(ds.NewMapDatastore())
nodeA, closeNodeA := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{
Logger: logger.Named("nodeA"),
Mocknet: mn,
DiscoveryServer: msrv,
}, dsA)
defer closeNodeA()
dsB := dsync.MutexWrap(ds.NewMapDatastore())
nodeB, closeNodeB := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{
Logger: logger.Named("nodeB"),
Mocknet: mn,
DiscoveryServer: msrv,
}, dsB)
defer closeNodeB()
// make connections
err := mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
// reactivate nodeA account group
nodeACfg, err := nodeA.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, nodeACfg)
deactivateFunc := func() {
t.Log("DeactivateGroup")
_, err := nodeA.Client.DeactivateGroup(ctx, &protocoltypes.DeactivateGroup_Request{
GroupPk: nodeACfg.AccountGroupPk,
})
require.NoError(t, err)
}
activateFunc := func() {
t.Log("ActivateGroup")
_, err := nodeA.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: nodeACfg.AccountGroupPk,
})
require.NoError(t, err)
}
go deactivateFunc()
time.Sleep(1 * time.Millisecond)
go activateFunc()
// test communication between nodeA and nodeB
time.Sleep(3 * time.Second)
nodes := []*weshnet.TestingProtocol{nodeA, nodeB}
t.Log("addAsContact")
addAsContact(ctx, t, nodes, nodes)
t.Log("sendMessageToContact")
sendMessageToContact(ctx, t, []string{"nodeA-nodeB"}, nodes)
}
func TestReactivateContactGroup(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
opts := weshnet.TestingOpts{
Mocknet: mocknet.New(),
Logger: logger,
ConnectFunc: weshnet.ConnectAll,
}
nodes, cleanup := weshnet.NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
addAsContact(ctx, t, nodes, nodes)
// send messages before deactivating
sendMessageToContact(ctx, t, []string{"pre-deactivate"}, nodes)
// get contact group
contactGroup := getContactGroup(ctx, t, nodes[0], nodes[1])
// deactivate contact group
_, err := nodes[0].Client.DeactivateGroup(ctx, &protocoltypes.DeactivateGroup_Request{
GroupPk: contactGroup.Group.PublicKey,
})
require.NoError(t, err)
// reactivate group
_, err = nodes[0].Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: contactGroup.Group.PublicKey,
})
require.NoError(t, err)
// send message after reactivating
sendMessageToContact(ctx, t, []string{"post-reactivate"}, nodes)
}
func TestRaceReactivateContactGroup(t *testing.T) {
testutil.FilterStability(t, testutil.Flappy)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
opts := weshnet.TestingOpts{
Mocknet: mocknet.New(),
Logger: logger,
ConnectFunc: weshnet.ConnectAll,
}
nodes, cleanup := weshnet.NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
t.Log("addAsContact")
addAsContact(ctx, t, nodes, nodes)
// send messages before deactivating
t.Log("sendMessageToContact")
sendMessageToContact(ctx, t, []string{"pre-deactivate"}, nodes)
// get contact group
contactGroup := getContactGroup(ctx, t, nodes[0], nodes[1])
// deactivate contact group
deactivateFunc := func() {
t.Log("DeactivateGroup")
_, err := nodes[0].Client.DeactivateGroup(ctx, &protocoltypes.DeactivateGroup_Request{
GroupPk: contactGroup.Group.PublicKey,
})
require.NoError(t, err)
}
// reactivate group
activateFunc := func() {
t.Log("ActivateGroup")
_, err := nodes[0].Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: contactGroup.Group.PublicKey,
})
require.NoError(t, err)
}
go deactivateFunc()
time.Sleep(1 * time.Millisecond)
go activateFunc()
// send message after reactivating
time.Sleep(5 * time.Second)
t.Log("sendMessageToContact")
sendMessageToContact(ctx, t, []string{"post-reactivate"}, nodes)
}
func TestReactivateMultimemberGroup(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
opts := weshnet.TestingOpts{
Mocknet: mocknet.New(),
Logger: logger,
ConnectFunc: weshnet.ConnectAll,
}
nodes, cleanup := weshnet.NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, 2)
defer cleanup()
// Create MultiMember Group
group := weshnet.CreateMultiMemberGroupInstance(ctx, t, nodes[0], nodes[1])
// Send message before deactivation
sendMessageOnGroup(ctx, t, nodes, nodes, group.PublicKey, []string{"pre-deactivate"})
// deactivate multimember group
_, err := nodes[0].Client.DeactivateGroup(ctx, &protocoltypes.DeactivateGroup_Request{
GroupPk: group.PublicKey,
})
require.NoError(t, err)
// reactivate group
_, err = nodes[0].Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: group.PublicKey,
})
require.NoError(t, err)
// Send message after reactivation
sendMessageOnGroup(ctx, t, nodes, nodes, group.PublicKey, []string{"post-deactivate"})
}
================================================
FILE: doc.go
================================================
// Package weshnet contains code for integrating the Berty protocol in your project.
//
// See https://berty.tech/protocol for more information.
package weshnet
================================================
FILE: docs/CONTRIBUTING.md
================================================
# Contributing
Please visit https://github.com/berty/community/blob/master/CONTRIBUTING.md
================================================
FILE: docs/Makefile
================================================
##
## Code gen
##
VERSION ?= `go run github.com/mdomke/git-semver/v5`
all: generate
gen_src := $(wildcard ../api/*.proto) $(wildcard ../api/*.yaml) Makefile
gen_sum := gen.sum
generate: gen.sum
$(gen_sum): $(gen_src)
@shasum $(gen_src) | sort -k 2 > $(gen_sum).tmp
@diff -q $(gen_sum).tmp $(gen_sum) || ( \
set -xe; \
(set -e; GO111MODULE=on go mod download); \
docker run \
--user=`id -u` \
--volume="$(PWD)/..:/go/src/berty.tech/berty" \
--volume="`go env GOPATH`/pkg/mod:/go/pkg/mod" \
--workdir="/go/src/berty.tech/berty/docs" \
--entrypoint="sh" \
--rm \
bertytech/buf:5 \
-xec 'make generate_local' \
)
.PHONY: generate
protoc_opts := -I ../api:`go list -m -mod=mod -f {{.Dir}} github.com/grpc-ecosystem/grpc-gateway`/third_party/googleapis
generate_local:
mkdir -p protocol
buf generate --template ./buf-doc.gen.yaml ../api/protocol/protocoltypes.proto -o protocol
@# replace multiple empty lines with one
cat protocol/api.md.tmp | sed '/^$$/N;/^\n$$/D' > protocol/api.md
rm -f */*.md.tmp
shasum $(gen_src) | sort -k 2 > $(gen_sum).tmp
mv $(gen_sum).tmp $(gen_sum)
mv protocol/api.md apis/protocoltypes.md
mv protocol/protocoltypes.swagger.json apis/
.PHONY: generate_local
regenerate: gen.clean generate
.PHONY: regenerate
gen.clean:
rm -f gen.sum $(wildcard */*.md.tmp) $(wildcard */*.swagger.json)
.PHONY: gen.clean
openapi.prepare: gen.sum
mkdir -p .tmp/openapi
cat ./apis/protocoltypes.swagger.json | jq '.info.version="'$(VERSION)'"' > .tmp/openapi/protocoltypes.swagger.json
cat .tmp/openapi/*.json | jq .info.version
.PHONY: openapi.prepare
BUMP_TOKEN ?=
bump.validate: openapi.prepare
@# gem install bump-cli
bump validate --token=$(BUMP_TOKEN) --doc=6eb1bb1e-c65d-4b73-a8c4-0e545742f6db .tmp/openapi/protocoltypes.swagger.json
.PHONY: bump.validate
bump.deploy: bump.validate
@# gem install bump-cli
bump deploy --token=$(BUMP_TOKEN) --doc=6eb1bb1e-c65d-4b73-a8c4-0e545742f6db .tmp/openapi/protocoltypes.swagger.json
.PHONY: bump.deploy
openapi.clean:
rm -rf .tmp/openapi
.PHONY: openapi.clean
clean: gen.clean openapi.clean
.PHONY: clean
tidy:
.PHONY: tidy
================================================
FILE: docs/apis/protocoltypes.md
================================================
# Protocol Documentation
## Table of Contents
- [protocoltypes.proto](#protocoltypes-proto)
- [Account](#weshnet-protocol-v1-Account)
- [AccountContactBlocked](#weshnet-protocol-v1-AccountContactBlocked)
- [AccountContactRequestDisabled](#weshnet-protocol-v1-AccountContactRequestDisabled)
- [AccountContactRequestEnabled](#weshnet-protocol-v1-AccountContactRequestEnabled)
- [AccountContactRequestIncomingAccepted](#weshnet-protocol-v1-AccountContactRequestIncomingAccepted)
- [AccountContactRequestIncomingDiscarded](#weshnet-protocol-v1-AccountContactRequestIncomingDiscarded)
- [AccountContactRequestIncomingReceived](#weshnet-protocol-v1-AccountContactRequestIncomingReceived)
- [AccountContactRequestOutgoingEnqueued](#weshnet-protocol-v1-AccountContactRequestOutgoingEnqueued)
- [AccountContactRequestOutgoingSent](#weshnet-protocol-v1-AccountContactRequestOutgoingSent)
- [AccountContactRequestReferenceReset](#weshnet-protocol-v1-AccountContactRequestReferenceReset)
- [AccountContactUnblocked](#weshnet-protocol-v1-AccountContactUnblocked)
- [AccountGroupJoined](#weshnet-protocol-v1-AccountGroupJoined)
- [AccountGroupLeft](#weshnet-protocol-v1-AccountGroupLeft)
- [AccountVerifiedCredentialRegistered](#weshnet-protocol-v1-AccountVerifiedCredentialRegistered)
- [ActivateGroup](#weshnet-protocol-v1-ActivateGroup)
- [ActivateGroup.Reply](#weshnet-protocol-v1-ActivateGroup-Reply)
- [ActivateGroup.Request](#weshnet-protocol-v1-ActivateGroup-Request)
- [AppMessageSend](#weshnet-protocol-v1-AppMessageSend)
- [AppMessageSend.Reply](#weshnet-protocol-v1-AppMessageSend-Reply)
- [AppMessageSend.Request](#weshnet-protocol-v1-AppMessageSend-Request)
- [AppMetadataSend](#weshnet-protocol-v1-AppMetadataSend)
- [AppMetadataSend.Reply](#weshnet-protocol-v1-AppMetadataSend-Reply)
- [AppMetadataSend.Request](#weshnet-protocol-v1-AppMetadataSend-Request)
- [ContactAliasKeyAdded](#weshnet-protocol-v1-ContactAliasKeyAdded)
- [ContactAliasKeySend](#weshnet-protocol-v1-ContactAliasKeySend)
- [ContactAliasKeySend.Reply](#weshnet-protocol-v1-ContactAliasKeySend-Reply)
- [ContactAliasKeySend.Request](#weshnet-protocol-v1-ContactAliasKeySend-Request)
- [ContactBlock](#weshnet-protocol-v1-ContactBlock)
- [ContactBlock.Reply](#weshnet-protocol-v1-ContactBlock-Reply)
- [ContactBlock.Request](#weshnet-protocol-v1-ContactBlock-Request)
- [ContactRequestAccept](#weshnet-protocol-v1-ContactRequestAccept)
- [ContactRequestAccept.Reply](#weshnet-protocol-v1-ContactRequestAccept-Reply)
- [ContactRequestAccept.Request](#weshnet-protocol-v1-ContactRequestAccept-Request)
- [ContactRequestDisable](#weshnet-protocol-v1-ContactRequestDisable)
- [ContactRequestDisable.Reply](#weshnet-protocol-v1-ContactRequestDisable-Reply)
- [ContactRequestDisable.Request](#weshnet-protocol-v1-ContactRequestDisable-Request)
- [ContactRequestDiscard](#weshnet-protocol-v1-ContactRequestDiscard)
- [ContactRequestDiscard.Reply](#weshnet-protocol-v1-ContactRequestDiscard-Reply)
- [ContactRequestDiscard.Request](#weshnet-protocol-v1-ContactRequestDiscard-Request)
- [ContactRequestEnable](#weshnet-protocol-v1-ContactRequestEnable)
- [ContactRequestEnable.Reply](#weshnet-protocol-v1-ContactRequestEnable-Reply)
- [ContactRequestEnable.Request](#weshnet-protocol-v1-ContactRequestEnable-Request)
- [ContactRequestReference](#weshnet-protocol-v1-ContactRequestReference)
- [ContactRequestReference.Reply](#weshnet-protocol-v1-ContactRequestReference-Reply)
- [ContactRequestReference.Request](#weshnet-protocol-v1-ContactRequestReference-Request)
- [ContactRequestResetReference](#weshnet-protocol-v1-ContactRequestResetReference)
- [ContactRequestResetReference.Reply](#weshnet-protocol-v1-ContactRequestResetReference-Reply)
- [ContactRequestResetReference.Request](#weshnet-protocol-v1-ContactRequestResetReference-Request)
- [ContactRequestSend](#weshnet-protocol-v1-ContactRequestSend)
- [ContactRequestSend.Reply](#weshnet-protocol-v1-ContactRequestSend-Reply)
- [ContactRequestSend.Request](#weshnet-protocol-v1-ContactRequestSend-Request)
- [ContactUnblock](#weshnet-protocol-v1-ContactUnblock)
- [ContactUnblock.Reply](#weshnet-protocol-v1-ContactUnblock-Reply)
- [ContactUnblock.Request](#weshnet-protocol-v1-ContactUnblock-Request)
- [CredentialVerificationServiceCompleteFlow](#weshnet-protocol-v1-CredentialVerificationServiceCompleteFlow)
- [CredentialVerificationServiceCompleteFlow.Reply](#weshnet-protocol-v1-CredentialVerificationServiceCompleteFlow-Reply)
- [CredentialVerificationServiceCompleteFlow.Request](#weshnet-protocol-v1-CredentialVerificationServiceCompleteFlow-Request)
- [CredentialVerificationServiceInitFlow](#weshnet-protocol-v1-CredentialVerificationServiceInitFlow)
- [CredentialVerificationServiceInitFlow.Reply](#weshnet-protocol-v1-CredentialVerificationServiceInitFlow-Reply)
- [CredentialVerificationServiceInitFlow.Request](#weshnet-protocol-v1-CredentialVerificationServiceInitFlow-Request)
- [DeactivateGroup](#weshnet-protocol-v1-DeactivateGroup)
- [DeactivateGroup.Reply](#weshnet-protocol-v1-DeactivateGroup-Reply)
- [DeactivateGroup.Request](#weshnet-protocol-v1-DeactivateGroup-Request)
- [DebugGroup](#weshnet-protocol-v1-DebugGroup)
- [DebugGroup.Reply](#weshnet-protocol-v1-DebugGroup-Reply)
- [DebugGroup.Request](#weshnet-protocol-v1-DebugGroup-Request)
- [DebugInspectGroupStore](#weshnet-protocol-v1-DebugInspectGroupStore)
- [DebugInspectGroupStore.Reply](#weshnet-protocol-v1-DebugInspectGroupStore-Reply)
- [DebugInspectGroupStore.Request](#weshnet-protocol-v1-DebugInspectGroupStore-Request)
- [DebugListGroups](#weshnet-protocol-v1-DebugListGroups)
- [DebugListGroups.Reply](#weshnet-protocol-v1-DebugListGroups-Reply)
- [DebugListGroups.Request](#weshnet-protocol-v1-DebugListGroups-Request)
- [DecodeContact](#weshnet-protocol-v1-DecodeContact)
- [DecodeContact.Reply](#weshnet-protocol-v1-DecodeContact-Reply)
- [DecodeContact.Request](#weshnet-protocol-v1-DecodeContact-Request)
- [DeviceChainKey](#weshnet-protocol-v1-DeviceChainKey)
- [EncryptedMessage](#weshnet-protocol-v1-EncryptedMessage)
- [EventContext](#weshnet-protocol-v1-EventContext)
- [FirstLastCounters](#weshnet-protocol-v1-FirstLastCounters)
- [Group](#weshnet-protocol-v1-Group)
- [GroupAddAdditionalRendezvousSeed](#weshnet-protocol-v1-GroupAddAdditionalRendezvousSeed)
- [GroupDeviceChainKeyAdded](#weshnet-protocol-v1-GroupDeviceChainKeyAdded)
- [GroupDeviceStatus](#weshnet-protocol-v1-GroupDeviceStatus)
- [GroupDeviceStatus.Reply](#weshnet-protocol-v1-GroupDeviceStatus-Reply)
- [GroupDeviceStatus.Reply.PeerConnected](#weshnet-protocol-v1-GroupDeviceStatus-Reply-PeerConnected)
- [GroupDeviceStatus.Reply.PeerDisconnected](#weshnet-protocol-v1-GroupDeviceStatus-Reply-PeerDisconnected)
- [GroupDeviceStatus.Reply.PeerReconnecting](#weshnet-protocol-v1-GroupDeviceStatus-Reply-PeerReconnecting)
- [GroupDeviceStatus.Request](#weshnet-protocol-v1-GroupDeviceStatus-Request)
- [GroupEnvelope](#weshnet-protocol-v1-GroupEnvelope)
- [GroupHeadsExport](#weshnet-protocol-v1-GroupHeadsExport)
- [GroupInfo](#weshnet-protocol-v1-GroupInfo)
- [GroupInfo.Reply](#weshnet-protocol-v1-GroupInfo-Reply)
- [GroupInfo.Request](#weshnet-protocol-v1-GroupInfo-Request)
- [GroupMemberDeviceAdded](#weshnet-protocol-v1-GroupMemberDeviceAdded)
- [GroupMessageEvent](#weshnet-protocol-v1-GroupMessageEvent)
- [GroupMessageList](#weshnet-protocol-v1-GroupMessageList)
- [GroupMessageList.Request](#weshnet-protocol-v1-GroupMessageList-Request)
- [GroupMetadata](#weshnet-protocol-v1-GroupMetadata)
- [GroupMetadataEvent](#weshnet-protocol-v1-GroupMetadataEvent)
- [GroupMetadataList](#weshnet-protocol-v1-GroupMetadataList)
- [GroupMetadataList.Request](#weshnet-protocol-v1-GroupMetadataList-Request)
- [GroupMetadataPayloadSent](#weshnet-protocol-v1-GroupMetadataPayloadSent)
- [GroupRemoveAdditionalRendezvousSeed](#weshnet-protocol-v1-GroupRemoveAdditionalRendezvousSeed)
- [GroupReplicating](#weshnet-protocol-v1-GroupReplicating)
- [MessageEnvelope](#weshnet-protocol-v1-MessageEnvelope)
- [MessageHeaders](#weshnet-protocol-v1-MessageHeaders)
- [MessageHeaders.MetadataEntry](#weshnet-protocol-v1-MessageHeaders-MetadataEntry)
- [MultiMemberGroupAdminRoleGrant](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGrant)
- [MultiMemberGroupAdminRoleGrant.Reply](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGrant-Reply)
- [MultiMemberGroupAdminRoleGrant.Request](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGrant-Request)
- [MultiMemberGroupAdminRoleGranted](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGranted)
- [MultiMemberGroupAliasResolverAdded](#weshnet-protocol-v1-MultiMemberGroupAliasResolverAdded)
- [MultiMemberGroupAliasResolverDisclose](#weshnet-protocol-v1-MultiMemberGroupAliasResolverDisclose)
- [MultiMemberGroupAliasResolverDisclose.Reply](#weshnet-protocol-v1-MultiMemberGroupAliasResolverDisclose-Reply)
- [MultiMemberGroupAliasResolverDisclose.Request](#weshnet-protocol-v1-MultiMemberGroupAliasResolverDisclose-Request)
- [MultiMemberGroupCreate](#weshnet-protocol-v1-MultiMemberGroupCreate)
- [MultiMemberGroupCreate.Reply](#weshnet-protocol-v1-MultiMemberGroupCreate-Reply)
- [MultiMemberGroupCreate.Request](#weshnet-protocol-v1-MultiMemberGroupCreate-Request)
- [MultiMemberGroupInitialMemberAnnounced](#weshnet-protocol-v1-MultiMemberGroupInitialMemberAnnounced)
- [MultiMemberGroupInvitationCreate](#weshnet-protocol-v1-MultiMemberGroupInvitationCreate)
- [MultiMemberGroupInvitationCreate.Reply](#weshnet-protocol-v1-MultiMemberGroupInvitationCreate-Reply)
- [MultiMemberGroupInvitationCreate.Request](#weshnet-protocol-v1-MultiMemberGroupInvitationCreate-Request)
- [MultiMemberGroupJoin](#weshnet-protocol-v1-MultiMemberGroupJoin)
- [MultiMemberGroupJoin.Reply](#weshnet-protocol-v1-MultiMemberGroupJoin-Reply)
- [MultiMemberGroupJoin.Request](#weshnet-protocol-v1-MultiMemberGroupJoin-Request)
- [MultiMemberGroupLeave](#weshnet-protocol-v1-MultiMemberGroupLeave)
- [MultiMemberGroupLeave.Reply](#weshnet-protocol-v1-MultiMemberGroupLeave-Reply)
- [MultiMemberGroupLeave.Request](#weshnet-protocol-v1-MultiMemberGroupLeave-Request)
- [OrbitDBMessageHeads](#weshnet-protocol-v1-OrbitDBMessageHeads)
- [OrbitDBMessageHeads.Box](#weshnet-protocol-v1-OrbitDBMessageHeads-Box)
- [OutOfStoreMessage](#weshnet-protocol-v1-OutOfStoreMessage)
- [OutOfStoreMessageEnvelope](#weshnet-protocol-v1-OutOfStoreMessageEnvelope)
- [OutOfStoreReceive](#weshnet-protocol-v1-OutOfStoreReceive)
- [OutOfStoreReceive.Reply](#weshnet-protocol-v1-OutOfStoreReceive-Reply)
- [OutOfStoreReceive.Request](#weshnet-protocol-v1-OutOfStoreReceive-Request)
- [OutOfStoreSeal](#weshnet-protocol-v1-OutOfStoreSeal)
- [OutOfStoreSeal.Reply](#weshnet-protocol-v1-OutOfStoreSeal-Reply)
- [OutOfStoreSeal.Request](#weshnet-protocol-v1-OutOfStoreSeal-Request)
- [PeerList](#weshnet-protocol-v1-PeerList)
- [PeerList.Peer](#weshnet-protocol-v1-PeerList-Peer)
- [PeerList.Reply](#weshnet-protocol-v1-PeerList-Reply)
- [PeerList.Request](#weshnet-protocol-v1-PeerList-Request)
- [PeerList.Route](#weshnet-protocol-v1-PeerList-Route)
- [PeerList.Stream](#weshnet-protocol-v1-PeerList-Stream)
- [Progress](#weshnet-protocol-v1-Progress)
- [ProtocolMetadata](#weshnet-protocol-v1-ProtocolMetadata)
- [RefreshContactRequest](#weshnet-protocol-v1-RefreshContactRequest)
- [RefreshContactRequest.Peer](#weshnet-protocol-v1-RefreshContactRequest-Peer)
- [RefreshContactRequest.Reply](#weshnet-protocol-v1-RefreshContactRequest-Reply)
- [RefreshContactRequest.Request](#weshnet-protocol-v1-RefreshContactRequest-Request)
- [ReplicationServiceRegisterGroup](#weshnet-protocol-v1-ReplicationServiceRegisterGroup)
- [ReplicationServiceRegisterGroup.Reply](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Reply)
- [ReplicationServiceRegisterGroup.Request](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Request)
- [ReplicationServiceReplicateGroup](#weshnet-protocol-v1-ReplicationServiceReplicateGroup)
- [ReplicationServiceReplicateGroup.Reply](#weshnet-protocol-v1-ReplicationServiceReplicateGroup-Reply)
- [ReplicationServiceReplicateGroup.Request](#weshnet-protocol-v1-ReplicationServiceReplicateGroup-Request)
- [ServiceExportData](#weshnet-protocol-v1-ServiceExportData)
- [ServiceExportData.Reply](#weshnet-protocol-v1-ServiceExportData-Reply)
- [ServiceExportData.Request](#weshnet-protocol-v1-ServiceExportData-Request)
- [ServiceGetConfiguration](#weshnet-protocol-v1-ServiceGetConfiguration)
- [ServiceGetConfiguration.Reply](#weshnet-protocol-v1-ServiceGetConfiguration-Reply)
- [ServiceGetConfiguration.Request](#weshnet-protocol-v1-ServiceGetConfiguration-Request)
- [ServiceToken](#weshnet-protocol-v1-ServiceToken)
- [ServiceTokenSupportedService](#weshnet-protocol-v1-ServiceTokenSupportedService)
- [ShareContact](#weshnet-protocol-v1-ShareContact)
- [ShareContact.Reply](#weshnet-protocol-v1-ShareContact-Reply)
- [ShareContact.Request](#weshnet-protocol-v1-ShareContact-Request)
- [ShareableContact](#weshnet-protocol-v1-ShareableContact)
- [SystemInfo](#weshnet-protocol-v1-SystemInfo)
- [SystemInfo.OrbitDB](#weshnet-protocol-v1-SystemInfo-OrbitDB)
- [SystemInfo.OrbitDB.ReplicationStatus](#weshnet-protocol-v1-SystemInfo-OrbitDB-ReplicationStatus)
- [SystemInfo.P2P](#weshnet-protocol-v1-SystemInfo-P2P)
- [SystemInfo.Process](#weshnet-protocol-v1-SystemInfo-Process)
- [SystemInfo.Reply](#weshnet-protocol-v1-SystemInfo-Reply)
- [SystemInfo.Request](#weshnet-protocol-v1-SystemInfo-Request)
- [VerifiedCredentialsList](#weshnet-protocol-v1-VerifiedCredentialsList)
- [VerifiedCredentialsList.Reply](#weshnet-protocol-v1-VerifiedCredentialsList-Reply)
- [VerifiedCredentialsList.Request](#weshnet-protocol-v1-VerifiedCredentialsList-Request)
- [ContactState](#weshnet-protocol-v1-ContactState)
- [DebugInspectGroupLogType](#weshnet-protocol-v1-DebugInspectGroupLogType)
- [Direction](#weshnet-protocol-v1-Direction)
- [EventType](#weshnet-protocol-v1-EventType)
- [GroupDeviceStatus.Transport](#weshnet-protocol-v1-GroupDeviceStatus-Transport)
- [GroupDeviceStatus.Type](#weshnet-protocol-v1-GroupDeviceStatus-Type)
- [GroupType](#weshnet-protocol-v1-GroupType)
- [PeerList.Feature](#weshnet-protocol-v1-PeerList-Feature)
- [ServiceGetConfiguration.SettingState](#weshnet-protocol-v1-ServiceGetConfiguration-SettingState)
- [ProtocolService](#weshnet-protocol-v1-ProtocolService)
- [Scalar Value Types](#scalar-value-types)
Top
## protocoltypes.proto
### Account
Account describes all the secrets that identifies an Account
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group | [Group](#weshnet-protocol-v1-Group) | | group specifies which group is used to manage the account |
| account_private_key | [bytes](#bytes) | | account_private_key, private part is used to signs handshake, signs device, create contacts group keys via ECDH -- public part is used to have a shareable identity |
| alias_private_key | [bytes](#bytes) | | alias_private_key, private part is use to derive group members private keys, signs alias proofs, public part can be shared to contacts to prove identity |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed, rendezvous seed used for direct communication |
### AccountContactBlocked
AccountContactBlocked indicates that a contact is blocked
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the contact blocked |
### AccountContactRequestDisabled
AccountContactRequestDisabled indicates that the account should not be advertised on a public rendezvous point
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
### AccountContactRequestEnabled
AccountContactRequestEnabled indicates that the account should be advertised on a public rendezvous point
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
### AccountContactRequestIncomingAccepted
This event should be followed by an AccountGroupJoined event
This event should be followed by GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events within the AccountGroup
AccountContactRequestIncomingAccepted indicates that a contact request has been accepted
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the contact whom request is accepted |
| group_pk | [bytes](#bytes) | | group_pk is the 1to1 group with the requester user |
### AccountContactRequestIncomingDiscarded
AccountContactRequestIncomingDiscarded indicates that a contact request has been refused
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the contact whom request is refused |
### AccountContactRequestIncomingReceived
AccountContactRequestIncomingReceived indicates that the account has received a new contact request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the account event (which received the contact request), signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the account sending the request |
| contact_rendezvous_seed | [bytes](#bytes) | | TODO: is this necessary? contact_rendezvous_seed is the rendezvous seed of the contact sending the request |
| contact_metadata | [bytes](#bytes) | | TODO: is this necessary? contact_metadata is the metadata specific to the app to identify the contact for the request |
### AccountContactRequestOutgoingEnqueued
This event should be followed by an AccountGroupJoined event
This event should be followed by a GroupMemberDeviceAdded event within the AccountGroup
This event should be followed by a GroupDeviceChainKeyAdded event within the AccountGroup
AccountContactRequestOutgoingEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| group_pk | [bytes](#bytes) | | group_pk is the 1to1 group with the requested user |
| contact | [ShareableContact](#weshnet-protocol-v1-ShareableContact) | | contact is a message describing how to connect to the other account |
| own_metadata | [bytes](#bytes) | | own_metadata is the identifying metadata that will be shared to the other account |
### AccountContactRequestOutgoingSent
AccountContactRequestOutgoingSent indicates that the account has sent a contact request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the account event, signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the contacted account |
### AccountContactRequestReferenceReset
AccountContactRequestReferenceReset indicates that the account should be advertised on different public rendezvous points
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed is the new rendezvous point seed |
### AccountContactUnblocked
AccountContactUnblocked indicates that a contact is unblocked
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| contact_pk | [bytes](#bytes) | | contact_pk is the contact unblocked |
### AccountGroupJoined
AccountGroupJoined indicates that the account is now part of a new group
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| group | [Group](#weshnet-protocol-v1-Group) | | group describe the joined group |
### AccountGroupLeft
AccountGroupLeft indicates that the account has left a group
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| group_pk | [bytes](#bytes) | | group_pk references the group left |
### AccountVerifiedCredentialRegistered
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the public key of the device sending the message |
| signed_identity_public_key | [bytes](#bytes) | | |
| verified_credential | [string](#string) | | |
| registration_date | [int64](#int64) | | |
| expiration_date | [int64](#int64) | | |
| identifier | [string](#string) | | |
| issuer | [string](#string) | | |
### ActivateGroup
### ActivateGroup.Reply
### ActivateGroup.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| local_only | [bool](#bool) | | local_only will open the group without enabling network interactions with other members |
### AppMessageSend
### AppMessageSend.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| cid | [bytes](#bytes) | | |
### AppMessageSend.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| payload | [bytes](#bytes) | | payload is the payload to send |
### AppMetadataSend
### AppMetadataSend.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| cid | [bytes](#bytes) | | |
### AppMetadataSend.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| payload | [bytes](#bytes) | | payload is the payload to send |
### ContactAliasKeyAdded
ContactAliasKeyAdded is an event type where ones shares their alias public key
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| alias_pk | [bytes](#bytes) | | alias_pk is the alias key which will be used to verify a contact identity |
### ContactAliasKeySend
### ContactAliasKeySend.Reply
### ContactAliasKeySend.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact to send the alias public key to |
### ContactBlock
### ContactBlock.Reply
### ContactBlock.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact to block |
### ContactRequestAccept
### ContactRequestAccept.Reply
### ContactRequestAccept.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact to accept the request from |
### ContactRequestDisable
### ContactRequestDisable.Reply
### ContactRequestDisable.Request
### ContactRequestDiscard
### ContactRequestDiscard.Reply
### ContactRequestDiscard.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact to ignore the request from |
### ContactRequestEnable
### ContactRequestEnable.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed is the rendezvous seed used by the current account |
### ContactRequestEnable.Request
### ContactRequestReference
### ContactRequestReference.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed is the rendezvous seed used by the current account |
| enabled | [bool](#bool) | | enabled indicates if incoming contact requests are enabled |
### ContactRequestReference.Request
### ContactRequestResetReference
### ContactRequestResetReference.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed is the rendezvous seed used by the current account |
### ContactRequestResetReference.Request
### ContactRequestSend
### ContactRequestSend.Reply
### ContactRequestSend.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact | [ShareableContact](#weshnet-protocol-v1-ShareableContact) | | contact is a message describing how to connect to the other account |
| own_metadata | [bytes](#bytes) | | own_metadata is the identifying metadata that will be shared to the other account |
### ContactUnblock
### ContactUnblock.Reply
### ContactUnblock.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact to unblock |
### CredentialVerificationServiceCompleteFlow
### CredentialVerificationServiceCompleteFlow.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| identifier | [string](#string) | | |
### CredentialVerificationServiceCompleteFlow.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| callback_uri | [string](#string) | | |
### CredentialVerificationServiceInitFlow
### CredentialVerificationServiceInitFlow.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| url | [string](#string) | | |
| secure_url | [bool](#bool) | | |
### CredentialVerificationServiceInitFlow.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| service_url | [string](#string) | | |
| public_key | [bytes](#bytes) | | |
| link | [string](#string) | | |
### DeactivateGroup
### DeactivateGroup.Reply
### DeactivateGroup.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
### DebugGroup
### DebugGroup.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peer_ids | [string](#string) | repeated | peer_ids is the list of peer ids connected to the same group |
### DebugGroup.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
### DebugInspectGroupStore
### DebugInspectGroupStore.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| cid | [bytes](#bytes) | | cid is the CID of the IPFS log entry |
| parent_cids | [bytes](#bytes) | repeated | parent_cids is the list of the parent entries |
| metadata_event_type | [EventType](#weshnet-protocol-v1-EventType) | | event_type metadata event type if subscribed to metadata events |
| device_pk | [bytes](#bytes) | | device_pk is the public key of the device signing the entry |
| payload | [bytes](#bytes) | | payload is the un encrypted entry payload if available |
### DebugInspectGroupStore.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| log_type | [DebugInspectGroupLogType](#weshnet-protocol-v1-DebugInspectGroupLogType) | | log_type is the log to inspect |
### DebugListGroups
### DebugListGroups.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the public key of the group |
| group_type | [GroupType](#weshnet-protocol-v1-GroupType) | | group_type is the type of the group |
| contact_pk | [bytes](#bytes) | | contact_pk is the contact public key if appropriate |
### DebugListGroups.Request
### DecodeContact
### DecodeContact.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact | [ShareableContact](#weshnet-protocol-v1-ShareableContact) | | shareable_contact is the decoded shareable contact. |
### DecodeContact.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| encoded_contact | [bytes](#bytes) | | encoded_contact is the Protobuf encoding of the shareable contact (as returned by ShareContact). |
### DeviceChainKey
DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| chain_key | [bytes](#bytes) | | chain_key is the current value of the chain key of the group device |
| counter | [uint64](#uint64) | | counter is the current value of the counter of the group device |
### EncryptedMessage
EncryptedMessage is used in MessageEnvelope and only readable by groups members that joined before the message was sent
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| plaintext | [bytes](#bytes) | | plaintext is the app layer data |
| protocol_metadata | [ProtocolMetadata](#weshnet-protocol-v1-ProtocolMetadata) | | protocol_metadata is protocol layer data |
### EventContext
EventContext adds context (its id, its parents and its attachments) to an event
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [bytes](#bytes) | | id is the CID of the underlying OrbitDB event |
| parent_ids | [bytes](#bytes) | repeated | id are the the CIDs of the underlying parents of the OrbitDB event |
| group_pk | [bytes](#bytes) | | group_pk receiving the event |
### FirstLastCounters
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| first | [uint64](#uint64) | | |
| last | [uint64](#uint64) | | |
### Group
Group define a group and is enough to invite someone to it
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| public_key | [bytes](#bytes) | | public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group |
| secret | [bytes](#bytes) | | secret is the symmetric secret of the group, which is used to encrypt the metadata |
| secret_sig | [bytes](#bytes) | | secret_sig is the signature of the secret used to ensure the validity of the group |
| group_type | [GroupType](#weshnet-protocol-v1-GroupType) | | group_type specifies the type of the group, used to determine how device chain key is generated |
| sign_pub | [bytes](#bytes) | | sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided |
| link_key | [bytes](#bytes) | | link_key is the secret key used to exchange group updates and links to attachments, useful for replication services |
| link_key_sig | [bytes](#bytes) | | link_key_sig is the signature of the link_key using the group private key |
### GroupAddAdditionalRendezvousSeed
GroupAddAdditionalRendezvousSeed indicates that an additional rendezvous point should be used for data synchronization
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message, must be the device of an admin of the group |
| seed | [bytes](#bytes) | | seed is the additional rendezvous point seed which should be used |
### GroupDeviceChainKeyAdded
GroupDeviceChainKeyAdded is an event which indicates to a group member a device chain key
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| dest_member_pk | [bytes](#bytes) | | dest_member_pk is the member who should receive the secret |
| payload | [bytes](#bytes) | | payload is the serialization of Payload encrypted for the specified member |
### GroupDeviceStatus
### GroupDeviceStatus.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| type | [GroupDeviceStatus.Type](#weshnet-protocol-v1-GroupDeviceStatus-Type) | | |
| event | [bytes](#bytes) | | |
### GroupDeviceStatus.Reply.PeerConnected
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peer_id | [string](#string) | | |
| device_pk | [bytes](#bytes) | | |
| transports | [GroupDeviceStatus.Transport](#weshnet-protocol-v1-GroupDeviceStatus-Transport) | repeated | |
| maddrs | [string](#string) | repeated | |
### GroupDeviceStatus.Reply.PeerDisconnected
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peer_id | [string](#string) | | |
### GroupDeviceStatus.Reply.PeerReconnecting
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peer_id | [string](#string) | | |
### GroupDeviceStatus.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | |
### GroupEnvelope
GroupEnvelope is a publicly exposed structure containing a group metadata event
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| nonce | [bytes](#bytes) | | nonce is used to encrypt the message |
| event | [bytes](#bytes) | | event is encrypted using a symmetric key shared among group members |
### GroupHeadsExport
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| public_key | [bytes](#bytes) | | public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group |
| sign_pub | [bytes](#bytes) | | sign_pub is the signature public key used to verify entries |
| metadata_heads_cids | [bytes](#bytes) | repeated | metadata_heads_cids are the heads of the metadata store that should be restored from an export |
| messages_heads_cids | [bytes](#bytes) | repeated | messages_heads_cids are the heads of the metadata store that should be restored from an export |
| link_key | [bytes](#bytes) | | link_key |
### GroupInfo
### GroupInfo.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group | [Group](#weshnet-protocol-v1-Group) | | group is the group invitation, containing the group pk and its type |
| member_pk | [bytes](#bytes) | | member_pk is the identifier of the current member in the group |
| device_pk | [bytes](#bytes) | | device_pk is the identifier of the current device in the group |
### GroupInfo.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| contact_pk | [bytes](#bytes) | | contact_pk is the identifier of the contact |
### GroupMemberDeviceAdded
GroupMemberDeviceAdded is an event which indicates to a group a new device (and eventually a new member) is joining it
When added on AccountGroup, this event should be followed by appropriate GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| member_pk | [bytes](#bytes) | | member_pk is the member sending the event |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| member_sig | [bytes](#bytes) | | member_sig is used to prove the ownership of the member pk
TODO: signature of what ??? ensure it can't be replayed |
### GroupMessageEvent
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| event_context | [EventContext](#weshnet-protocol-v1-EventContext) | | event_context contains context information about the event |
| headers | [MessageHeaders](#weshnet-protocol-v1-MessageHeaders) | | headers contains headers of the secure message |
| message | [bytes](#bytes) | | message contains the secure message payload |
### GroupMessageList
### GroupMessageList.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| since_id | [bytes](#bytes) | | since is the lower ID bound used to filter events if not set, will return events since the beginning |
| since_now | [bool](#bool) | | since_now will list only new event to come since_id must not be set |
| until_id | [bytes](#bytes) | | until is the upper ID bound used to filter events if not set, will subscribe to new events to come |
| until_now | [bool](#bool) | | until_now will not list new event to come until_id must not be set |
| reverse_order | [bool](#bool) | | reverse_order indicates whether the previous events should be returned in reverse chronological order |
### GroupMetadata
GroupMetadata is used in GroupEnvelope and only readable by invited group members
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| event_type | [EventType](#weshnet-protocol-v1-EventType) | | event_type defines which event type is used |
| payload | [bytes](#bytes) | | the serialization depends on event_type, event is symmetrically encrypted |
| sig | [bytes](#bytes) | | sig is the signature of the payload, it depends on the event_type for the used key |
| protocol_metadata | [ProtocolMetadata](#weshnet-protocol-v1-ProtocolMetadata) | | protocol_metadata is protocol layer data |
### GroupMetadataEvent
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| event_context | [EventContext](#weshnet-protocol-v1-EventContext) | | event_context contains context information about the event |
| metadata | [GroupMetadata](#weshnet-protocol-v1-GroupMetadata) | | metadata contains the newly available metadata |
| event | [bytes](#bytes) | | event_clear clear bytes for the event |
### GroupMetadataList
### GroupMetadataList.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| since_id | [bytes](#bytes) | | since is the lower ID bound used to filter events if not set, will return events since the beginning |
| since_now | [bool](#bool) | | since_now will list only new event to come since_id must not be set |
| until_id | [bytes](#bytes) | | until is the upper ID bound used to filter events if not set, will subscribe to new events to come |
| until_now | [bool](#bool) | | until_now will not list new event to come until_id must not be set |
| reverse_order | [bool](#bool) | | reverse_order indicates whether the previous events should be returned in reverse chronological order |
### GroupMetadataPayloadSent
GroupMetadataPayloadSent is an app defined message, accessible to future group members
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| message | [bytes](#bytes) | | message is the payload |
### GroupRemoveAdditionalRendezvousSeed
GroupRemoveAdditionalRendezvousSeed indicates that a previously added rendezvous point should be removed
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message, must be the device of an admin of the group |
| seed | [bytes](#bytes) | | seed is the additional rendezvous point seed which should be removed |
### GroupReplicating
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| authentication_url | [string](#string) | | authentication_url indicates which server has been used for authentication |
| replication_server | [string](#string) | | replication_server indicates which server will be used for replication |
### MessageEnvelope
MessageEnvelope is a publicly exposed structure containing a group secure message
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| message_headers | [bytes](#bytes) | | message_headers is an encrypted serialization using a symmetric key of a MessageHeaders message |
| message | [bytes](#bytes) | | message is an encrypted message, only readable by group members who previously received the appropriate chain key |
| nonce | [bytes](#bytes) | | nonce is a nonce for message headers |
### MessageHeaders
MessageHeaders is used in MessageEnvelope and only readable by invited group members
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| counter | [uint64](#uint64) | | counter is the current counter value for the specified device |
| device_pk | [bytes](#bytes) | | device_pk is the public key of the device sending the message |
| sig | [bytes](#bytes) | | sig is the signature of the encrypted message using the device's private key |
| metadata | [MessageHeaders.MetadataEntry](#weshnet-protocol-v1-MessageHeaders-MetadataEntry) | repeated | metadata allow to pass custom informations |
### MessageHeaders.MetadataEntry
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| key | [string](#string) | | |
| value | [string](#string) | | |
### MultiMemberGroupAdminRoleGrant
### MultiMemberGroupAdminRoleGrant.Reply
### MultiMemberGroupAdminRoleGrant.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
| member_pk | [bytes](#bytes) | | member_pk is the identifier of the member which will be granted the admin role |
### MultiMemberGroupAdminRoleGranted
MultiMemberGroupAdminRoleGranted indicates that a group admin allows another group member to act as an admin
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message, must be the device of an admin of the group |
| grantee_member_pk | [bytes](#bytes) | | grantee_member_pk is the member public key of the member granted of the admin role |
### MultiMemberGroupAliasResolverAdded
MultiMemberGroupAliasResolverAdded indicates that a group member want to disclose their presence in the group to their contacts
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device_pk | [bytes](#bytes) | | device_pk is the device sending the event, signs the message |
| alias_resolver | [bytes](#bytes) | | alias_resolver allows contact of an account to resolve the real identity behind an alias (Multi-Member Group Member) Generated by both contacts and account independently using: hmac(aliasPK, GroupID) |
| alias_proof | [bytes](#bytes) | | alias_proof ensures that the associated alias_resolver has been issued by the right account Generated using aliasSKSig(GroupID) |
### MultiMemberGroupAliasResolverDisclose
### MultiMemberGroupAliasResolverDisclose.Reply
### MultiMemberGroupAliasResolverDisclose.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
### MultiMemberGroupCreate
### MultiMemberGroupCreate.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the newly created group |
### MultiMemberGroupCreate.Request
### MultiMemberGroupInitialMemberAnnounced
MultiMemberGroupInitialMemberAnnounced indicates that a member is the group creator, this event is signed using the group ID private key
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| member_pk | [bytes](#bytes) | | member_pk is the public key of the member who is the group creator |
### MultiMemberGroupInvitationCreate
### MultiMemberGroupInvitationCreate.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group | [Group](#weshnet-protocol-v1-Group) | | group is the invitation to the group |
### MultiMemberGroupInvitationCreate.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | group_pk is the identifier of the group |
### MultiMemberGroupJoin
### MultiMemberGroupJoin.Reply
### MultiMemberGroupJoin.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group | [Group](#weshnet-protocol-v1-Group) | | group is the information of the group to join |
### MultiMemberGroupLeave
### MultiMemberGroupLeave.Reply
### MultiMemberGroupLeave.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | |
### OrbitDBMessageHeads
OrbitDBMessageHeads is the payload sent on orbitdb to share peer's heads
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| sealed_box | [bytes](#bytes) | | sealed box should contain encrypted Box |
| raw_rotation | [bytes](#bytes) | | current topic used |
### OrbitDBMessageHeads.Box
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| address | [string](#string) | | |
| heads | [bytes](#bytes) | | |
| device_pk | [bytes](#bytes) | | |
| peer_id | [bytes](#bytes) | | |
### OutOfStoreMessage
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| cid | [bytes](#bytes) | | |
| device_pk | [bytes](#bytes) | | |
| counter | [fixed64](#fixed64) | | |
| sig | [bytes](#bytes) | | |
| flags | [fixed32](#fixed32) | | |
| encrypted_payload | [bytes](#bytes) | | |
| nonce | [bytes](#bytes) | | |
### OutOfStoreMessageEnvelope
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| nonce | [bytes](#bytes) | | |
| box | [bytes](#bytes) | | |
| group_reference | [bytes](#bytes) | | |
### OutOfStoreReceive
### OutOfStoreReceive.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| message | [OutOfStoreMessage](#weshnet-protocol-v1-OutOfStoreMessage) | | |
| cleartext | [bytes](#bytes) | | |
| group_public_key | [bytes](#bytes) | | |
| already_received | [bool](#bool) | | |
### OutOfStoreReceive.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| payload | [bytes](#bytes) | | |
### OutOfStoreSeal
### OutOfStoreSeal.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| encrypted | [bytes](#bytes) | | |
### OutOfStoreSeal.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| cid | [bytes](#bytes) | | |
| group_public_key | [bytes](#bytes) | | |
### PeerList
### PeerList.Peer
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | id is the libp2p.PeerID. |
| routes | [PeerList.Route](#weshnet-protocol-v1-PeerList-Route) | repeated | routes are the list of active and known maddr. |
| errors | [string](#string) | repeated | errors is a list of errors related to the peer. |
| features | [PeerList.Feature](#weshnet-protocol-v1-PeerList-Feature) | repeated | Features is a list of available features. |
| min_latency | [int64](#int64) | | MinLatency is the minimum latency across all the peer routes. |
| is_active | [bool](#bool) | | IsActive is true if at least one of the route is active. |
| direction | [Direction](#weshnet-protocol-v1-Direction) | | Direction is the aggregate of all the routes's direction. |
### PeerList.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peers | [PeerList.Peer](#weshnet-protocol-v1-PeerList-Peer) | repeated | |
### PeerList.Request
### PeerList.Route
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| is_active | [bool](#bool) | | IsActive indicates whether the address is currently used or just known. |
| address | [string](#string) | | Address is the multiaddress via which we are connected with the peer. |
| direction | [Direction](#weshnet-protocol-v1-Direction) | | Direction is which way the connection was established. |
| latency | [int64](#int64) | | Latency is the last known round trip time to the peer in ms. |
| streams | [PeerList.Stream](#weshnet-protocol-v1-PeerList-Stream) | repeated | Streams returns list of streams established with the peer. |
### PeerList.Stream
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | id is an identifier used to write protocol headers in streams. |
### Progress
Progress define a generic object that can be used to display a progress bar for long-running actions.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| state | [string](#string) | | |
| doing | [string](#string) | | |
| progress | [float](#float) | | |
| completed | [uint64](#uint64) | | |
| total | [uint64](#uint64) | | |
| delay | [uint64](#uint64) | | |
### ProtocolMetadata
### RefreshContactRequest
### RefreshContactRequest.Peer
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | id is the libp2p.PeerID. |
| addrs | [string](#string) | repeated | list of peers multiaddrs. |
### RefreshContactRequest.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| peers_found | [RefreshContactRequest.Peer](#weshnet-protocol-v1-RefreshContactRequest-Peer) | repeated | peers found and successfully connected. |
### RefreshContactRequest.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| contact_pk | [bytes](#bytes) | | |
| timeout | [int64](#int64) | | timeout in second |
### ReplicationServiceRegisterGroup
### ReplicationServiceRegisterGroup.Reply
### ReplicationServiceRegisterGroup.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group_pk | [bytes](#bytes) | | |
| token | [string](#string) | | |
| authentication_url | [string](#string) | | |
| replication_server | [string](#string) | | |
### ReplicationServiceReplicateGroup
### ReplicationServiceReplicateGroup.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| ok | [bool](#bool) | | |
### ReplicationServiceReplicateGroup.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| group | [Group](#weshnet-protocol-v1-Group) | | |
### ServiceExportData
### ServiceExportData.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| exported_data | [bytes](#bytes) | | |
### ServiceExportData.Request
### ServiceGetConfiguration
### ServiceGetConfiguration.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| account_pk | [bytes](#bytes) | | account_pk is the public key of the current account |
| device_pk | [bytes](#bytes) | | device_pk is the public key of the current device |
| account_group_pk | [bytes](#bytes) | | account_group_pk is the public key of the account group |
| peer_id | [string](#string) | | peer_id is the peer ID of the current IPFS node |
| listeners | [string](#string) | repeated | listeners is the list of swarm listening addresses of the current IPFS node |
| ble_enabled | [ServiceGetConfiguration.SettingState](#weshnet-protocol-v1-ServiceGetConfiguration-SettingState) | | |
| wifi_p2p_enabled | [ServiceGetConfiguration.SettingState](#weshnet-protocol-v1-ServiceGetConfiguration-SettingState) | | MultiPeerConnectivity for Darwin and Nearby for Android |
| mdns_enabled | [ServiceGetConfiguration.SettingState](#weshnet-protocol-v1-ServiceGetConfiguration-SettingState) | | |
| relay_enabled | [ServiceGetConfiguration.SettingState](#weshnet-protocol-v1-ServiceGetConfiguration-SettingState) | | |
### ServiceGetConfiguration.Request
### ServiceToken
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| token | [string](#string) | | |
| authentication_url | [string](#string) | | |
| supported_services | [ServiceTokenSupportedService](#weshnet-protocol-v1-ServiceTokenSupportedService) | repeated | |
| expiration | [int64](#int64) | | |
### ServiceTokenSupportedService
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| service_type | [string](#string) | | |
| service_endpoint | [string](#string) | | |
### ShareContact
### ShareContact.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| encoded_contact | [bytes](#bytes) | | encoded_contact is the Protobuf encoding of the ShareableContact. You can further encode the bytes for sharing, such as base58 or QR code. |
### ShareContact.Request
### ShareableContact
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| pk | [bytes](#bytes) | | pk is the account to send a contact request to |
| public_rendezvous_seed | [bytes](#bytes) | | public_rendezvous_seed is the rendezvous seed used by the account to send a contact request to |
| metadata | [bytes](#bytes) | | metadata is the metadata specific to the app to identify the contact for the request |
### SystemInfo
### SystemInfo.OrbitDB
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| account_metadata | [SystemInfo.OrbitDB.ReplicationStatus](#weshnet-protocol-v1-SystemInfo-OrbitDB-ReplicationStatus) | | |
### SystemInfo.OrbitDB.ReplicationStatus
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| progress | [int64](#int64) | | |
| maximum | [int64](#int64) | | |
| buffered | [int64](#int64) | | |
| queued | [int64](#int64) | | |
### SystemInfo.P2P
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| connected_peers | [int64](#int64) | | |
### SystemInfo.Process
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| version | [string](#string) | | |
| vcs_ref | [string](#string) | | |
| uptime_ms | [int64](#int64) | | |
| user_cpu_time_ms | [int64](#int64) | | |
| system_cpu_time_ms | [int64](#int64) | | |
| started_at | [int64](#int64) | | |
| rlimit_cur | [uint64](#uint64) | | |
| num_goroutine | [int64](#int64) | | |
| nofile | [int64](#int64) | | |
| too_many_open_files | [bool](#bool) | | |
| num_cpu | [int64](#int64) | | |
| go_version | [string](#string) | | |
| operating_system | [string](#string) | | |
| host_name | [string](#string) | | |
| arch | [string](#string) | | |
| rlimit_max | [uint64](#uint64) | | |
| pid | [int64](#int64) | | |
| ppid | [int64](#int64) | | |
| priority | [int64](#int64) | | |
| uid | [int64](#int64) | | |
| working_dir | [string](#string) | | |
| system_username | [string](#string) | | |
### SystemInfo.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| process | [SystemInfo.Process](#weshnet-protocol-v1-SystemInfo-Process) | | |
| p2p | [SystemInfo.P2P](#weshnet-protocol-v1-SystemInfo-P2P) | | |
| orbitdb | [SystemInfo.OrbitDB](#weshnet-protocol-v1-SystemInfo-OrbitDB) | | |
| warns | [string](#string) | repeated | |
### SystemInfo.Request
### VerifiedCredentialsList
### VerifiedCredentialsList.Reply
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| credential | [AccountVerifiedCredentialRegistered](#weshnet-protocol-v1-AccountVerifiedCredentialRegistered) | | |
### VerifiedCredentialsList.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| filter_identifier | [string](#string) | | |
| filter_issuer | [string](#string) | | |
| exclude_expired | [bool](#bool) | | |
### ContactState
| Name | Number | Description |
| ---- | ------ | ----------- |
| ContactStateUndefined | 0 | |
| ContactStateToRequest | 1 | |
| ContactStateReceived | 2 | |
| ContactStateAdded | 3 | |
| ContactStateRemoved | 4 | |
| ContactStateDiscarded | 5 | |
| ContactStateBlocked | 6 | |
### DebugInspectGroupLogType
| Name | Number | Description |
| ---- | ------ | ----------- |
| DebugInspectGroupLogTypeUndefined | 0 | |
| DebugInspectGroupLogTypeMessage | 1 | |
| DebugInspectGroupLogTypeMetadata | 2 | |
### Direction
| Name | Number | Description |
| ---- | ------ | ----------- |
| UnknownDir | 0 | |
| InboundDir | 1 | |
| OutboundDir | 2 | |
| BiDir | 3 | |
### EventType
| Name | Number | Description |
| ---- | ------ | ----------- |
| EventTypeUndefined | 0 | EventTypeUndefined indicates that the value has not been set. Should not happen. |
| EventTypeGroupMemberDeviceAdded | 1 | EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group |
| EventTypeGroupDeviceChainKeyAdded | 2 | EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member |
| EventTypeAccountGroupJoined | 101 | EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group |
| EventTypeAccountGroupLeft | 102 | EventTypeAccountGroupLeft indicates the payload includes that the account has left a group |
| EventTypeAccountContactRequestDisabled | 103 | EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests |
| EventTypeAccountContactRequestEnabled | 104 | EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests |
| EventTypeAccountContactRequestReferenceReset | 105 | EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed |
| EventTypeAccountContactRequestOutgoingEnqueued | 106 | EventTypeAccountContactRequestOutgoingEnqueued indicates the payload includes that the account will attempt to send a new contact request |
| EventTypeAccountContactRequestOutgoingSent | 107 | EventTypeAccountContactRequestOutgoingSent indicates the payload includes that the account has sent a contact request |
| EventTypeAccountContactRequestIncomingReceived | 108 | EventTypeAccountContactRequestIncomingReceived indicates the payload includes that the account has received a contact request |
| EventTypeAccountContactRequestIncomingDiscarded | 109 | EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request |
| EventTypeAccountContactRequestIncomingAccepted | 110 | EventTypeAccountContactRequestIncomingAccepted indicates the payload includes that the account has accepted a contact request |
| EventTypeAccountContactBlocked | 111 | EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact |
| EventTypeAccountContactUnblocked | 112 | EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact |
| EventTypeContactAliasKeyAdded | 201 | EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key |
| EventTypeMultiMemberGroupAliasResolverAdded | 301 | EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof |
| EventTypeMultiMemberGroupInitialMemberAnnounced | 302 | EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner |
| EventTypeMultiMemberGroupAdminRoleGranted | 303 | EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin |
| EventTypeGroupReplicating | 403 | EventTypeGroupReplicating indicates that the group has been registered for replication on a server |
| EventTypeAccountVerifiedCredentialRegistered | 500 | EventTypeAccountVerifiedCredentialRegistered |
| EventTypeGroupMetadataPayloadSent | 1001 | EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key |
### GroupDeviceStatus.Transport
| Name | Number | Description |
| ---- | ------ | ----------- |
| TptUnknown | 0 | |
| TptLAN | 1 | |
| TptWAN | 2 | |
| TptProximity | 3 | |
### GroupDeviceStatus.Type
| Name | Number | Description |
| ---- | ------ | ----------- |
| TypeUnknown | 0 | |
| TypePeerDisconnected | 1 | |
| TypePeerConnected | 2 | |
| TypePeerReconnecting | 3 | |
### GroupType
| Name | Number | Description |
| ---- | ------ | ----------- |
| GroupTypeUndefined | 0 | GroupTypeUndefined indicates that the value has not been set. For example, happens if group is replicated. |
| GroupTypeAccount | 1 | GroupTypeAccount is the group managing an account, available to all its devices. |
| GroupTypeContact | 2 | GroupTypeContact is the group created between two accounts, available to all their devices. |
| GroupTypeMultiMember | 3 | GroupTypeMultiMember is a group containing an undefined number of members. |
### PeerList.Feature
| Name | Number | Description |
| ---- | ------ | ----------- |
| UnknownFeature | 0 | |
| WeshFeature | 1 | |
| BLEFeature | 2 | |
| LocalFeature | 3 | |
| TorFeature | 4 | |
| QuicFeature | 5 | |
### ServiceGetConfiguration.SettingState
| Name | Number | Description |
| ---- | ------ | ----------- |
| Unknown | 0 | |
| Enabled | 1 | |
| Disabled | 2 | |
| Unavailable | 3 | |
### ProtocolService
ProtocolService is the top-level API to manage the Wesh protocol service.
Each active Wesh protocol service is considered as a Wesh device and is associated with a Wesh user.
| Method Name | Request Type | Response Type | Description |
| ----------- | ------------ | ------------- | ------------|
| ServiceExportData | [ServiceExportData.Request](#weshnet-protocol-v1-ServiceExportData-Request) | [ServiceExportData.Reply](#weshnet-protocol-v1-ServiceExportData-Reply) stream | ServiceExportData exports the current data of the protocol service |
| ServiceGetConfiguration | [ServiceGetConfiguration.Request](#weshnet-protocol-v1-ServiceGetConfiguration-Request) | [ServiceGetConfiguration.Reply](#weshnet-protocol-v1-ServiceGetConfiguration-Reply) | ServiceGetConfiguration gets the current configuration of the protocol service |
| ContactRequestReference | [ContactRequestReference.Request](#weshnet-protocol-v1-ContactRequestReference-Request) | [ContactRequestReference.Reply](#weshnet-protocol-v1-ContactRequestReference-Reply) | ContactRequestReference retrieves the information required to create a reference (ie. included in a shareable link) to the current account |
| ContactRequestDisable | [ContactRequestDisable.Request](#weshnet-protocol-v1-ContactRequestDisable-Request) | [ContactRequestDisable.Reply](#weshnet-protocol-v1-ContactRequestDisable-Reply) | ContactRequestDisable disables incoming contact requests |
| ContactRequestEnable | [ContactRequestEnable.Request](#weshnet-protocol-v1-ContactRequestEnable-Request) | [ContactRequestEnable.Reply](#weshnet-protocol-v1-ContactRequestEnable-Reply) | ContactRequestEnable enables incoming contact requests |
| ContactRequestResetReference | [ContactRequestResetReference.Request](#weshnet-protocol-v1-ContactRequestResetReference-Request) | [ContactRequestResetReference.Reply](#weshnet-protocol-v1-ContactRequestResetReference-Reply) | ContactRequestResetReference changes the contact request reference |
| ContactRequestSend | [ContactRequestSend.Request](#weshnet-protocol-v1-ContactRequestSend-Request) | [ContactRequestSend.Reply](#weshnet-protocol-v1-ContactRequestSend-Reply) | ContactRequestSend attempt to send a contact request |
| ContactRequestAccept | [ContactRequestAccept.Request](#weshnet-protocol-v1-ContactRequestAccept-Request) | [ContactRequestAccept.Reply](#weshnet-protocol-v1-ContactRequestAccept-Reply) | ContactRequestAccept accepts a contact request |
| ContactRequestDiscard | [ContactRequestDiscard.Request](#weshnet-protocol-v1-ContactRequestDiscard-Request) | [ContactRequestDiscard.Reply](#weshnet-protocol-v1-ContactRequestDiscard-Reply) | ContactRequestDiscard ignores a contact request, without informing the other user |
| ShareContact | [ShareContact.Request](#weshnet-protocol-v1-ShareContact-Request) | [ShareContact.Reply](#weshnet-protocol-v1-ShareContact-Reply) | ShareContact uses ContactRequestReference to get the contact information for the current account and returns the Protobuf encoding of a shareable contact which you can further encode and share. If needed, this will reset the contact request reference and enable contact requests. To decode the result, see DecodeContact. |
| DecodeContact | [DecodeContact.Request](#weshnet-protocol-v1-DecodeContact-Request) | [DecodeContact.Reply](#weshnet-protocol-v1-DecodeContact-Reply) | DecodeContact decodes the Protobuf encoding of a shareable contact which was returned by ShareContact. |
| ContactBlock | [ContactBlock.Request](#weshnet-protocol-v1-ContactBlock-Request) | [ContactBlock.Reply](#weshnet-protocol-v1-ContactBlock-Reply) | ContactBlock blocks a contact from sending requests |
| ContactUnblock | [ContactUnblock.Request](#weshnet-protocol-v1-ContactUnblock-Request) | [ContactUnblock.Reply](#weshnet-protocol-v1-ContactUnblock-Reply) | ContactUnblock unblocks a contact from sending requests |
| ContactAliasKeySend | [ContactAliasKeySend.Request](#weshnet-protocol-v1-ContactAliasKeySend-Request) | [ContactAliasKeySend.Reply](#weshnet-protocol-v1-ContactAliasKeySend-Reply) | ContactAliasKeySend send an alias key to a contact, the contact will be able to assert that your account is being present on a multi-member group |
| MultiMemberGroupCreate | [MultiMemberGroupCreate.Request](#weshnet-protocol-v1-MultiMemberGroupCreate-Request) | [MultiMemberGroupCreate.Reply](#weshnet-protocol-v1-MultiMemberGroupCreate-Reply) | MultiMemberGroupCreate creates a new multi-member group |
| MultiMemberGroupJoin | [MultiMemberGroupJoin.Request](#weshnet-protocol-v1-MultiMemberGroupJoin-Request) | [MultiMemberGroupJoin.Reply](#weshnet-protocol-v1-MultiMemberGroupJoin-Reply) | MultiMemberGroupJoin joins a multi-member group |
| MultiMemberGroupLeave | [MultiMemberGroupLeave.Request](#weshnet-protocol-v1-MultiMemberGroupLeave-Request) | [MultiMemberGroupLeave.Reply](#weshnet-protocol-v1-MultiMemberGroupLeave-Reply) | MultiMemberGroupLeave leaves a multi-member group |
| MultiMemberGroupAliasResolverDisclose | [MultiMemberGroupAliasResolverDisclose.Request](#weshnet-protocol-v1-MultiMemberGroupAliasResolverDisclose-Request) | [MultiMemberGroupAliasResolverDisclose.Reply](#weshnet-protocol-v1-MultiMemberGroupAliasResolverDisclose-Reply) | MultiMemberGroupAliasResolverDisclose discloses your alias resolver key |
| MultiMemberGroupAdminRoleGrant | [MultiMemberGroupAdminRoleGrant.Request](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGrant-Request) | [MultiMemberGroupAdminRoleGrant.Reply](#weshnet-protocol-v1-MultiMemberGroupAdminRoleGrant-Reply) | MultiMemberGroupAdminRoleGrant grants an admin role to a group member |
| MultiMemberGroupInvitationCreate | [MultiMemberGroupInvitationCreate.Request](#weshnet-protocol-v1-MultiMemberGroupInvitationCreate-Request) | [MultiMemberGroupInvitationCreate.Reply](#weshnet-protocol-v1-MultiMemberGroupInvitationCreate-Reply) | MultiMemberGroupInvitationCreate creates an invitation to a multi-member group |
| AppMetadataSend | [AppMetadataSend.Request](#weshnet-protocol-v1-AppMetadataSend-Request) | [AppMetadataSend.Reply](#weshnet-protocol-v1-AppMetadataSend-Reply) | AppMetadataSend adds an app event to the metadata store, the message is encrypted using a symmetric key and readable by future group members |
| AppMessageSend | [AppMessageSend.Request](#weshnet-protocol-v1-AppMessageSend-Request) | [AppMessageSend.Reply](#weshnet-protocol-v1-AppMessageSend-Reply) | AppMessageSend adds an app event to the message store, the message is encrypted using a derived key and readable by current group members |
| GroupMetadataList | [GroupMetadataList.Request](#weshnet-protocol-v1-GroupMetadataList-Request) | [GroupMetadataEvent](#weshnet-protocol-v1-GroupMetadataEvent) stream | GroupMetadataList replays previous and subscribes to new metadata events from the group |
| GroupMessageList | [GroupMessageList.Request](#weshnet-protocol-v1-GroupMessageList-Request) | [GroupMessageEvent](#weshnet-protocol-v1-GroupMessageEvent) stream | GroupMessageList replays previous and subscribes to new message events from the group |
| GroupInfo | [GroupInfo.Request](#weshnet-protocol-v1-GroupInfo-Request) | [GroupInfo.Reply](#weshnet-protocol-v1-GroupInfo-Reply) | GroupInfo retrieves information about a group |
| ActivateGroup | [ActivateGroup.Request](#weshnet-protocol-v1-ActivateGroup-Request) | [ActivateGroup.Reply](#weshnet-protocol-v1-ActivateGroup-Reply) | ActivateGroup explicitly opens a group |
| DeactivateGroup | [DeactivateGroup.Request](#weshnet-protocol-v1-DeactivateGroup-Request) | [DeactivateGroup.Reply](#weshnet-protocol-v1-DeactivateGroup-Reply) | DeactivateGroup closes a group |
| GroupDeviceStatus | [GroupDeviceStatus.Request](#weshnet-protocol-v1-GroupDeviceStatus-Request) | [GroupDeviceStatus.Reply](#weshnet-protocol-v1-GroupDeviceStatus-Reply) stream | GroupDeviceStatus monitor device status |
| DebugListGroups | [DebugListGroups.Request](#weshnet-protocol-v1-DebugListGroups-Request) | [DebugListGroups.Reply](#weshnet-protocol-v1-DebugListGroups-Reply) stream | |
| DebugInspectGroupStore | [DebugInspectGroupStore.Request](#weshnet-protocol-v1-DebugInspectGroupStore-Request) | [DebugInspectGroupStore.Reply](#weshnet-protocol-v1-DebugInspectGroupStore-Reply) stream | |
| DebugGroup | [DebugGroup.Request](#weshnet-protocol-v1-DebugGroup-Request) | [DebugGroup.Reply](#weshnet-protocol-v1-DebugGroup-Reply) | |
| SystemInfo | [SystemInfo.Request](#weshnet-protocol-v1-SystemInfo-Request) | [SystemInfo.Reply](#weshnet-protocol-v1-SystemInfo-Reply) | |
| CredentialVerificationServiceInitFlow | [CredentialVerificationServiceInitFlow.Request](#weshnet-protocol-v1-CredentialVerificationServiceInitFlow-Request) | [CredentialVerificationServiceInitFlow.Reply](#weshnet-protocol-v1-CredentialVerificationServiceInitFlow-Reply) | CredentialVerificationServiceInitFlow Initialize a credential verification flow |
| CredentialVerificationServiceCompleteFlow | [CredentialVerificationServiceCompleteFlow.Request](#weshnet-protocol-v1-CredentialVerificationServiceCompleteFlow-Request) | [CredentialVerificationServiceCompleteFlow.Reply](#weshnet-protocol-v1-CredentialVerificationServiceCompleteFlow-Reply) | CredentialVerificationServiceCompleteFlow Completes a credential verification flow |
| VerifiedCredentialsList | [VerifiedCredentialsList.Request](#weshnet-protocol-v1-VerifiedCredentialsList-Request) | [VerifiedCredentialsList.Reply](#weshnet-protocol-v1-VerifiedCredentialsList-Reply) stream | VerifiedCredentialsList Retrieves the list of verified credentials |
| ReplicationServiceRegisterGroup | [ReplicationServiceRegisterGroup.Request](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Request) | [ReplicationServiceRegisterGroup.Reply](#weshnet-protocol-v1-ReplicationServiceRegisterGroup-Reply) | ReplicationServiceRegisterGroup Asks a replication service to distribute a group contents |
| PeerList | [PeerList.Request](#weshnet-protocol-v1-PeerList-Request) | [PeerList.Reply](#weshnet-protocol-v1-PeerList-Reply) | PeerList returns a list of P2P peers |
| OutOfStoreReceive | [OutOfStoreReceive.Request](#weshnet-protocol-v1-OutOfStoreReceive-Request) | [OutOfStoreReceive.Reply](#weshnet-protocol-v1-OutOfStoreReceive-Reply) | OutOfStoreReceive parses a payload received outside a synchronized store |
| OutOfStoreSeal | [OutOfStoreSeal.Request](#weshnet-protocol-v1-OutOfStoreSeal-Request) | [OutOfStoreSeal.Reply](#weshnet-protocol-v1-OutOfStoreSeal-Reply) | OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store |
| RefreshContactRequest | [RefreshContactRequest.Request](#weshnet-protocol-v1-RefreshContactRequest-Request) | [RefreshContactRequest.Reply](#weshnet-protocol-v1-RefreshContactRequest-Reply) | RefreshContactRequest try to refresh the contact request for the given contact |
## Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |
| double | | double | double | float | float64 | double | float | Float |
| float | | float | float | float | float32 | float | float | Float |
| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| bool | | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |
| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
================================================
FILE: docs/apis/protocoltypes.swagger.json
================================================
{
"swagger": "2.0",
"info": {
"title": "protocoltypes.proto",
"version": "version not set"
},
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"GroupDeviceStatusType": {
"type": "string",
"enum": [
"TypeUnknown",
"TypePeerDisconnected",
"TypePeerConnected",
"TypePeerReconnecting"
],
"default": "TypeUnknown"
},
"OrbitDBReplicationStatus": {
"type": "object",
"properties": {
"progress": {
"type": "string",
"format": "int64"
},
"maximum": {
"type": "string",
"format": "int64"
},
"buffered": {
"type": "string",
"format": "int64"
},
"queued": {
"type": "string",
"format": "int64"
}
}
},
"PeerListFeature": {
"type": "string",
"enum": [
"UnknownFeature",
"WeshFeature",
"BLEFeature",
"LocalFeature",
"TorFeature",
"QuicFeature"
],
"default": "UnknownFeature"
},
"PeerListRoute": {
"type": "object",
"properties": {
"is_active": {
"type": "boolean",
"description": "IsActive indicates whether the address is currently used or just known."
},
"address": {
"type": "string",
"description": "Address is the multiaddress via which we are connected with the peer."
},
"direction": {
"$ref": "#/definitions/v1Direction",
"description": "Direction is which way the connection was established."
},
"latency": {
"type": "string",
"format": "int64",
"description": "Latency is the last known round trip time to the peer in ms."
},
"streams": {
"type": "array",
"items": {
"$ref": "#/definitions/PeerListStream"
},
"description": "Streams returns list of streams established with the peer."
}
}
},
"PeerListStream": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "id is an identifier used to write protocol headers in streams."
}
}
},
"ServiceGetConfigurationSettingState": {
"type": "string",
"enum": [
"Unknown",
"Enabled",
"Disabled",
"Unavailable"
],
"default": "Unknown"
},
"SystemInfoOrbitDB": {
"type": "object",
"properties": {
"account_metadata": {
"$ref": "#/definitions/OrbitDBReplicationStatus"
}
}
},
"SystemInfoP2P": {
"type": "object",
"properties": {
"connected_peers": {
"type": "string",
"format": "int64"
}
}
},
"SystemInfoProcess": {
"type": "object",
"properties": {
"version": {
"type": "string"
},
"vcs_ref": {
"type": "string"
},
"uptime_ms": {
"type": "string",
"format": "int64"
},
"user_cpu_time_ms": {
"type": "string",
"format": "int64"
},
"system_cpu_time_ms": {
"type": "string",
"format": "int64"
},
"started_at": {
"type": "string",
"format": "int64"
},
"rlimit_cur": {
"type": "string",
"format": "uint64"
},
"num_goroutine": {
"type": "string",
"format": "int64"
},
"nofile": {
"type": "string",
"format": "int64"
},
"too_many_open_files": {
"type": "boolean"
},
"num_cpu": {
"type": "string",
"format": "int64"
},
"go_version": {
"type": "string"
},
"operating_system": {
"type": "string"
},
"host_name": {
"type": "string"
},
"arch": {
"type": "string"
},
"rlimit_max": {
"type": "string",
"format": "uint64"
},
"pid": {
"type": "string",
"format": "int64"
},
"ppid": {
"type": "string",
"format": "int64"
},
"priority": {
"type": "string",
"format": "int64"
},
"uid": {
"type": "string",
"format": "int64"
},
"working_dir": {
"type": "string"
},
"system_username": {
"type": "string"
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"type_url": {
"type": "string"
},
"value": {
"type": "string",
"format": "byte"
}
}
},
"runtimeError": {
"type": "object",
"properties": {
"error": {
"type": "string"
},
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
},
"runtimeStreamError": {
"type": "object",
"properties": {
"grpc_code": {
"type": "integer",
"format": "int32"
},
"http_code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"http_status": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
},
"v1AccountVerifiedCredentialRegistered": {
"type": "object",
"properties": {
"device_pk": {
"type": "string",
"format": "byte",
"title": "device_pk is the public key of the device sending the message"
},
"signed_identity_public_key": {
"type": "string",
"format": "byte"
},
"verified_credential": {
"type": "string"
},
"registration_date": {
"type": "string",
"format": "int64"
},
"expiration_date": {
"type": "string",
"format": "int64"
},
"identifier": {
"type": "string"
},
"issuer": {
"type": "string"
}
}
},
"v1ActivateGroupReply": {
"type": "object"
},
"v1AppMessageSendReply": {
"type": "object",
"properties": {
"cid": {
"type": "string",
"format": "byte"
}
}
},
"v1AppMetadataSendReply": {
"type": "object",
"properties": {
"cid": {
"type": "string",
"format": "byte"
}
}
},
"v1ContactAliasKeySendReply": {
"type": "object"
},
"v1ContactBlockReply": {
"type": "object"
},
"v1ContactRequestAcceptReply": {
"type": "object"
},
"v1ContactRequestDisableReply": {
"type": "object"
},
"v1ContactRequestDiscardReply": {
"type": "object"
},
"v1ContactRequestEnableReply": {
"type": "object",
"properties": {
"public_rendezvous_seed": {
"type": "string",
"format": "byte",
"title": "public_rendezvous_seed is the rendezvous seed used by the current account"
}
}
},
"v1ContactRequestReferenceReply": {
"type": "object",
"properties": {
"public_rendezvous_seed": {
"type": "string",
"format": "byte",
"title": "public_rendezvous_seed is the rendezvous seed used by the current account"
},
"enabled": {
"type": "boolean",
"title": "enabled indicates if incoming contact requests are enabled"
}
}
},
"v1ContactRequestResetReferenceReply": {
"type": "object",
"properties": {
"public_rendezvous_seed": {
"type": "string",
"format": "byte",
"title": "public_rendezvous_seed is the rendezvous seed used by the current account"
}
}
},
"v1ContactRequestSendReply": {
"type": "object"
},
"v1ContactUnblockReply": {
"type": "object"
},
"v1CredentialVerificationServiceCompleteFlowReply": {
"type": "object",
"properties": {
"identifier": {
"type": "string"
}
}
},
"v1CredentialVerificationServiceInitFlowReply": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"secure_url": {
"type": "boolean"
}
}
},
"v1DeactivateGroupReply": {
"type": "object"
},
"v1DebugGroupReply": {
"type": "object",
"properties": {
"peer_ids": {
"type": "array",
"items": {
"type": "string"
},
"title": "peer_ids is the list of peer ids connected to the same group"
}
}
},
"v1DebugInspectGroupLogType": {
"type": "string",
"enum": [
"DebugInspectGroupLogTypeUndefined",
"DebugInspectGroupLogTypeMessage",
"DebugInspectGroupLogTypeMetadata"
],
"default": "DebugInspectGroupLogTypeUndefined"
},
"v1DebugInspectGroupStoreReply": {
"type": "object",
"properties": {
"cid": {
"type": "string",
"format": "byte",
"title": "cid is the CID of the IPFS log entry"
},
"parent_cids": {
"type": "array",
"items": {
"type": "string",
"format": "byte"
},
"title": "parent_cids is the list of the parent entries"
},
"metadata_event_type": {
"$ref": "#/definitions/v1EventType",
"title": "event_type metadata event type if subscribed to metadata events"
},
"device_pk": {
"type": "string",
"format": "byte",
"title": "device_pk is the public key of the device signing the entry"
},
"payload": {
"type": "string",
"format": "byte",
"title": "payload is the un encrypted entry payload if available"
}
}
},
"v1DebugListGroupsReply": {
"type": "object",
"properties": {
"group_pk": {
"type": "string",
"format": "byte",
"title": "group_pk is the public key of the group"
},
"group_type": {
"$ref": "#/definitions/v1GroupType",
"title": "group_type is the type of the group"
},
"contact_pk": {
"type": "string",
"format": "byte",
"title": "contact_pk is the contact public key if appropriate"
}
}
},
"v1DecodeContactReply": {
"type": "object",
"properties": {
"contact": {
"$ref": "#/definitions/v1ShareableContact",
"description": "shareable_contact is the decoded shareable contact."
}
}
},
"v1Direction": {
"type": "string",
"enum": [
"UnknownDir",
"InboundDir",
"OutboundDir",
"BiDir"
],
"default": "UnknownDir"
},
"v1EventContext": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "byte",
"title": "id is the CID of the underlying OrbitDB event"
},
"parent_ids": {
"type": "array",
"items": {
"type": "string",
"format": "byte"
},
"title": "id are the the CIDs of the underlying parents of the OrbitDB event"
},
"group_pk": {
"type": "string",
"format": "byte",
"title": "group_pk receiving the event"
}
},
"title": "EventContext adds context (its id, its parents and its attachments) to an event"
},
"v1EventType": {
"type": "string",
"enum": [
"EventTypeUndefined",
"EventTypeGroupMemberDeviceAdded",
"EventTypeGroupDeviceChainKeyAdded",
"EventTypeAccountGroupJoined",
"EventTypeAccountGroupLeft",
"EventTypeAccountContactRequestDisabled",
"EventTypeAccountContactRequestEnabled",
"EventTypeAccountContactRequestReferenceReset",
"EventTypeAccountContactRequestOutgoingEnqueued",
"EventTypeAccountContactRequestOutgoingSent",
"EventTypeAccountContactRequestIncomingReceived",
"EventTypeAccountContactRequestIncomingDiscarded",
"EventTypeAccountContactRequestIncomingAccepted",
"EventTypeAccountContactBlocked",
"EventTypeAccountContactUnblocked",
"EventTypeContactAliasKeyAdded",
"EventTypeMultiMemberGroupAliasResolverAdded",
"EventTypeMultiMemberGroupInitialMemberAnnounced",
"EventTypeMultiMemberGroupAdminRoleGranted",
"EventTypeGroupReplicating",
"EventTypeAccountVerifiedCredentialRegistered",
"EventTypeGroupMetadataPayloadSent"
],
"default": "EventTypeUndefined",
"title": "- EventTypeUndefined: EventTypeUndefined indicates that the value has not been set. Should not happen.\n - EventTypeGroupMemberDeviceAdded: EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group\n - EventTypeGroupDeviceChainKeyAdded: EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member\n - EventTypeAccountGroupJoined: EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group\n - EventTypeAccountGroupLeft: EventTypeAccountGroupLeft indicates the payload includes that the account has left a group\n - EventTypeAccountContactRequestDisabled: EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests\n - EventTypeAccountContactRequestEnabled: EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests\n - EventTypeAccountContactRequestReferenceReset: EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed\n - EventTypeAccountContactRequestOutgoingEnqueued: EventTypeAccountContactRequestOutgoingEnqueued indicates the payload includes that the account will attempt to send a new contact request\n - EventTypeAccountContactRequestOutgoingSent: EventTypeAccountContactRequestOutgoingSent indicates the payload includes that the account has sent a contact request\n - EventTypeAccountContactRequestIncomingReceived: EventTypeAccountContactRequestIncomingReceived indicates the payload includes that the account has received a contact request\n - EventTypeAccountContactRequestIncomingDiscarded: EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request\n - EventTypeAccountContactRequestIncomingAccepted: EventTypeAccountContactRequestIncomingAccepted indicates the payload includes that the account has accepted a contact request\n - EventTypeAccountContactBlocked: EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact\n - EventTypeAccountContactUnblocked: EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact\n - EventTypeContactAliasKeyAdded: EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key\n - EventTypeMultiMemberGroupAliasResolverAdded: EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof\n - EventTypeMultiMemberGroupInitialMemberAnnounced: EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner\n - EventTypeMultiMemberGroupAdminRoleGranted: EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin\n - EventTypeGroupReplicating: EventTypeGroupReplicating indicates that the group has been registered for replication on a server\n - EventTypeAccountVerifiedCredentialRegistered: EventTypeAccountVerifiedCredentialRegistered\n - EventTypeGroupMetadataPayloadSent: EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key"
},
"v1Group": {
"type": "object",
"properties": {
"public_key": {
"type": "string",
"format": "byte",
"title": "public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group"
},
"secret": {
"type": "string",
"format": "byte",
"title": "secret is the symmetric secret of the group, which is used to encrypt the metadata"
},
"secret_sig": {
"type": "string",
"format": "byte",
"title": "secret_sig is the signature of the secret used to ensure the validity of the group"
},
"group_type": {
"$ref": "#/definitions/v1GroupType",
"title": "group_type specifies the type of the group, used to determine how device chain key is generated"
},
"sign_pub": {
"type": "string",
"format": "byte",
"title": "sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided"
},
"link_key": {
"type": "string",
"format": "byte",
"title": "link_key is the secret key used to exchange group updates and links to attachments, useful for replication services"
},
"link_key_sig": {
"type": "string",
"format": "byte",
"title": "link_key_sig is the signature of the link_key using the group private key"
}
},
"title": "Group define a group and is enough to invite someone to it"
},
"v1GroupDeviceStatusReply": {
"type": "object",
"properties": {
"type": {
"$ref": "#/definitions/GroupDeviceStatusType"
},
"event": {
"type": "string",
"format": "byte"
}
}
},
"v1GroupInfoReply": {
"type": "object",
"properties": {
"group": {
"$ref": "#/definitions/v1Group",
"title": "group is the group invitation, containing the group pk and its type"
},
"member_pk": {
"type": "string",
"format": "byte",
"title": "member_pk is the identifier of the current member in the group"
},
"device_pk": {
"type": "string",
"format": "byte",
"title": "device_pk is the identifier of the current device in the group"
}
}
},
"v1GroupMessageEvent": {
"type": "object",
"properties": {
"event_context": {
"$ref": "#/definitions/v1EventContext",
"title": "event_context contains context information about the event"
},
"headers": {
"$ref": "#/definitions/v1MessageHeaders",
"title": "headers contains headers of the secure message"
},
"message": {
"type": "string",
"format": "byte",
"title": "message contains the secure message payload"
}
}
},
"v1GroupMetadata": {
"type": "object",
"properties": {
"event_type": {
"$ref": "#/definitions/v1EventType",
"title": "event_type defines which event type is used"
},
"payload": {
"type": "string",
"format": "byte",
"title": "the serialization depends on event_type, event is symmetrically encrypted"
},
"sig": {
"type": "string",
"format": "byte",
"title": "sig is the signature of the payload, it depends on the event_type for the used key"
},
"protocol_metadata": {
"$ref": "#/definitions/v1ProtocolMetadata",
"title": "protocol_metadata is protocol layer data"
}
},
"title": "GroupMetadata is used in GroupEnvelope and only readable by invited group members"
},
"v1GroupMetadataEvent": {
"type": "object",
"properties": {
"event_context": {
"$ref": "#/definitions/v1EventContext",
"title": "event_context contains context information about the event"
},
"metadata": {
"$ref": "#/definitions/v1GroupMetadata",
"title": "metadata contains the newly available metadata"
},
"event": {
"type": "string",
"format": "byte",
"title": "event_clear clear bytes for the event"
}
}
},
"v1GroupType": {
"type": "string",
"enum": [
"GroupTypeUndefined",
"GroupTypeAccount",
"GroupTypeContact",
"GroupTypeMultiMember"
],
"default": "GroupTypeUndefined",
"description": " - GroupTypeUndefined: GroupTypeUndefined indicates that the value has not been set. For example, happens if group is replicated.\n - GroupTypeAccount: GroupTypeAccount is the group managing an account, available to all its devices.\n - GroupTypeContact: GroupTypeContact is the group created between two accounts, available to all their devices.\n - GroupTypeMultiMember: GroupTypeMultiMember is a group containing an undefined number of members."
},
"v1MessageHeaders": {
"type": "object",
"properties": {
"counter": {
"type": "string",
"format": "uint64",
"title": "counter is the current counter value for the specified device"
},
"device_pk": {
"type": "string",
"format": "byte",
"title": "device_pk is the public key of the device sending the message"
},
"sig": {
"type": "string",
"format": "byte",
"title": "sig is the signature of the encrypted message using the device's private key"
},
"metadata": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"title": "metadata allow to pass custom informations"
}
},
"title": "MessageHeaders is used in MessageEnvelope and only readable by invited group members"
},
"v1MultiMemberGroupAdminRoleGrantReply": {
"type": "object"
},
"v1MultiMemberGroupAliasResolverDiscloseReply": {
"type": "object"
},
"v1MultiMemberGroupCreateReply": {
"type": "object",
"properties": {
"group_pk": {
"type": "string",
"format": "byte",
"title": "group_pk is the identifier of the newly created group"
}
}
},
"v1MultiMemberGroupInvitationCreateReply": {
"type": "object",
"properties": {
"group": {
"$ref": "#/definitions/v1Group",
"title": "group is the invitation to the group"
}
}
},
"v1MultiMemberGroupJoinReply": {
"type": "object"
},
"v1MultiMemberGroupLeaveReply": {
"type": "object"
},
"v1OutOfStoreMessage": {
"type": "object",
"properties": {
"cid": {
"type": "string",
"format": "byte"
},
"device_pk": {
"type": "string",
"format": "byte"
},
"counter": {
"type": "string",
"format": "uint64"
},
"sig": {
"type": "string",
"format": "byte"
},
"flags": {
"type": "integer",
"format": "int64"
},
"encrypted_payload": {
"type": "string",
"format": "byte"
},
"nonce": {
"type": "string",
"format": "byte"
}
}
},
"v1OutOfStoreReceiveReply": {
"type": "object",
"properties": {
"message": {
"$ref": "#/definitions/v1OutOfStoreMessage"
},
"cleartext": {
"type": "string",
"format": "byte"
},
"group_public_key": {
"type": "string",
"format": "byte"
},
"already_received": {
"type": "boolean"
}
}
},
"v1OutOfStoreSealReply": {
"type": "object",
"properties": {
"encrypted": {
"type": "string",
"format": "byte"
}
}
},
"v1PeerListPeer": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "id is the libp2p.PeerID."
},
"routes": {
"type": "array",
"items": {
"$ref": "#/definitions/PeerListRoute"
},
"description": "routes are the list of active and known maddr."
},
"errors": {
"type": "array",
"items": {
"type": "string"
},
"description": "errors is a list of errors related to the peer."
},
"features": {
"type": "array",
"items": {
"$ref": "#/definitions/PeerListFeature"
},
"description": "Features is a list of available features."
},
"min_latency": {
"type": "string",
"format": "int64",
"description": "MinLatency is the minimum latency across all the peer routes."
},
"is_active": {
"type": "boolean",
"description": "IsActive is true if at least one of the route is active."
},
"direction": {
"$ref": "#/definitions/v1Direction",
"description": "Direction is the aggregate of all the routes's direction."
}
}
},
"v1PeerListReply": {
"type": "object",
"properties": {
"peers": {
"type": "array",
"items": {
"$ref": "#/definitions/v1PeerListPeer"
}
}
}
},
"v1ProtocolMetadata": {
"type": "object"
},
"v1RefreshContactRequestPeer": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "id is the libp2p.PeerID."
},
"addrs": {
"type": "array",
"items": {
"type": "string"
},
"description": "list of peers multiaddrs."
}
}
},
"v1RefreshContactRequestReply": {
"type": "object",
"properties": {
"peers_found": {
"type": "array",
"items": {
"$ref": "#/definitions/v1RefreshContactRequestPeer"
},
"description": "peers found and successfully connected."
}
}
},
"v1ReplicationServiceRegisterGroupReply": {
"type": "object"
},
"v1ServiceExportDataReply": {
"type": "object",
"properties": {
"exported_data": {
"type": "string",
"format": "byte"
}
}
},
"v1ServiceGetConfigurationReply": {
"type": "object",
"properties": {
"account_pk": {
"type": "string",
"format": "byte",
"title": "account_pk is the public key of the current account"
},
"device_pk": {
"type": "string",
"format": "byte",
"title": "device_pk is the public key of the current device"
},
"account_group_pk": {
"type": "string",
"format": "byte",
"title": "account_group_pk is the public key of the account group"
},
"peer_id": {
"type": "string",
"title": "peer_id is the peer ID of the current IPFS node"
},
"listeners": {
"type": "array",
"items": {
"type": "string"
},
"title": "listeners is the list of swarm listening addresses of the current IPFS node"
},
"ble_enabled": {
"$ref": "#/definitions/ServiceGetConfigurationSettingState"
},
"wifi_p2p_enabled": {
"$ref": "#/definitions/ServiceGetConfigurationSettingState"
},
"mdns_enabled": {
"$ref": "#/definitions/ServiceGetConfigurationSettingState"
},
"relay_enabled": {
"$ref": "#/definitions/ServiceGetConfigurationSettingState"
}
}
},
"v1ShareContactReply": {
"type": "object",
"properties": {
"encoded_contact": {
"type": "string",
"format": "byte",
"description": "encoded_contact is the Protobuf encoding of the ShareableContact. You can further encode the bytes for sharing, such as base58 or QR code."
}
}
},
"v1ShareableContact": {
"type": "object",
"properties": {
"pk": {
"type": "string",
"format": "byte",
"title": "pk is the account to send a contact request to"
},
"public_rendezvous_seed": {
"type": "string",
"format": "byte",
"title": "public_rendezvous_seed is the rendezvous seed used by the account to send a contact request to"
},
"metadata": {
"type": "string",
"format": "byte",
"title": "metadata is the metadata specific to the app to identify the contact for the request"
}
}
},
"v1SystemInfoReply": {
"type": "object",
"properties": {
"process": {
"$ref": "#/definitions/SystemInfoProcess"
},
"p2p": {
"$ref": "#/definitions/SystemInfoP2P"
},
"orbitdb": {
"$ref": "#/definitions/SystemInfoOrbitDB"
},
"warns": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1VerifiedCredentialsListReply": {
"type": "object",
"properties": {
"credential": {
"$ref": "#/definitions/v1AccountVerifiedCredentialRegistered"
}
}
}
}
}
================================================
FILE: docs/architecture/2020-11-27-adr-berty-grpc-bridge.txt
================================================
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│service BridgeService { │
│ // CreateClient client a new bridge client │
│ rpc CreateClient (CreateClient.Request) returns (CreateClient.Reply); │
│ │
│ // ClientInvokeUnary invoke a unary method │
│ rpc ClientInvokeUnary (ClientInvokeUnary.Request) returns (ClientInvokeUnary.Reply); │
│ │
│ // CreateStream create a stream │
│ rpc CreateClientStream (ClientCreateStream.Request) returns (ClientCreateStream.Reply); │
│ │
│ // Send Message over the given stream │
│ rpc ClientStreamSend (ClientStreamSend.Request) returns (ClientStreamSend.Reply); │
│ │
│ // Recv message over the given stream │
│ rpc ClientStreamRecv (ClientStreamRecv.Request) returns (ClientStreamRecv.Reply); │
│ │
│ // Close the given stream │
│ rpc ClientStreamClose (ClientStreamClose.Request) returns (ClientStreamClose.Reply); │
│} │
└──────────────────────────────────────────────────────────────────────────────────────────┘
│
│
│
│
│
┌──────────────────────┘
│
│
┏━━━━━━┳───────────────┼────────────────────────────────────────────┐ ┏━━━━━━━━━━━━━━━━━━━━━━━━┳─────────────────────┐ ┏━━━━━━┳──────────────────────────────────────────────────────────────┐
┃ JS ┃ │ │ ┃ NATIVE (ios/android) ┃ │ ┃ Go ┃ │
┣━━━━━━┛ ◎ │ ┣━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┣━━━━━━┛ │
│ ┌──────────────────┐ ┌──────────────┐ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ ┌────────────┐ ┌────────────────┐ ┌──────────────────┐ │
│ │ │ │ RPC native │ │ │ ┌───────────────────────────────────────────┐│ │ │ │ │ │ │ │ │
│ │ Bridge Service │ │ Transport │ │ │ │ ││ │ │ Buffer │ │ ClientConn │ │ Bridge Service │ │
│ ┌─▶│ Client │────────▶│ (Unary Only) │──────────┼───────┼▶│InvokeMethod (Base64EncodedMessage: String)│├───────────┼───▶│ Listener │────▶│(Bridge Service)│────▶│ Server │──┐│
│ │ │ │ │ │ │ │ │ ││ │ │ │ │ │ │ │ ││
│ │ │ │ │ │ │ │ └───────────────────────────────────────────┘│ │ └────────────┘ └────────────────┘ └──────────────────┘ ││
│ │ │ │ │ │ │ │ │ │ ││
│ │ │ │ │ │ │ │ │ │ ││
│ │ └──────────────────┘ └──────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────┘│
│ │ │ │ │ │ │ │
│ └─────────────────────────────────────────────────┐ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ ┌──────────────┐ │ │ │ │ │ │ ┌────────────────┐ │
│ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ ┌──────────────────────┐ │ │ │ │ │ │ │ │ ┌──────────────────────┐ │
│ │ Messenger Service │ │ │ │ │ │ │ │ │ │ Messenger Service │ │
│ │ Client │────┐ │ │ │ │ │ │ │ │ ┌──────▶│ Server │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
│ └──────────────────────┘ │ │ │ │ │ │ │ │ │ │ └──────────────────────┘ │
│ ┌──────────────────────┐ │ │ Bridge │ │ │ │ │ │ │ │ ┌──────────────────────┐ │
│ │ Protocol Service │ │ │ Transport │ │ │ │ │ │GRPC ClientConn │ │ │ Protocol Service │ │
│ │ Client │────┼───▶│(Stream/Unary)│──┘ │ │ └─▶│(Mixed Services)│───────┼──────▶│ Server │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ └──────────────────────┘ │ │ │ │ │ │ │ │ └──────────────────────┘ │
│ ┌──────────────────────┐ │ │ │ │ │ │ │ │ ┌──────────────────────┐ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ ... │────┘ │ │ │ │ │ │ └──────▶│ ... │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ └──────────────────────┘ │ │ │ │ │ │ └──────────────────────┘ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ └──────────────┘ │ │ └────────────────┘ │
│ │ │ │
│ │ │ │
│ │ │ │
└───────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────┘
================================================
FILE: docs/architecture/2020-11-27-adr-gomobile-ipfs.md
================================================
# GomobileIPFS
## concept
### Driver
```
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ │ │ │ │ │
│ Native │ │ Init Driver │ │ Go │
│ (IOS/Android) │────────────▶│ │───────────▶│ │
│ │ │ │ │ │
└───────────────┘ └───────────────┘ └───────────────┘
│ │
│ │
│ │
│ ▼
│ ┌───────────────┐
│ │ │
│ implement │ Interface │
└─────────────────────────────────────────────────▶│ (Driver) │
│ │
└───────────────┘
```
- Go can call Native by calling **Driver** method directly
- Native can call Go Method with **Driver** `RegisterHandler` method
#### RegisterHandler example
_example from berty_
```go
// BackgroundTask
type BackgroundTaskHandlerDriver interface {
RegisterHandler(BackgroundTaskHandler)
}
type BackgroundTaskHandler interface {
HandleTask() LifeCycleBackgroundTask
}
type BackgroundTaskDriver interface {
Execute() (success bool)
}
```
[berty](https://github.com/berty/berty/blob/master/go/framework/bertynative/driver_lifecycle.go)
##### implement in swift
```swift
// BackgroundTaskDriver implement BackgroundTaskHandler
public class BackgroundTaskDriver: BackgroundTaskHandlerDriverProtocol {
let handler: BackgroundTaskHandlerProtocol
func registerHandler(handler: BackgroundTaskHandlerProtocol) {
self.handler = handler
}
func executeGoBackgroundTask() {
let success = self.handler.Execute()
}
}
```
[berty](https://github.com/berty/berty/blob/master/js/ios/Berty/Sources/LifeCycle.swift#L24)
##### Usage in gomobileipfs
user will then simply register the driver to ios background task system then pass it to go
```swift
// pseudo code below
// ...
backgroundDriver = BackgroundTaskDriver()
// user register
registerLifecycleBackgroundTaskToIOS("myapp.ios.background-task", backgroundDriver)
// go node init
let node = IPFSNode()
node.withBackgroundTaskDriver(backgroundDriver)
// ...
```
[berty](https://github.com/berty/berty/blob/master/js/ios/Berty/AppDelegate.m#L54)
### GomobileIPFS \w berty
```
╔════════╦━━━━━━━━━━━━━━━━┓ ┏╦═════════════╦━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
║ Berty ║ ┃ ┃║GomobileIPFS ║ ┃
╠════════╝ ┃ ┃╚═════════════╝ ┃
┃ ┃ ┃ ┃
┃ ┌────────────┐ ┃ ┃ ┌────────────┐ ┃
┃ │ │ ┃ ┃ │ │ ┃
┃ │ pkg │ ┃ ┃ │ pkg │ ┃
┃ │ │ ┃ ┃ │ │ ┃
┃ └────────────┘ ┃ ┃ └────────────┘ ┃
┃ │ ┃ ┃ │ ┃
┃ │ ┃ ┃ ┌──────────────────┴────────────────┐ ┃
┃ ▼ ┃ ┃ ▼ ▼ ┃
┃ ┌────────────┐ ┃ ┃ ┌────────────┐ ┌────────────┐ ┃
┃ │ │ ┃ ┃ │ │ │ │ ┃
┃ │ bridge │◀─────╋─import─╋────────│ driver │────────import─┐ │ node │ ┃
┃ │ │ ┃ ┃ │ │ │ │ │ ┃
┃ └────────────┘ ┃ ┃ └────────────┘ │ └────────────┘ ┃
┃ │ ┃ ┃ ▲ ▲ │ │ ┃
┃ │ ┃ ┃ │ │ │ └───────┐ ┃
┃ │ ┃ ┃ │ │ │ ▼ ┃
┃ │ ┃ ┃ │ │ │ ┌───────────┐ ┃
┃ │ ┃ ┃ │ │ │ │ │ ┃
┃ │ ┃ ┃ │ │ └──────────────▶│ bind │ ┃
┃ │ ┃ ┃ │ │ │ │ ┃
┃ │ ┃ ┃ │ │ └───────────┘ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ implement │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ gobind ┃ ┃ │ │ gobind ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ │ ┃ ┃ │ │ │ ┃
┃ ▼ ┃ ┃ │ │ ▼ ┃
┃ ┏━━━━━━━━━━━━┓ ┃ ┃ │ │ ┏━━━━━━━━━━━━┓ ┃
┃ ┃ Berty ┃ ┃ ┃ │ │ ┃GomobileIPFS┃ ┃
┃ ┃ Framework ┃──────╋────────╋────────────┘ └─────────────────────────────────┃ Framework ┃ ┃
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃
┃ ┗━━━━━━━━━━━━┛ ┃ ┃ ┗━━━━━━━━━━━━┛ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
```
================================================
FILE: docs/architecture/README.md
================================================
# Architecture
This folder mostly contains snapshots of the architecture at Berty, some documentations may be outdated, but reflect our feeling at a particular period of the project.
================================================
FILE: docs/architecture/messenger-mvp/README.md
================================================
# Berty Messenger MVP
## Reading linked graphs
### Account group/log back and forth ignored
Sending an event from the protocol to the app actually requires the app to subscribe to the account log, the protocol then adds the events it wants to send to the app on the account log. It was simplified by drawing an edge from the protocol to the app directly
## Contact request

================================================
FILE: docs/architecture/messenger-mvp/contact-request.mermaid
================================================
sequenceDiagram
participant aorbitdb as Alice orbitdb
participant aprotocol as Alice fake protocol
participant achat as Alice chat app
participant a as Alice
participant b as Bob
participant bchat as Bob chat app
participant bprotocol as Bob fake protocol
participant borbitdb as Bob orbitdb
a->>achat: Start app
achat->>aprotocol: Call contactRequestEnable command
aprotocol-->>aorbitdb: Subscribe to Alice rdv log
aprotocol->>achat: Send contactRequestEnabled event with reference
achat->>a: Display QR code with reference and Alice metadata
a->>b: Show/Send QR with Alice reference and contact metadata
b->>bchat: Scan QR with Alice reference and contact metadata
bchat-->> bprotocol: Subscribe to 1to1 group metadata
bprotocol-->> borbitdb: Subscribe to 1to1 group metadata log
bchat->>bprotocol: Call sendContactRequest command
bprotocol-->> bchat: Send contactRequestEnqueued event
bchat-->> b: Display an outgoing contact request
bprotocol->>borbitdb: Send Bob fake public key, 1to1 group fake public key and contact metadata on Alice rdv log
borbitdb->>aorbitdb: Alice rdv log replication
aorbitdb->>aprotocol: Send contact request with bob data from rdv log
aprotocol->>achat: Send contactRequestReceived event
achat->> a: Display contact request
a->> achat: Touch accept contact request
achat->> aprotocol: Call contactRequestAccept command
aprotocol->> aorbitdb: Send groupMemberDeviceAdded event on the 1to1 group metadata log
aorbitdb->>borbitdb: 1to1 group metadata log replication
borbitdb->> bprotocol: Send groupMemberDeviceAdded event from the 1to1 group metadata log
bprotocol->> bchat: Send groupMemberDeviceAdded event from the 1to1 group metadata
bchat->> b: Show that the request is accepted
================================================
FILE: docs/buf-doc.gen.yaml
================================================
version: v1
plugins:
- plugin: doc
out: ./
opt: markdown,api.md.tmp
- plugin: swagger
out: ./
opt:
- logtostderr=true
================================================
FILE: docs/gen.sum
================================================
10db4498e1b002bb5bbfeb67ec3ce4d259b35c3d Makefile
================================================
FILE: docs/ideas/distributed-entropy.md
================================================
# Distributed entropy
Date: 2019-05-24
Author: Antoine Eddi (aeddi)
## Description
The idea would be to exchange random data blocks between trusted devices (owned by the same account or by different contacts).
The exchange will take place during device-to-device handshakes, we could add a step to our handshake protocol to exchange 64 bytes of random data.
All the random data collected from different sources could be mixed up and stored securely so that it could be reused later to generate new cryptographic materials.
NB: It is obviously out of the question to use the data provided by a single peer without mixing it with data from other sources to generate secrets.
## Why?
A particular device could have an unsafe PRNG for some reason. Mixing random data provided by different devices should prevent an attack based on PNRG weaknesses specific to a particular device.
## To be considered
We don't know enough about the subject to assess whether it's a bad practice to do this kind of thing.
================================================
FILE: docs/ideas/entropy-pool.md
================================================
# Entropy pool
Date: 2019-05-24
Author: Manfred Touron (moul)
## Description
The idea would be to add to a pool random data blocks generated when the level of entropy provided by the OS or by dedicated hardware is at its highest.
Random data added to the pool could be reused later to generate new cryptographic materials.
We could ensure that the pool is built when the device is idle and its battery is fully charged.
For example, in the case of a phone: when it charges during the night.
## Why?
An attacker could lower the entropy level at some point and make the numbers generated predictable.
## To be considered
We don't know enough about the subject to assess whether it's a bad practice to do this kind of thing.
================================================
FILE: docs/protocol/README.md
================================================
# Wesh protocol
The Wesh protocol is documented at https://berty.tech/docs/protocol .
================================================
FILE: events.go
================================================
package weshnet
import (
"fmt"
cid "github.com/ipfs/go-cid"
"golang.org/x/crypto/nacl/secretbox"
"google.golang.org/protobuf/proto"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
var eventTypesMapper = map[protocoltypes.EventType]struct {
Message proto.Message
SigChecker sigChecker
}{
protocoltypes.EventType_EventTypeGroupMemberDeviceAdded: {Message: &protocoltypes.GroupMemberDeviceAdded{}, SigChecker: sigCheckerGroupMemberDeviceAdded},
protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded: {Message: &protocoltypes.GroupDeviceChainKeyAdded{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountGroupJoined: {Message: &protocoltypes.AccountGroupJoined{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountGroupLeft: {Message: &protocoltypes.AccountGroupLeft{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestDisabled: {Message: &protocoltypes.AccountContactRequestDisabled{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestEnabled: {Message: &protocoltypes.AccountContactRequestEnabled{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestReferenceReset: {Message: &protocoltypes.AccountContactRequestReferenceReset{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued: {Message: &protocoltypes.AccountContactRequestOutgoingEnqueued{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingSent: {Message: &protocoltypes.AccountContactRequestOutgoingSent{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived: {Message: &protocoltypes.AccountContactRequestIncomingReceived{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingDiscarded: {Message: &protocoltypes.AccountContactRequestIncomingDiscarded{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingAccepted: {Message: &protocoltypes.AccountContactRequestIncomingAccepted{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactBlocked: {Message: &protocoltypes.AccountContactBlocked{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountContactUnblocked: {Message: &protocoltypes.AccountContactUnblocked{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeContactAliasKeyAdded: {Message: &protocoltypes.ContactAliasKeyAdded{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeMultiMemberGroupAliasResolverAdded: {Message: &protocoltypes.MultiMemberGroupAliasResolverAdded{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeMultiMemberGroupInitialMemberAnnounced: {Message: &protocoltypes.MultiMemberGroupInitialMemberAnnounced{}, SigChecker: sigCheckerGroupSigned},
protocoltypes.EventType_EventTypeMultiMemberGroupAdminRoleGranted: {Message: &protocoltypes.MultiMemberGroupAdminRoleGranted{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeGroupMetadataPayloadSent: {Message: &protocoltypes.GroupMetadataPayloadSent{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeGroupReplicating: {Message: &protocoltypes.GroupReplicating{}, SigChecker: sigCheckerDeviceSigned},
protocoltypes.EventType_EventTypeAccountVerifiedCredentialRegistered: {Message: &protocoltypes.AccountVerifiedCredentialRegistered{}, SigChecker: sigCheckerDeviceSigned},
}
func newEventContext(eventID cid.Cid, parentIDs []cid.Cid, g *protocoltypes.Group) *protocoltypes.EventContext {
parentIDsBytes := make([][]byte, len(parentIDs))
for i, parentID := range parentIDs {
parentIDsBytes[i] = parentID.Bytes()
}
return &protocoltypes.EventContext{
Id: eventID.Bytes(),
ParentIds: parentIDsBytes,
GroupPk: g.PublicKey,
}
}
// FIXME(gfanton): getParentsCID use a lot of resources
// nolint:unused
func getParentsForCID(log ipfslog.Log, c cid.Cid) []cid.Cid {
if log == nil {
// TODO: this should not happen
return []cid.Cid{}
}
parent, ok := log.Get(c)
// Can't fetch parent entry
if !ok {
return []cid.Cid{}
}
nextEntries := parent.GetNext()
// Parent has only one or no parents, returning its id
if len(nextEntries) <= 1 {
return []cid.Cid{parent.GetHash()}
}
// Parent has more than one parent, returning parent entries
var ret []cid.Cid
for _, n := range nextEntries {
ret = append(ret, getParentsForCID(log, n)...)
}
return ret
}
func newGroupMetadataEventFromEntry(_ ipfslog.Log, e ipfslog.Entry, metadata *protocoltypes.GroupMetadata, event proto.Message, g *protocoltypes.Group) (*protocoltypes.GroupMetadataEvent, error) {
// TODO: if parent is a merge node we should return the next nodes of it
eventBytes, err := proto.Marshal(event)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization
}
// TODO(gfanton): getParentsCID use a lot of resources, disable it until we need it
// evtCtx := newEventContext(e.GetHash(), getParentsForCID(log, e.GetHash()), group, attachmentsCIDs)
evtCtx := newEventContext(e.GetHash(), []cid.Cid{}, g)
gme := protocoltypes.GroupMetadataEvent{
EventContext: evtCtx,
Metadata: metadata,
Event: eventBytes,
}
return &gme, nil
}
func openGroupEnvelope(g *protocoltypes.Group, envelopeBytes []byte) (*protocoltypes.GroupMetadata, proto.Message, error) {
env := &protocoltypes.GroupEnvelope{}
if err := proto.Unmarshal(envelopeBytes, env); err != nil {
return nil, nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
data, ok := secretbox.Open(nil, env.Event, nonce, g.GetSharedSecret())
if !ok {
return nil, nil, errcode.ErrCode_ErrGroupMemberLogEventOpen
}
metadataEvent := &protocoltypes.GroupMetadata{}
err = proto.Unmarshal(data, metadataEvent)
if err != nil {
return nil, nil, errcode.ErrCode_TODO.Wrap(err)
}
et, ok := eventTypesMapper[metadataEvent.EventType]
if !ok {
return nil, nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("event type not found"))
}
payload := proto.Clone(et.Message)
if err := proto.Unmarshal(metadataEvent.Payload, payload); err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if err := et.SigChecker(g, metadataEvent, payload); err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
return metadataEvent, payload, nil
}
func sealGroupEnvelope(g *protocoltypes.Group, eventType protocoltypes.EventType, payload proto.Message, payloadSig []byte) ([]byte, error) {
payloadBytes, err := proto.Marshal(payload)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
nonce, err := cryptoutil.GenerateNonce()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoNonceGeneration.Wrap(err)
}
event := &protocoltypes.GroupMetadata{
EventType: eventType,
Payload: payloadBytes,
Sig: payloadSig,
ProtocolMetadata: &protocoltypes.ProtocolMetadata{},
}
eventClearBytes, err := proto.Marshal(event)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
eventBytes := secretbox.Seal(nil, eventClearBytes, nonce, g.GetSharedSecret())
env := &protocoltypes.GroupEnvelope{
Event: eventBytes,
Nonce: nonce[:],
}
return proto.Marshal(env)
}
================================================
FILE: events_sig_checkers.go
================================================
package weshnet
import (
"github.com/libp2p/go-libp2p/core/crypto"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
type sigChecker func(g *protocoltypes.Group, metadata *protocoltypes.GroupMetadata, message proto.Message) error
func sigCheckerGroupSigned(g *protocoltypes.Group, metadata *protocoltypes.GroupMetadata, _ proto.Message) error {
pk, err := g.GetPubKey()
if err != nil {
return err
}
ok, err := pk.Verify(metadata.Payload, metadata.Sig)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
if !ok {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return nil
}
type eventDeviceSigned interface {
proto.Message
GetDevicePk() []byte
}
func sigCheckerDeviceSigned(_ *protocoltypes.Group, metadata *protocoltypes.GroupMetadata, message proto.Message) error {
msg, ok := message.(eventDeviceSigned)
if !ok {
return errcode.ErrCode_ErrDeserialization
}
devPK, err := crypto.UnmarshalEd25519PublicKey(msg.GetDevicePk())
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
ok, err = devPK.Verify(metadata.Payload, metadata.Sig)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
if !ok {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return nil
}
func sigCheckerGroupMemberDeviceAdded(g *protocoltypes.Group, metadata *protocoltypes.GroupMetadata, message proto.Message) error {
msg, ok := message.(*protocoltypes.GroupMemberDeviceAdded)
if !ok {
return errcode.ErrCode_ErrDeserialization
}
memPK, err := crypto.UnmarshalEd25519PublicKey(msg.MemberPk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
ok, err = memPK.Verify(msg.DevicePk, msg.MemberSig)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
if !ok {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return sigCheckerDeviceSigned(g, metadata, message)
}
================================================
FILE: gen.sum
================================================
78cfa180bfe8caf1572068cd6ea6bee4b89b3348 Makefile
================================================
FILE: go.mod
================================================
module berty.tech/weshnet/v2
go 1.22
toolchain go1.22.5
require (
berty.tech/go-ipfs-log v1.10.3-0.20240719141234-29e2d26e2aeb
berty.tech/go-ipfs-repo-encrypted v1.3.1-0.20240722095251-c6b363b38785
berty.tech/go-orbit-db v1.22.2-0.20240719144258-ec7d1faaca68
filippo.io/edwards25519 v1.0.0
github.com/aead/ecdh v0.2.0
github.com/berty/emitter-go v0.0.0-20221031144724-5dae963c3622
github.com/berty/go-libp2p-rendezvous v0.5.1
github.com/buicongtan1997/protoc-gen-swagger-config v0.0.0-20200705084907-1342b78c1a7e
github.com/daixiang0/gci v0.8.2
github.com/dgraph-io/badger/v2 v2.2007.3
github.com/gofrs/uuid v4.3.1+incompatible
github.com/golang/protobuf v1.5.4
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/hyperledger/aries-framework-go v0.1.9-0.20221202141134-083803ecf0a3
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/go-datastore v0.6.0
github.com/ipfs/go-ds-badger2 v0.1.3
github.com/ipfs/go-ipfs-keystore v0.1.0
github.com/ipfs/go-ipld-cbor v0.1.0
github.com/ipfs/go-log/v2 v2.5.1
github.com/ipfs/kubo v0.29.0
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b
github.com/libp2p/go-libp2p v0.34.1
github.com/libp2p/go-libp2p-kad-dht v0.25.2
github.com/libp2p/go-libp2p-pubsub v0.11.1-0.20240711152552-e508d8643ddb
github.com/libp2p/go-libp2p-testing v0.12.0
github.com/mdomke/git-semver/v5 v5.0.0
github.com/multiformats/go-multiaddr v0.12.4
github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/multiformats/go-multiaddr-fmt v0.1.0
github.com/multiformats/go-multibase v0.2.0
github.com/multiformats/go-multihash v0.2.3
github.com/piprate/json-gold v0.4.2
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.1
github.com/pseudomuto/protoc-gen-doc v1.5.1
github.com/srikrsna/protoc-gen-gotag v1.0.1
github.com/stretchr/testify v1.9.0
go.uber.org/goleak v1.3.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.24.0
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
google.golang.org/grpc v1.65.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
google.golang.org/grpc/examples v0.0.0-20200922230038-4e932bbcb079
google.golang.org/protobuf v1.34.2
moul.io/openfiles v1.2.0
moul.io/srand v1.6.1
moul.io/testman v1.5.0
moul.io/u v1.27.0
moul.io/zapfilter v1.7.0
moul.io/zapring v1.3.3
mvdan.cc/gofumpt v0.4.0
)
require (
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/DataDog/zstd v1.4.1 // indirect
github.com/Jorropo/jsync v1.0.1 // indirect
github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/VictoriaMetrics/fastcache v1.5.7 // indirect
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheggaaa/pb v1.0.29 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 // indirect
github.com/cskr/pubsub v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/ristretto v0.0.3 // indirect
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/eclipse/paho.mqtt.golang v1.4.2 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 // indirect
github.com/emicklei/proto v1.6.13 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 // indirect
github.com/google/tink/go v1.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/huin/goupnp v1.3.0 // indirect
github.com/hyperledger/aries-framework-go/spi v0.0.0-20221025204933-b807371b6f1e // indirect
github.com/hyperledger/ursa-wrapper-go v0.3.1 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs-shipyard/nopfs v0.0.12 // indirect
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/boxo v0.20.0 // indirect
github.com/ipfs/go-bitfield v1.1.0 // indirect
github.com/ipfs/go-block-format v0.2.0 // indirect
github.com/ipfs/go-blockservice v0.5.2 // indirect
github.com/ipfs/go-cidutil v0.1.0 // indirect
github.com/ipfs/go-ds-badger v0.3.0 // indirect
github.com/ipfs/go-ds-flatfs v0.5.1 // indirect
github.com/ipfs/go-ds-leveldb v0.5.0 // indirect
github.com/ipfs/go-ds-measure v0.2.0 // indirect
github.com/ipfs/go-ds-sql v0.3.0 // indirect
github.com/ipfs/go-fs-lock v0.0.7 // indirect
github.com/ipfs/go-ipfs-blockstore v1.3.1 // indirect
github.com/ipfs/go-ipfs-cmds v0.11.0 // indirect
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect
github.com/ipfs/go-ipfs-exchange-interface v0.2.1 // indirect
github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.3 // indirect
github.com/ipfs/go-ipld-format v0.6.0 // indirect
github.com/ipfs/go-ipld-git v0.1.1 // indirect
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect
github.com/ipfs/go-libipfs v0.6.2 // indirect
github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-merkledag v0.11.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
github.com/ipfs/go-unixfsnode v1.9.0 // indirect
github.com/ipfs/go-verifcid v0.0.3 // indirect
github.com/ipld/go-car v0.6.2 // indirect
github.com/ipld/go-car/v2 v2.13.1 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-doh-resolver v0.4.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
github.com/libp2p/go-libp2p-gostream v0.6.0 // indirect
github.com/libp2p/go-libp2p-http v0.5.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // indirect
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/lyft/protoc-gen-star/v2 v2.0.3 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/maruel/circular v0.0.0-20200815005550-36e533b830e9 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.8 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/miekg/dns v1.1.59 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/mutecomm/go-sqlcipher/v4 v4.4.2 // indirect
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 // indirect
github.com/onsi/ginkgo/v2 v2.17.3 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/openzipkin/zipkin-go v0.4.3 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect
github.com/peterbourgon/ff/v3 v3.0.0 // indirect
github.com/pion/datachannel v1.5.6 // indirect
github.com/pion/dtls/v2 v2.2.11 // indirect
github.com/pion/ice/v2 v2.3.24 // indirect
github.com/pion/interceptor v0.1.29 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.12 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.14 // indirect
github.com/pion/rtp v1.8.6 // indirect
github.com/pion/sctp v1.8.16 // indirect
github.com/pion/sdp/v3 v3.0.9 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect
github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.5 // indirect
github.com/pion/turn/v2 v2.1.6 // indirect
github.com/pion/webrtc/v3 v3.2.40 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.89.0 // indirect
github.com/pquerna/cachecontrol v0.1.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.15.0 // indirect
github.com/prometheus/statsd_exporter v0.22.7 // indirect
github.com/pseudomuto/protokit v0.2.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.44.0 // indirect
github.com/quic-go/webtransport-go v0.8.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rs/cors v1.10.1 // indirect
github.com/samber/lo v1.39.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 // indirect
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect
github.com/whyrusleeping/cbor-gen v0.1.1 // indirect
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 // indirect
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 // indirect
go.opentelemetry.io/otel/exporters/zipkin v1.26.0 // indirect
go.opentelemetry.io/otel/metric v1.26.0 // indirect
go.opentelemetry.io/otel/sdk v1.26.0 // indirect
go.opentelemetry.io/otel/trace v1.26.0 // indirect
go.opentelemetry.io/proto/otlp v1.2.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/fx v1.21.1 // indirect
go.uber.org/mock v0.4.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
moul.io/banner v1.0.1 // indirect
moul.io/motd v1.0.0 // indirect
)
================================================
FILE: go.sum
================================================
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc h1:utDghgcjE8u+EBjHOgYT+dJPcnDF05KqWMBcjuJy510=
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
berty.tech/go-ipfs-log v1.10.3-0.20240719141234-29e2d26e2aeb h1:FogPdtHCS/jQMX0iC9r/iQxVyYIFEpcoQvQrf6gxf0w=
berty.tech/go-ipfs-log v1.10.3-0.20240719141234-29e2d26e2aeb/go.mod h1:9iZx/jWL+Su7j5ALhljjKZN/QScM4ONGs7yqqlcb/Qg=
berty.tech/go-ipfs-repo-encrypted v1.3.1-0.20240722095251-c6b363b38785 h1:71O7eF4Hr22KKOk5y9Uzvt372siWoA55/DBj2DSbafA=
berty.tech/go-ipfs-repo-encrypted v1.3.1-0.20240722095251-c6b363b38785/go.mod h1:JjEWS7xkbCQAm2NFt2JKFg3wx2Qkgr2jBMHRAgkfU10=
berty.tech/go-orbit-db v1.22.2-0.20240719144258-ec7d1faaca68 h1:Y0TmVC11z+CQpQFoqyeOcrh/wgEIhbI/ZppfJOjuvDk=
berty.tech/go-orbit-db v1.22.2-0.20240719144258-ec7d1faaca68/go.mod h1:UoKTs3bAL3Q1eCwj2VKA/LFspSFbacNeZsUkxDh3S3Q=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.63.0/go.mod h1:GmezbQc7T2snqkEXWfZ0sy0VfkB/ivI2DdtJL2DEmlg=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg=
contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Jorropo/jsync v1.0.1 h1:6HgRolFZnsdfzRUj+ImB9og1JYOxQoReSywkHOGSaUU=
github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
github.com/aead/ecdh v0.2.0 h1:pYop54xVaq/CEREFEcukHRZfTdjiWvYIsZDXXrBapQQ=
github.com/aead/ecdh v0.2.0/go.mod h1:a9HHtXuSo8J1Js1MwLQx2mBhkXMT6YwUmVVEY4tTB8U=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs=
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM=
github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/berty/emitter-go v0.0.0-20221031144724-5dae963c3622 h1:kJqfCXKR5EJdh9HYh4rjYL3QvxjP5cnCssIU141m79c=
github.com/berty/emitter-go v0.0.0-20221031144724-5dae963c3622/go.mod h1:G66sIy+q6BKIoKoKNqFU7sxSnrS5d8Z8meQ3Iu0ZJ4o=
github.com/berty/go-libp2p-rendezvous v0.5.1 h1:6KnCOlyMIKAZq5COJeglWK5M8MhSJ2cKtMDf6x0KQm0=
github.com/berty/go-libp2p-rendezvous v0.5.1/go.mod h1:gNhPX2RnxaGHLKxj/hWiaQKR2TwYnKxjtFXoVhzUBYE=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buicongtan1997/protoc-gen-swagger-config v0.0.0-20200705084907-1342b78c1a7e h1:SHEegopzGCu0vkoUK98733r9TfviEO57VVPkYQ0G+WU=
github.com/buicongtan1997/protoc-gen-swagger-config v0.0.0-20200705084907-1342b78c1a7e/go.mod h1:NQIP/fdybt3yyAPo2/ew6pJYzUb1EWizEblXkQOu+TE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU=
github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo=
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 h1:ZFUue+PNxmHlu7pYv+IYMtqlaO/0VwaGEqKepZf9JpA=
github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=
github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=
github.com/daixiang0/gci v0.8.2 h1:4VLVDNdJ+wkXxz/nr5QRrbeK+JCvkMVqYjUWB5EnPF4=
github.com/daixiang0/gci v0.8.2/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
github.com/dgraph-io/badger/v2 v2.2007.3 h1:Sl9tQWz92WCbVSe8pj04Tkqlm2boW+KAxd+XSs58SQI=
github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/eclipse/paho.mqtt.golang v1.4.2 h1:66wOzfUHSSI1zamx7jR6yMEI5EuHnT1G6rNA5PM12m4=
github.com/eclipse/paho.mqtt.golang v1.4.2/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 h1:QV0ZrfBLpFc2KDk+a4LJefDczXnonRwrYrQJY/9L4dA=
github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE=
github.com/emicklei/proto v1.6.13 h1:8iuAuKbFmFhkmstObb0EV/Hrn9W+x6EuV1y5Da8Ye9E=
github.com/emicklei/proto v1.6.13/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI=
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI=
github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk=
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/hyperledger/aries-framework-go v0.1.9-0.20221202141134-083803ecf0a3 h1:r/jf1DTXG72uO5xK1VgZGywcjBlXh1E8kKnAt67bXJA=
github.com/hyperledger/aries-framework-go v0.1.9-0.20221202141134-083803ecf0a3/go.mod h1:5lp5+NPjRngsjFLYYGg5mtkvw6I4Mr7CKz+wHYxROk0=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20221025204933-b807371b6f1e h1:SxbXlF39661T9w/L9PhVdtbJfJ51Pm4JYEEW6XfZHEQ=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20221025204933-b807371b6f1e/go.mod h1:oryUyWb23l/a3tAP9KW+GBbfcfqp9tZD4y5hSkFrkqI=
github.com/hyperledger/ursa-wrapper-go v0.3.1 h1:Do+QrVNniY77YK2jTIcyWqj9rm/Yb5SScN0bqCjiibA=
github.com/hyperledger/ursa-wrapper-go v0.3.1/go.mod h1:nPSAuMasIzSVciQo22PedBk4Opph6bJ6ia3ms7BH/mk=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/ipfs-shipyard/nopfs v0.0.12 h1:mvwaoefDF5VI9jyvgWCmaoTJIJFAfrbyQV5fJz35hlk=
github.com/ipfs-shipyard/nopfs v0.0.12/go.mod h1:mQyd0BElYI2gB/kq/Oue97obP4B3os4eBmgfPZ+hnrE=
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7UynTbtdlt+w08ggb1UGLGaGjp1mMaZhoTZSctpn5Ak=
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
github.com/ipfs/boxo v0.20.0 h1:umUl7q1v5g5AX8FPLTnZBvvagLmT+V0Tt61EigP81ec=
github.com/ipfs/boxo v0.20.0/go.mod h1:mwttn53Eibgska2DhVIj7ln3UViq7MVHRxOMb+ehSDM=
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk=
github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8=
github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk=
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q=
github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA=
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro=
github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek=
github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg=
github.com/ipfs/go-ds-badger2 v0.1.3/go.mod h1:TPhhljfrgewjbtuL/tczP8dNrBYwwk+SdPYbms/NO9w=
github.com/ipfs/go-ds-flatfs v0.5.1 h1:ZCIO/kQOS/PSh3vcF1H6a8fkRGS7pOfwfPdx4n/KJH4=
github.com/ipfs/go-ds-flatfs v0.5.1/go.mod h1:RWTV7oZD/yZYBKdbVIFXTX2fdY2Tbvl94NsWqmoyAX4=
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
github.com/ipfs/go-ds-leveldb v0.5.0 h1:s++MEBbD3ZKc9/8/njrn4flZLnCuY9I79v94gBUNumo=
github.com/ipfs/go-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q=
github.com/ipfs/go-ds-measure v0.2.0 h1:sG4goQe0KDTccHMyT45CY1XyUbxe5VwTKpg2LjApYyQ=
github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9UvVh8V3JxE=
github.com/ipfs/go-ds-sql v0.3.0 h1:PLBbl0Rt0tBwWhQ0b3GCQbH+Bgd6aj2srKG6vJ7nYl4=
github.com/ipfs/go-ds-sql v0.3.0/go.mod h1:jE3bhmuUnMPXFftc4NEAiPUfgiwiv7fIdjozuX+m1/E=
github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U=
github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc=
github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ=
github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk=
github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8=
github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8=
github.com/ipfs/go-ipfs-cmds v0.11.0 h1:6AsTKwbVxwzrOkq2x89e6jYMGxzYqjt/WbAam69HZQE=
github.com/ipfs/go-ipfs-cmds v0.11.0/go.mod h1:DHp7YfJlOK+2IS07nk+hFmbKHK52tc29W38CaAgWHpk=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw=
github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo=
github.com/ipfs/go-ipfs-exchange-interface v0.2.1 h1:jMzo2VhLKSHbVe+mHNzYgs95n0+t0Q69GQ5WhRDZV/s=
github.com/ipfs/go-ipfs-exchange-interface v0.2.1/go.mod h1:MUsYn6rKbG6CTtsDp+lKJPmVt3ZrCViNyH3rfPGsZ2E=
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA=
github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s=
github.com/ipfs/go-ipfs-keystore v0.1.0 h1:gfuQUO/cyGZgZIHE6OrJas4OnwuxXCqJG7tI0lrB5Qc=
github.com/ipfs/go-ipfs-keystore v0.1.0/go.mod h1:LvLw7Qhnb0RlMOfCzK6OmyWxICip6lQ06CCmdbee75U=
github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8=
github.com/ipfs/go-ipfs-redirects-file v0.1.1/go.mod h1:tAwRjCV0RjLTjH8DR/AU7VYvfQECg+lpUy2Mdzv7gyk=
github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc=
github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo=
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0=
github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs=
github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs=
github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk=
github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U=
github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg=
github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y=
github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI=
github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk=
github.com/ipfs/go-ipld-legacy v0.2.1/go.mod h1:782MOUghNzMO2DER0FlBR94mllfdCJCkTtDtPM51otM=
github.com/ipfs/go-libipfs v0.6.2 h1:QUf3kS3RrCjgtE0QW2d18PFFfOLeEt24Ft892ipLzRI=
github.com/ipfs/go-libipfs v0.6.2/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8=
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g=
github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
github.com/ipfs/go-merkledag v0.11.0 h1:DgzwK5hprESOzS4O1t/wi6JDpyVQdvm9Bs59N/jqfBY=
github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4=
github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg=
github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU=
github.com/ipfs/go-unixfs v0.4.5 h1:wj8JhxvV1G6CD7swACwSKYa+NgtdWC1RUit+gFnymDU=
github.com/ipfs/go-unixfs v0.4.5/go.mod h1:BIznJNvt/gEx/ooRMI4Us9K8+qeGO7vx1ohnbk8gjFg=
github.com/ipfs/go-unixfsnode v1.9.0 h1:ubEhQhr22sPAKO2DNsyVBW7YB/zA8Zkif25aBvz8rc8=
github.com/ipfs/go-unixfsnode v1.9.0/go.mod h1:HxRu9HYHOjK6HUqFBAi++7DVoWAHn0o4v/nZ/VA+0g8=
github.com/ipfs/go-verifcid v0.0.3 h1:gmRKccqhWDocCRkC+a59g5QW7uJw5bpX9HWBevXa0zs=
github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw=
github.com/ipfs/kubo v0.29.0 h1:J5G5le0/gYkx8qLN/zxDl0LcEXKbHZyMh4FCuQN1nVo=
github.com/ipfs/kubo v0.29.0/go.mod h1:mLhuve/44BxEX5ujEihviRXiaxdlrja3kjJgEs2WhK0=
github.com/ipld/go-car v0.6.2 h1:Hlnl3Awgnq8icK+ze3iRghk805lu8YNq3wlREDTF2qc=
github.com/ipld/go-car v0.6.2/go.mod h1:oEGXdwp6bmxJCZ+rARSkDliTeYnVzv3++eXajZ+Bmr8=
github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4=
github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo=
github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc=
github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s=
github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b h1:FQ7+9fxhyp82ks9vAuyPzG0/vVbWwMwLJ+P6yJI5FN8=
github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b/go.mod h1:HMcgvsgd0Fjj4XXDkbjdmlbI505rUPBs6WBMYg2pXks=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 h1:kMJlf8z8wUcpyI+FQJIdGjAhfTww1y0AbQEv86bpVQI=
github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69/go.mod h1:tlkavyke+Ac7h8R3gZIjI5LKBcvMlSWnXNMgT3vZXo8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
github.com/libp2p/go-doh-resolver v0.4.0 h1:gUBa1f1XsPwtpE1du0O+nnZCUqtG7oYi7Bb+0S7FQqw=
github.com/libp2p/go-doh-resolver v0.4.0/go.mod h1:v1/jwsFusgsWIGX/c6vCRrnJ60x7bhTiq/fs2qt0cAg=
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
github.com/libp2p/go-libp2p v0.34.1 h1:fxn9vyLo7vJcXQRNvdRbyPjbzuQgi2UiqC8hEbn8a18=
github.com/libp2p/go-libp2p v0.34.1/go.mod h1:snyJQix4ET6Tj+LeI0VPjjxTtdWpeOhYt5lEY0KirkQ=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qkCnjyaZUPYU=
github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA=
github.com/libp2p/go-libp2p-http v0.5.0 h1:+x0AbLaUuLBArHubbbNRTsgWz0RjNTy6DJLOxQ3/QBc=
github.com/libp2p/go-libp2p-http v0.5.0/go.mod h1:glh87nZ35XCQyFsdzZps6+F4HYI6DctVFY5u1fehwSg=
github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ=
github.com/libp2p/go-libp2p-kad-dht v0.25.2/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo=
github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0=
github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0=
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
github.com/libp2p/go-libp2p-pubsub v0.11.1-0.20240711152552-e508d8643ddb h1:Ux/fNS52HowibmSbtEDzeKiu4N5gFklPv/1myFh/VVE=
github.com/libp2p/go-libp2p-pubsub v0.11.1-0.20240711152552-e508d8643ddb/go.mod h1:QEb+hEV9WL9wCiUAnpY29FZR6W3zK8qYlaml8R4q6gQ=
github.com/libp2p/go-libp2p-pubsub-router v0.6.0 h1:D30iKdlqDt5ZmLEYhHELCMRj8b4sFAqrUcshIUvVP/s=
github.com/libp2p/go-libp2p-pubsub-router v0.6.0/go.mod h1:FY/q0/RBTKsLA7l4vqC2cbRbOvyDotg8PJQ7j8FDudE=
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
github.com/libp2p/go-libp2p-routing-helpers v0.7.3 h1:u1LGzAMVRK9Nqq5aYDVOiq/HaB93U9WWczBzGyAC5ZY=
github.com/libp2p/go-libp2p-routing-helpers v0.7.3/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8=
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
github.com/libp2p/go-libp2p-xor v0.1.0 h1:hhQwT4uGrBcuAkUGXADuPltalOdpf9aag9kaYNT2tLA=
github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY=
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q=
github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o=
github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
github.com/maruel/circular v0.0.0-20200815005550-36e533b830e9 h1:d8OcZrg9dmqfBsHRDGP2QarJlj/1p0YI/NylTf2LYqo=
github.com/maruel/circular v0.0.0-20200815005550-36e533b830e9/go.mod h1:AEsb24YMiJiSqh8Cs8kRGJxDDXKEkveJ7nxYUeYibEc=
github.com/maruel/ut v1.0.2 h1:mQTlQk3jubTbdTcza+hwoZQWhzcvE4L6K6RTtAFlA1k=
github.com/maruel/ut v1.0.2/go.mod h1:RV8PwPD9dd2KFlnlCc/DB2JVvkXmyaalfc5xvmSrRSs=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdomke/git-semver/v5 v5.0.0 h1:By50HK/pTLR64WUUmDVtQNrVNDXsCehujhjBTAIyCHk=
github.com/mdomke/git-semver/v5 v5.0.0/go.mod h1:+f5KQvxYk4WbjLPgYujVa+97Gx0dbrc4fxIK7F6fRf0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU=
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc=
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc=
github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
github.com/multiformats/go-multiaddr-dns v0.3.0/go.mod h1:mNzQ4eTGDg0ll1N9jKPOUogZPoJ30W8a7zk66FQPpdQ=
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84=
github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=
github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA=
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/mutecomm/go-sqlcipher/v4 v4.4.2 h1:eM10bFtI4UvibIsKr10/QT7Yfz+NADfjZYh0GKrXUNc=
github.com/mutecomm/go-sqlcipher/v4 v4.4.2/go.mod h1:mF2UmIpBnzFeBdu/ypTDb/LdbS0nk0dfSN1WUsWTjMA=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 h1:28i1IjGcx8AofiB4N3q5Yls55VEaitzuEPkFJEVgGkA=
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk=
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw=
github.com/peterbourgon/ff/v3 v3.0.0 h1:eQzEmNahuOjQXfuegsKQTSTDbf4dNvr/eNLrmJhiH7M=
github.com/peterbourgon/ff/v3 v3.0.0/go.mod h1:UILIFjRH5a/ar8TjXYLTkIvSvekZqPm5Eb/qbGk6CT0=
github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg=
github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks=
github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI=
github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw=
github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M=
github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw=
github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA=
github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY=
github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE=
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo=
github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc=
github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4=
github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU=
github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY=
github.com/piprate/json-gold v0.4.2 h1:Rq8V+637HOFcj20KdTqW/g/llCwX2qtau0g5d1pD79o=
github.com/piprate/json-gold v0.4.2/go.mod h1:OK1z7UgtBZk06n2cDE2OSq1kffmjFFp5/2yhLLCz9UM=
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek=
github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk=
github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0=
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
github.com/pseudomuto/protoc-gen-doc v1.5.1 h1:Ah259kcrio7Ix1Rhb6u8FCaOkzf9qRBqXnvAufg061w=
github.com/pseudomuto/protoc-gen-doc v1.5.1/go.mod h1:XpMKYg6zkcpgfpCfQ8GcWBDRtRxOmMR5w7pz4Xo+dYM=
github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 h1:wD1IWQwAhdWclCwaf6DdzgCAe9Bfz1M+4AHRd7N786Y=
github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU=
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
github.com/srikrsna/protoc-gen-gotag v1.0.1 h1:zMDkplPjcpIOafgfXTD1BqCrMGycXcomV794MIKKi9s=
github.com/srikrsna/protoc-gen-gotag v1.0.1/go.mod h1:HiXK5kcp/ZRnNPahuJm3tzfGDoD8xzvLNdg5/PYKq7Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 h1:RBkacARv7qY5laaXGlF4wFB/tk5rnthhPb8oIBGoagY=
github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8/go.mod h1:9PdLyPiZIiW3UopXyRnPYyjUXSpiQNHRLu8fOsR3o8M=
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ=
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y=
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ=
github.com/whyrusleeping/cbor-gen v0.1.1 h1:eKfcJIoxivjMtwfCfmJAqSF56MHcWqyIScXwaC1VBgw=
github.com/whyrusleeping/cbor-gen v0.1.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 h1:ctS9Anw/KozviCCtK6VWMz5kPL9nbQzbQY4yfqlIV4M=
github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1/go.mod h1:tKH72zYNt/exx6/5IQO6L9LoQ0rEjd5SbbWaDTs9Zso=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 h1:1u/AyyOqAWzy+SkPxDpahCNZParHV8Vid1RnI2clyDE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0/go.mod h1:z46paqbJ9l7c9fIPCXTqTGwhQZ5XoTIsfeFYWboizjs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 h1:Waw9Wfpo/IXzOI8bCB7DIk+0JZcqqsyn1JFnAc+iam8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0/go.mod h1:wnJIG4fOqyynOnnQF/eQb4/16VlX2EJAHhHgqIqWfAo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 h1:0W5o9SzoR15ocYHEQfvfipzcNog1lBxOLfnex91Hk6s=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0/go.mod h1:zVZ8nz+VSggWmnh6tTsJqXQ7rU4xLwRtna1M4x5jq58=
go.opentelemetry.io/otel/exporters/zipkin v1.26.0 h1:sBk6A62GgcQRwcxcBwRMPkqeuSizcpHkXyZNyP281Fw=
go.opentelemetry.io/otel/exporters/zipkin v1.26.0/go.mod h1:fLzYtPUxPFzu7rSqhYsCxYheT2dNoPjtKovCLzLm07w=
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0=
go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks=
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/grpc/examples v0.0.0-20200922230038-4e932bbcb079 h1:unzgkDPNegIn/czOcgxzQaTzEzOiBH1V1j55rsEzVEg=
google.golang.org/grpc/examples v0.0.0-20200922230038-4e932bbcb079/go.mod h1:Lh55/1hxmVHEkOvSIQ2uj0P12QyOCUNyRwnUlSS13hw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
moul.io/banner v1.0.1 h1:+WsemGLhj2pOajw2eR5VYjLhOIqs0XhIRYchzTyMLk0=
moul.io/banner v1.0.1/go.mod h1:XwvIGKkhKRKyN1vIdmR5oaKQLIkMhkMqrsHpS94QzAU=
moul.io/godev v1.7.0/go.mod h1:5lgSpI1oH7xWpLl2Ew/Nsgk8DiNM6FzN9WV9+lgW8RQ=
moul.io/motd v1.0.0 h1:Trk4fPibDfPJf2iCBSQC8ws7Q02sMwivQdVEFAjCPto=
moul.io/motd v1.0.0/go.mod h1:39rvZ0lC2oRhHDY2VoPyZ8r70VKqeJye3QAxjeLDJso=
moul.io/openfiles v1.2.0 h1:oAmBX0ChBBsKERFfTRyLi9JkjOvEv9E474BEL/wVq44=
moul.io/openfiles v1.2.0/go.mod h1:FR9BZ1mw7VE0uZN6HVJcA16Ee2nTDG/YZUyiGM/T2Rw=
moul.io/srand v1.6.1 h1:SJ335F+54ivLdlH7wH52Rtyv0Ffos6DpsF5wu3ZVMXU=
moul.io/srand v1.6.1/go.mod h1:P2uaZB+GFstFNo8sEj6/U8FRV1n25kD0LLckFpJ+qvc=
moul.io/testman v1.5.0 h1:tN1XEzLxYh8ZYy1wET6leWufnTl7BcZELkSNiro/yEo=
moul.io/testman v1.5.0/go.mod h1:b4/5+lMsMDJtwuh25Cr0eVJ5Y4B2lSPfkzDtfct070g=
moul.io/u v1.6.0/go.mod h1:yd3/IoYRIJaZWAJV2rYHvM2EPp/Pp0zSNraB5IPX+hw=
moul.io/u v1.27.0 h1:rF0p184mludn2DzL0unA8Gf/mFWMBerdqOh8cyuQYzQ=
moul.io/u v1.27.0/go.mod h1:ggYDXxUjoHpfDsMPD3STqkUZTyA741PZiQhSd+7kRnA=
moul.io/zapfilter v1.7.0 h1:7aFrG4N72bDH9a2BtYUuUaDS981Dxu3qybWfeqaeBDU=
moul.io/zapfilter v1.7.0/go.mod h1:M+N2s+qZiA+bzRoyKMVRxyuERijS2ovi2pnMyiOGMvc=
moul.io/zapring v1.3.3 h1:N2QPn6qTMBWjh842UPxdjj2UW+uH/foXohgGCPZDlM8=
moul.io/zapring v1.3.3/go.mod h1:UvlTrdjeHtSqdjkGXwAxIfpaQ/ai4I+ccRASFxflcJE=
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
================================================
FILE: group.go
================================================
package weshnet
import (
"github.com/libp2p/go-libp2p/core/crypto"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const CurrentGroupVersion = 1
// NewGroupMultiMember creates a new Group object and an invitation to be used by
// the first member of the group
func NewGroupMultiMember() (*protocoltypes.Group, crypto.PrivKey, error) {
return protocoltypes.NewGroupMultiMember()
}
func getAndFilterGroupDeviceChainKeyAddedPayload(m *protocoltypes.GroupMetadata, localMemberPublicKey crypto.PubKey) (crypto.PubKey, []byte, error) {
if m == nil || m.EventType != protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded {
return nil, nil, errcode.ErrCode_ErrInvalidInput
}
s := &protocoltypes.GroupDeviceChainKeyAdded{}
if err := proto.Unmarshal(m.Payload, s); err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
senderDevicePubKey, err := crypto.UnmarshalEd25519PublicKey(s.DevicePk)
if err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
destMemberPubKey, err := crypto.UnmarshalEd25519PublicKey(s.DestMemberPk)
if err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if !localMemberPublicKey.Equals(destMemberPubKey) {
return nil, nil, errcode.ErrCode_ErrGroupSecretOtherDestMember
}
return senderDevicePubKey, s.Payload, nil
}
================================================
FILE: group_context.go
================================================
package weshnet
import (
"context"
"encoding/base64"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"berty.tech/go-orbit-db/stores"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
type GroupContext struct {
ctx context.Context
cancel context.CancelFunc
group *protocoltypes.Group
metadataStore *MetadataStore
messageStore *MessageStore
secretStore secretstore.SecretStore
ownMemberDevice secretstore.OwnMemberDevice
logger *zap.Logger
closed uint32
tasks sync.WaitGroup
devicesAdded map[string]chan struct{}
muDevicesAdded sync.RWMutex
selfAnnounced chan struct{}
selfAnnouncedOnce sync.Once
}
func (gc *GroupContext) SecretStore() secretstore.SecretStore {
return gc.secretStore
}
func (gc *GroupContext) MessageStore() *MessageStore {
return gc.messageStore
}
func (gc *GroupContext) MetadataStore() *MetadataStore {
return gc.metadataStore
}
func (gc *GroupContext) Group() *protocoltypes.Group {
return gc.group
}
func (gc *GroupContext) MemberPubKey() crypto.PubKey {
return gc.ownMemberDevice.Member()
}
func (gc *GroupContext) DevicePubKey() crypto.PubKey {
return gc.ownMemberDevice.Device()
}
func (gc *GroupContext) Close() error {
gc.cancel()
// @NOTE(gfanton): wait for active tasks to end, doing this we avoid to do
// some operations on a closed store
gc.tasks.Wait()
// mark group context has closed
atomic.StoreUint32(&gc.closed, 1)
// @FIXME(gfanton): should we really handle store closing here ?
gc.metadataStore.Close()
gc.messageStore.Close()
gc.logger.Debug("group context closed", zap.String("groupID", gc.group.GroupIDAsString()))
return nil
}
func (gc *GroupContext) IsClosed() bool {
return atomic.LoadUint32(&gc.closed) != 0
}
func NewContextGroup(group *protocoltypes.Group, metadataStore *MetadataStore, messageStore *MessageStore, secretStore secretstore.SecretStore, memberDevice secretstore.OwnMemberDevice, logger *zap.Logger) *GroupContext {
ctx, cancel := context.WithCancel(context.Background())
if logger == nil {
logger = zap.NewNop()
}
return &GroupContext{
ctx: ctx,
cancel: cancel,
group: group,
metadataStore: metadataStore,
messageStore: messageStore,
secretStore: secretStore,
ownMemberDevice: memberDevice,
logger: logger.With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(group.PublicKey)))),
closed: 0,
devicesAdded: make(map[string]chan struct{}),
selfAnnounced: make(chan struct{}),
}
}
func (gc *GroupContext) ActivateGroupContext(contactPK crypto.PubKey) (err error) {
ctx := gc.ctx
// start watching for GroupMetadataEvent to send secret and register
// chainkey of new members.
{
m := gc.MetadataStore()
sub, err := m.EventBus().Subscribe(new(*protocoltypes.GroupMetadataEvent))
if err != nil {
return fmt.Errorf("unable to subscribe to group metadata event: %w", err)
}
gc.tasks.Add(1)
go func() {
defer gc.tasks.Done() // ultimately, mark bg task has done
defer sub.Close()
for {
var evt any
select {
case <-ctx.Done():
return
case evt = <-sub.Out():
}
// @TODO(gfanton): should we handle this in a sub gorouting ?
e := evt.(*protocoltypes.GroupMetadataEvent)
// start := time.Now()
if err := gc.handleGroupMetadataEvent(e); err != nil {
gc.logger.Error("unable to handle EventTypeGroupDeviceSecretAdded", zap.Error(err))
}
// if t := time.Since(start).Milliseconds(); t > 0 {
// fmt.Printf("elapsed: %dms\n", t)
// }
}
}()
}
// send secret and register key from existing members.
// we should wait until all the events have been retrieved.
{
var wgExistingMembers sync.WaitGroup
wgExistingMembers.Add(2)
go func() {
start := time.Now()
gc.fillMessageKeysHolderUsingPreviousData()
wgExistingMembers.Done()
gc.logger.Info(fmt.Sprintf("FillMessageKeysHolderUsingPreviousData took %s", time.Since(start)))
}()
go func() {
start := time.Now()
gc.sendSecretsToExistingMembers(contactPK)
wgExistingMembers.Done()
gc.logger.Info(fmt.Sprintf("SendSecretsToExistingMembers took %s", time.Since(start)))
}()
wgExistingMembers.Wait()
}
start := time.Now()
op, err := gc.MetadataStore().AddDeviceToGroup(gc.ctx)
if err != nil {
return fmt.Errorf("unable to add device to groupo: %w", err)
}
gc.logger.Info(fmt.Sprintf("AddDeviceToGroup took %s", time.Since(start)))
if op != nil {
// Waiting for async events to be handled
select {
case <-ctx.Done():
return ctx.Err()
case <-gc.selfAnnounced: // device has been selfAnnounced
}
}
return nil
}
func (gc *GroupContext) handleGroupMetadataEvent(e *protocoltypes.GroupMetadataEvent) (err error) {
switch e.Metadata.EventType {
case protocoltypes.EventType_EventTypeGroupMemberDeviceAdded:
event := &protocoltypes.GroupMemberDeviceAdded{}
if err := proto.Unmarshal(e.Event, event); err != nil {
gc.logger.Error("unable to unmarshal payload", zap.Error(err))
}
memberPK, err := crypto.UnmarshalEd25519PublicKey(event.MemberPk)
if err != nil {
return fmt.Errorf("unable to unmarshal sender member pk: %w", err)
}
if memberPK.Equals(gc.ownMemberDevice.Member()) {
gc.selfAnnouncedOnce.Do(func() { close(gc.selfAnnounced) }) // mark has self announced
}
if _, err := gc.MetadataStore().SendSecret(gc.ctx, memberPK); err != nil {
if !errcode.Is(err, errcode.ErrCode_ErrGroupSecretAlreadySentToMember) {
return fmt.Errorf("unable to send secret to member: %w", err)
}
}
case protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded:
senderPublicKey, encryptedDeviceChainKey, err := getAndFilterGroupDeviceChainKeyAddedPayload(e.Metadata, gc.ownMemberDevice.Member())
switch err {
case nil: // ok
case errcode.ErrCode_ErrInvalidInput, errcode.ErrCode_ErrGroupSecretOtherDestMember:
// @FIXME(gfanton): should we log this ?
return nil
default:
return fmt.Errorf("an error occurred while opening device secrets: %w", err)
}
if err = gc.SecretStore().RegisterChainKey(gc.ctx, gc.Group(), senderPublicKey, encryptedDeviceChainKey); err != nil {
return fmt.Errorf("unable to register chain key: %w", err)
}
if rawPK, err := senderPublicKey.Raw(); err == nil {
// A new chainKey has been registered, notify watcher
go gc.notifyDeviceAdded(rawPK)
// process queued message and check if cached messages can be opened with it
gc.MessageStore().ProcessMessageQueueForDevicePK(gc.ctx, rawPK)
}
}
return nil
}
func (gc *GroupContext) fillMessageKeysHolderUsingPreviousData() {
publishedSecrets := gc.metadataStoreListSecrets()
for senderPublicKey, encryptedSecret := range publishedSecrets {
if err := gc.SecretStore().RegisterChainKey(gc.ctx, gc.Group(), senderPublicKey, encryptedSecret); err != nil {
gc.logger.Error("unable to register chain key", zap.Error(err))
continue
}
// A new chainKey is registered, check if cached messages can be opened with it
if rawPK, err := senderPublicKey.Raw(); err == nil {
gc.MessageStore().ProcessMessageQueueForDevicePK(gc.ctx, rawPK)
}
}
}
func (gc *GroupContext) metadataStoreListSecrets() map[crypto.PubKey][]byte {
publishedSecrets := map[crypto.PubKey][]byte{}
m := gc.MetadataStore()
metadatas, err := m.ListEvents(gc.ctx, nil, nil, false)
if err != nil {
return nil
}
for metadata := range metadatas {
if metadata == nil {
continue
}
pk, encryptedDeviceChainKey, err := getAndFilterGroupDeviceChainKeyAddedPayload(metadata.Metadata, gc.MemberPubKey())
if errcode.Is(err, errcode.ErrCode_ErrInvalidInput) || errcode.Is(err, errcode.ErrCode_ErrGroupSecretOtherDestMember) {
continue
}
if err != nil {
gc.logger.Error("unable to open chain key", zap.Error(err))
continue
}
publishedSecrets[pk] = encryptedDeviceChainKey
}
return publishedSecrets
}
func (gc *GroupContext) sendSecretsToExistingMembers(contact crypto.PubKey) {
members := gc.MetadataStore().ListMembers()
// Force sending secret to contact member in contact group
if gc.group.GroupType == protocoltypes.GroupType_GroupTypeContact && len(members) < 2 && contact != nil {
// Check if contact member is already listed
found := false
for _, member := range members {
if member.Equals(contact) {
found = true
}
}
// If not listed, add it to the list
if !found {
members = append(members, contact)
}
}
for _, pk := range members {
rawPK, err := pk.Raw()
if err != nil {
gc.logger.Error("failed to serialize pk", zap.Error(err))
continue
}
if _, err := gc.MetadataStore().SendSecret(gc.ctx, pk); err != nil {
if !errcode.Is(err, errcode.ErrCode_ErrGroupSecretAlreadySentToMember) {
gc.logger.Info("secret already sent secret to member", logutil.PrivateString("memberpk", base64.StdEncoding.EncodeToString(rawPK)))
continue
}
} else {
gc.logger.Info("sent secret to existing member", logutil.PrivateString("memberpk", base64.StdEncoding.EncodeToString(rawPK)))
}
}
}
func (gc *GroupContext) TagGroupContextPeers(ipfsCoreAPI ipfsutil.ExtendedCoreAPI, weight int) {
id := gc.Group().GroupIDAsString()
chSub1, err := gc.metadataStore.EventBus().Subscribe(new(stores.EventNewPeer))
if err != nil {
gc.logger.Warn("unable to subscribe to metadata event new peer")
return
}
chSub2, err := gc.messageStore.EventBus().Subscribe(new(stores.EventNewPeer))
if err != nil {
gc.logger.Warn("unable to subscribe to message event new peer")
return
}
go func() {
defer chSub1.Close()
defer chSub2.Close()
for {
var e any
select {
case e = <-chSub1.Out():
case e = <-chSub2.Out():
case <-gc.ctx.Done():
return
}
evt := e.(stores.EventNewPeer)
tag := fmt.Sprintf("grp_%s", id)
gc.logger.Debug("new peer of interest", logutil.PrivateStringer("peer", evt.Peer), zap.String("tag", tag), zap.Int("score", weight))
ipfsCoreAPI.ConnMgr().TagPeer(evt.Peer, tag, weight)
}
}()
}
func (gc *GroupContext) WaitForDeviceAdded(ctx context.Context, devicePK crypto.PubKey) (found chan struct{}) {
gc.muDevicesAdded.Lock()
defer gc.muDevicesAdded.Unlock()
rawpk, err := devicePK.Raw()
if err != nil {
gc.logger.Error("unable to get raw public key", zap.Error(err))
return
}
k := string(rawpk)
var ok bool
if found, ok = gc.devicesAdded[k]; ok {
return
}
groupPublicKey, err := gc.group.GetPubKey()
if err != nil {
gc.logger.Error("unable to get group public key", zap.Error(err))
return
}
found = make(chan struct{})
if gc.secretStore.IsChainKeyKnownForDevice(ctx, groupPublicKey, devicePK) {
close(found)
return
}
gc.devicesAdded[k] = found
return
}
func (gc *GroupContext) notifyDeviceAdded(dPK []byte) {
gc.muDevicesAdded.Lock()
k := string(dPK)
if cc, ok := gc.devicesAdded[k]; ok {
close(cc)
delete(gc.devicesAdded, k)
}
gc.muDevicesAdded.Unlock()
}
================================================
FILE: iface_account.go
================================================
package weshnet
import (
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
type AccountKeys interface {
AccountPrivKey() (crypto.PrivKey, error)
AccountProofPrivKey() (crypto.PrivKey, error)
DevicePrivKey() (crypto.PrivKey, error)
ContactGroupPrivKey(pk crypto.PubKey) (crypto.PrivKey, error)
MemberDeviceForGroup(g *protocoltypes.Group) (secretstore.OwnMemberDevice, error)
}
================================================
FILE: infra/.gitignore
================================================
!.env
================================================
FILE: infra/README.md
================================================
# How to Deploy Weshnet Infrastructure
This guide explains how to set up the essential services for a Weshnet network infrastructure, including rendez-vous points, emitter.io, and relay services.
## Prerequisites
Before starting the deployment, ensure you have the following tools installed on your system:
1. **Docker**: Required to run all services in containers
- For Ubuntu/Debian: `sudo apt update && sudo apt install docker.io docker-compose`
- For macOS: Download and install Docker Desktop from [docker.com](https://www.docker.com/products/docker-desktop)
- For Windows: Download and install Docker Desktop from [docker.com](https://www.docker.com/products/docker-desktop)
2. **Make**: Used to simplify deployment commands
- For Ubuntu/Debian: `sudo apt install make`
- For macOS: Install Xcode Command Line Tools with `xcode-select --install`
- For Windows: Install via [Chocolatey](https://chocolatey.org/) with `choco install make`
Verify installations with `docker --version` and `make --version`.
## Service Overview
Weshnet relies on three main components to facilitate peer-to-peer communication:
1. **Rendez-vous Point (RDVP)**: Acts as a meeting point for peers to discover each other on the network. It helps peers establish connections without needing to know each other's exact network location beforehand.
2. **Emitter.io**: Provides a pub/sub messaging system that allows peers to broadcast their presence and receive notifications about other peers. This service facilitates real-time communication and discovery within the network.
3. **Relay Service**: Helps peers connect when they're behind NATs or firewalls. It relays traffic between peers that cannot establish direct connections, ensuring connectivity even in challenging network environments.
## Rendez-vous Point and Emitter.io Services
### Setting Up Rendez-vous Point
1. Generate a new private key for the rendez-vous point service:
```sh
cd rdvp
docker run --rm --entrypoint rdvp bertytech/berty:kubo-v0.29.0 genkey
```
2. When the command completes, you'll receive a key in this format:
`CAESQHW91QjcGJN1RrIXtzCf8aC5EHCIB2Q+CSJ6KI68E7WLn49INScVKtToDjCMk4TxnncKWFcys59TjCgu8yBDOD8=`
3. Copy this key to the `RDVP_PK` variable in your `.env` file.
4. Add your public IP address to the `ANNOUNCE_SERVER` variable in the same file.
### Setting Up Emitter.io
1. Generate a license and secret key for emitter.io:
```sh
cd rdvp
docker run --rm emitter/server:v3.1
```
2. From the output, copy:
- The license to the `EMITTER_LICENSE` variable
- The secret key to the `EMITTER_SECRET_KEY` variable in your `.env` file
### Starting the Services
Once your configuration is complete, start both services with:
```sh
make up
```
### Configuring Your App to Use the Services
Print the multiaddress of the rendez-vous point service with:
```sh
docker compose logs rdvp | grep maddr
```
For mobile, you can prefer the "quic" multiaddress which looks something like `/ip4/51.15.25.200/udp/4040/quic-v1/p2p/12D3KooWPFQYmKg3KqZkeXyhwTBhpDu1cWNE8VruyxiMiroStNqh` .
To configure Berty Messenger, click the user icon to open Settings. Click Network. Click Rendezvous Point Nodes. Click the + to add a node.
To configure your Wesh app, create the service client with the `WithP2PRdvpMaddrs` option. For example:
```go
client1, err := weshnet.NewPersistentServiceClient("data1", weshnet.WithP2PRdvpMaddrs([]string{
"/ip4/51.15.25.200/udp/4040/quic-v1/p2p/12D3KooWPFQYmKg3KqZkeXyhwTBhpDu1cWNE8VruyxiMiroStNq",
}))
```
## Relay Service
The relay service facilitates peer connections through NATs and firewalls.
### Configuration and Deployment
1. Edit the relay configuration file:
- Open `relay/config.json`
- Update the `Network/AnnounceAddrs` section with your public IP address
2. Deploy your relay:
```sh
cd relay
make build # Build the relay Docker image
make up # Start the relay service
```
### Configuring Your App to Use the Service
Print the multiaddress of the relay service with:
```sh
docker compose logs relay | grep -A 3 "Public Addresses"
```
For mobile, you can prefer the "quic" multiaddress which looks something like `/ip4/51.15.25.200/udp/6363/quic/p2p/12D3KooWKjkkYVJg9RtQCiuV8bKheYB5sgVWSpo6LVyoRHtMZXCF` .
To configure Berty Messenger, click the user icon to open Settings. Click Network. Click Relay Nodes. Click the + to add a node.
To configure your Wesh app, create the service client with the `WithP2PStaticRelays` option. For example:
```go
client1, err := weshnet.NewPersistentServiceClient("data1", weshnet.WithP2PStaticRelays([]string{
"/ip4/51.15.25.200/udp/6363/quic/p2p/12D3KooWKjkkYVJg9RtQCiuV8bKheYB5sgVWSpo6LVyoRHtMZXCF",
}))
```
## Verifying Your Deployment
After deployment, you can verify your services are running correctly by checking:
- Logs for each service
- Network connectivity through the announced addresses
- Peer connections through your infrastructure
## Troubleshooting
If you encounter issues:
- Check that ports are properly forwarded on your network
- Verify your public IP is correctly configured in all services
- Ensure Docker has sufficient resources allocated
- Review service logs for specific error messages
================================================
FILE: infra/rdvp/.env
================================================
# Rendez-vous point public key
RDVP_PK=
# External IP address
ANNOUNCE_SERVER=
# Emitter.io secret key
EMITTER_SECRET_KEY=
# Emitter.io license key
EMITTER_LICENSE=
================================================
FILE: infra/rdvp/Makefile
================================================
.PHONY: all
all: up ps logs
up:
docker compose up -d
logs:
docker compose logs --tail=100 -f
down ps:
docker compose $@
genkey:
echo RDVP_PK=`docker compose run server genkey` > .env
ip:
curl ifconfig.co
================================================
FILE: infra/rdvp/docker-compose.yml
================================================
version: "3.7"
services:
rdvp:
image: bertytech/berty:kubo-v0.29.0
restart: on-failure
environment:
- RDVP_PK
- EMITTER_SECRET_KEY
network_mode: bridge
entrypoint: rdvp
links:
- emitter
expose:
- 8888
ports:
- 4040:4040
- 4040:4040/udp
command:
- serve
- "-log.format=json"
- "-log.filters=debug+:*"
- "--db=:memory:"
- "--pk=$RDVP_PK"
- "-metrics=:8888"
- "-l=/ip4/0.0.0.0/tcp/4040,/ip4/0.0.0.0/udp/4040/quic-v1"
- "-announce=/ip4/${ANNOUNCE_SERVER}/tcp/4040,/ip4/${ANNOUNCE_SERVER}/udp/4040/quic-v1"
- "-emitter-admin-key=$EMITTER_SECRET_KEY"
- "-emitter-public-addr=tcp://${ANNOUNCE_SERVER}:9494"
- "-emitter-server=tcp://emitter:9494"
emitter:
image: emitter/server:v3.1
container_name: emitter
restart: unless-stopped
network_mode: bridge
ports:
- 9494:9494
expose:
- 9494
# - 4000 # for cluster usage
environment:
- EMITTER_LICENSE
- EMITTER_LISTEN=:9494
================================================
FILE: infra/relay/Dockerfile
================================================
# builder
FROM golang:1.19-alpine3.16 as builder
MAINTAINER gfanton <8671905+gfanton@users.noreply.github.com>
ARG GIT_REPOS=https://github.com/libp2p/go-libp2p-relay-daemon.git
ARG GIT_TAG=v0.3.0
RUN apk add --no-cache git
RUN git clone --depth 1 --branch "${GIT_TAG}" "${GIT_REPOS}" /app
WORKDIR /app
RUN go build -o /go/bin/daemon -v -ldflags="-s -w" -v ./cmd/libp2p-relay-daemon
# runner
FROM alpine:3.16
COPY --from=builder /go/bin/daemon /usr/local/bin
ENTRYPOINT ["/usr/local/bin/daemon"]
================================================
FILE: infra/relay/Makefile
================================================
build:
tar -czh . | docker build -t relay - # need to tar because of the symlink
.PHONY: build
up:
docker compose up -d
logs:
docker compose logs --tail=100 -f
down ps:
docker compose $@
================================================
FILE: infra/relay/config.json
================================================
{
"RelayV2": {
"Enabled": true,
"Resources": {
"Limit": null
}
},
"RelayV1": {
"Enabled": true,
"Resources": {
"MaxCircuits": 2048,
"MaxCircuitsPerPeer": 128,
"BufferSize": 4096
}
},
"Network": {
"AnnounceAddrs": [
"/ip4//tcp/6363",
"/ip4//udp/6363/quic"
],
"ListenAddrs": [
"/ip4/0.0.0.0/udp/6363/quic",
"/ip6/::/udp/6363/quic",
"/ip4/0.0.0.0/tcp/6363",
"/ip6/::/tcp/6363"
]
}
}
================================================
FILE: infra/relay/docker-compose.yml
================================================
version: '3.7'
services:
relay:
image: relay
restart: on-failure
volumes:
- ./config.json:/etc/daemon-config.json
- ./data:/etc/daemon
command:
- -id=/etc/daemon/id.key
- -config=/etc/daemon-config.json
ports:
- 6363:6363
- 6363:6363/udp
================================================
FILE: internal/benchmark/benchmark_test.go
================================================
package benchmark
import (
"testing"
)
// BenchmarkScenario is a benchmark for the scenario
// FIXME: previous benchmark used Berty Messenger dependencies, we need to find a way to benchmark without them
func BenchmarkScenario(b *testing.B) {
}
================================================
FILE: internal/bertyversion/example_test.go
================================================
package bertyversion_test
================================================
FILE: internal/bertyversion/version.go
================================================
package bertyversion
var (
Version = "n/a"
VcsRef = "n/a"
)
================================================
FILE: internal/datastoreutil/consts.go
================================================
package datastoreutil
const (
NamespaceMessageKeystore = "messages_keystore"
)
================================================
FILE: internal/datastoreutil/datastore_namespaced.go
================================================
package datastoreutil
import (
ds "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/keytransform"
)
type namespacedDatastore struct {
ds.Batching
}
func (n *namespacedDatastore) Close() error {
// noop
return nil
}
func NewNamespacedDatastore(child ds.Datastore, prefix ds.Key) ds.Batching {
return &namespacedDatastore{Batching: keytransform.Wrap(child, keytransform.PrefixTransform{Prefix: prefix})}
}
================================================
FILE: internal/handshake/doc.go
================================================
// Package handshake implements a capability-based handshake.
//
// Handshake Sequence Diagram:
// ---------------------------
// Handshake vastely inspired by Scuttlebutt's Capability-based Handshake
// https://scuttlebot.io/more/protocols/shs.pdf
//
// - a, b are ephemeral key pairs generated by respectively Requester and
// Responder. Ephemeral keys are used for one handshake only and then
// discarded. They guarantee the freshness of the messages and avoid
// replay attacks.
//
// - A, B are the Account IDs of respectively Requester and Responder.
//
// - a.b denotes a secret derived from the two keys a and b.
//
// - | is the concatenation operator.
//
// - box[a.b](content) denotes the encryption of content using Nacl box
// with a.b as key.
//
// - sig[A](content) denotes the signature of content verified by A.
//
// +-----------+ +-----------+
// | Requester | | Responder |
// +-----------+ +-----------+
// | ---------------------\ |
// |-| 1. Requester Hello | |
// | |--------------------| |
// | |
// | a |
// |---------------------------------->|
// | ---------------------\ |
// | | 2. Responder Hello |-|
// | |--------------------| |
// | |
// | b |
// |<----------------------------------|
// | ----------------------------\ |
// |-| 3. Requester Authenticate | |
// | |---------------------------| |
// | |
// | box[a.b|a.B](A,sig[A](a.b)) |
// |---------------------------------->|
// | ----------------------\ |
// | | 4. Responder Accept |-|
// | |---------------------| |
// | |
// | box[a.b|A.B](sig[B](a.b)) |
// |<----------------------------------|
// | ---------------------------\ |
// |-| 5. Requester Acknowledge | |
// | |--------------------------| |
// | |
// | ok |
// |---------------------------------->|
// | |
//
// See the documentation at https://berty.tech/protocol for more information.
package handshake
================================================
FILE: internal/handshake/handshake.go
================================================
package handshake
import (
crand "crypto/rand"
"encoding/base64"
p2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
"golang.org/x/crypto/nacl/box"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/tyber"
)
// Constant nonces
var (
nonceRequesterAuthenticate = [cryptoutil.NonceSize]byte{1}
nonceResponderAccept = [cryptoutil.NonceSize]byte{2}
)
// Common struct and methods
type handshakeContext struct {
reader protoio.Reader
writer protoio.Writer
ownAccountID p2pcrypto.PrivKey
peerAccountID p2pcrypto.PubKey
ownEphemeral *[cryptoutil.KeySize]byte
peerEphemeral *[cryptoutil.KeySize]byte
sharedEphemeral *[cryptoutil.KeySize]byte
}
func (hc *handshakeContext) toTyberStepMutator() tyber.StepMutator {
return func(s tyber.Step) tyber.Step {
if hc == nil {
return s
}
if hc.peerAccountID != nil {
if cpkb, err := hc.peerAccountID.Raw(); err == nil {
s.Details = append(s.Details, tyber.Detail{Name: "ContactPublicKey", Description: base64.RawURLEncoding.EncodeToString(cpkb)})
}
}
for key, val := range map[string]*[cryptoutil.KeySize]byte{
"OwnEphemeral": hc.ownEphemeral,
"PeerEphemeral": hc.peerEphemeral,
"SharedEphemeral": hc.sharedEphemeral,
} {
if val != nil {
s.Details = append(s.Details, tyber.Detail{
Name: key,
Description: base64.RawURLEncoding.EncodeToString(val[:]),
})
}
}
return s
}
}
// Generates own Ephemeral key pair and send pub key to peer
func (hc *handshakeContext) generateOwnEphemeralAndSendPubKey() error {
// Generate own Ephemeral key pair
ownEphemeralPub, ownEphemeralPriv, err := box.GenerateKey(crand.Reader)
if err != nil {
return errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
// Set own Ephemeral priv key in Handshake Context
hc.ownEphemeral = ownEphemeralPriv
// Send own Ephemeral pub key to peer
hello := HelloPayload{EphemeralPubKey: ownEphemeralPub[:]}
if err := hc.writer.WriteMsg(&hello); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
return nil
}
// Receives peer's Ephemeral pub key
func (hc *handshakeContext) receivePeerEphemeralPubKey() error {
var err error
// Receive peer's Ephemeral pub key
hello := HelloPayload{}
if err := hc.reader.ReadMsg(&hello); err != nil {
return errcode.ErrCode_ErrStreamRead.Wrap(err)
}
// Set peer's Ephemeral pub key in Handshake Context
hc.peerEphemeral, err = cryptoutil.KeySliceToArray(hello.EphemeralPubKey)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
return nil
}
// Computes box key for step 3 (Requester Authenticate): box[a.b|a.B]
func (hc *handshakeContext) computeRequesterAuthenticateBoxKey(asRequester bool) (*[cryptoutil.KeySize]byte, error) {
var sharedReqEphemeralRespAccountID [cryptoutil.KeySize]byte
// If this function was called by the requester
if asRequester {
// Convert Ed25519 peer's AccountID key to X25519 key
mongPeerAccountID, err := cryptoutil.EdwardsToMontgomeryPub(hc.peerAccountID)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
// Compute shared key from own Ephemeral key and peer's AccountID key
box.Precompute(
&sharedReqEphemeralRespAccountID,
mongPeerAccountID,
hc.ownEphemeral,
)
} else {
// Convert Ed25519 own AccountID key to X25519 key
mongOwnAccountID, err := cryptoutil.EdwardsToMontgomeryPriv(hc.ownAccountID)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
// Compute shared key from peer's Ephemeral key and own AccountID key
box.Precompute(
&sharedReqEphemeralRespAccountID,
hc.peerEphemeral,
mongOwnAccountID,
)
}
// Concatenate both shared keys and hash them using sha256
boxKey := cryptoutil.ConcatAndHashSha256(
hc.sharedEphemeral[:],
sharedReqEphemeralRespAccountID[:],
)
return boxKey, nil
}
// Computes box key for step 4 (Responder Accept): box[a.b|A.B]
func (hc *handshakeContext) computeResponderAcceptBoxKey() (*[cryptoutil.KeySize]byte, error) {
var sharedAccountID [cryptoutil.KeySize]byte
// Convert Ed25519 AccountID keys to X25519 keys
mongOwnAccountID, mongPeerAccountID, err := cryptoutil.EdwardsToMontgomery(
hc.ownAccountID,
hc.peerAccountID,
)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
// Compute shared key from AccountID keys (X25519 converted)
box.Precompute(&sharedAccountID, mongPeerAccountID, mongOwnAccountID)
// Concatenate both shared keys and hash them using sha256
boxKey := cryptoutil.ConcatAndHashSha256(
hc.sharedEphemeral[:],
sharedAccountID[:],
)
return boxKey, nil
}
================================================
FILE: internal/handshake/handshake.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: handshake/handshake.proto
package handshake
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BoxEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Box []byte `protobuf:"bytes,1,opt,name=box,proto3" json:"box,omitempty"`
}
func (x *BoxEnvelope) Reset() {
*x = BoxEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_handshake_handshake_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BoxEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BoxEnvelope) ProtoMessage() {}
func (x *BoxEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_handshake_handshake_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BoxEnvelope.ProtoReflect.Descriptor instead.
func (*BoxEnvelope) Descriptor() ([]byte, []int) {
return file_handshake_handshake_proto_rawDescGZIP(), []int{0}
}
func (x *BoxEnvelope) GetBox() []byte {
if x != nil {
return x.Box
}
return nil
}
type HelloPayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
EphemeralPubKey []byte `protobuf:"bytes,1,opt,name=ephemeral_pub_key,json=ephemeralPubKey,proto3" json:"ephemeral_pub_key,omitempty"`
}
func (x *HelloPayload) Reset() {
*x = HelloPayload{}
if protoimpl.UnsafeEnabled {
mi := &file_handshake_handshake_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HelloPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HelloPayload) ProtoMessage() {}
func (x *HelloPayload) ProtoReflect() protoreflect.Message {
mi := &file_handshake_handshake_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HelloPayload.ProtoReflect.Descriptor instead.
func (*HelloPayload) Descriptor() ([]byte, []int) {
return file_handshake_handshake_proto_rawDescGZIP(), []int{1}
}
func (x *HelloPayload) GetEphemeralPubKey() []byte {
if x != nil {
return x.EphemeralPubKey
}
return nil
}
type RequesterAuthenticatePayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RequesterAccountId []byte `protobuf:"bytes,1,opt,name=requester_account_id,json=requesterAccountId,proto3" json:"requester_account_id,omitempty"`
RequesterAccountSig []byte `protobuf:"bytes,2,opt,name=requester_account_sig,json=requesterAccountSig,proto3" json:"requester_account_sig,omitempty"`
}
func (x *RequesterAuthenticatePayload) Reset() {
*x = RequesterAuthenticatePayload{}
if protoimpl.UnsafeEnabled {
mi := &file_handshake_handshake_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RequesterAuthenticatePayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RequesterAuthenticatePayload) ProtoMessage() {}
func (x *RequesterAuthenticatePayload) ProtoReflect() protoreflect.Message {
mi := &file_handshake_handshake_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RequesterAuthenticatePayload.ProtoReflect.Descriptor instead.
func (*RequesterAuthenticatePayload) Descriptor() ([]byte, []int) {
return file_handshake_handshake_proto_rawDescGZIP(), []int{2}
}
func (x *RequesterAuthenticatePayload) GetRequesterAccountId() []byte {
if x != nil {
return x.RequesterAccountId
}
return nil
}
func (x *RequesterAuthenticatePayload) GetRequesterAccountSig() []byte {
if x != nil {
return x.RequesterAccountSig
}
return nil
}
type ResponderAcceptPayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ResponderAccountSig []byte `protobuf:"bytes,1,opt,name=responder_account_sig,json=responderAccountSig,proto3" json:"responder_account_sig,omitempty"`
}
func (x *ResponderAcceptPayload) Reset() {
*x = ResponderAcceptPayload{}
if protoimpl.UnsafeEnabled {
mi := &file_handshake_handshake_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResponderAcceptPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResponderAcceptPayload) ProtoMessage() {}
func (x *ResponderAcceptPayload) ProtoReflect() protoreflect.Message {
mi := &file_handshake_handshake_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResponderAcceptPayload.ProtoReflect.Descriptor instead.
func (*ResponderAcceptPayload) Descriptor() ([]byte, []int) {
return file_handshake_handshake_proto_rawDescGZIP(), []int{3}
}
func (x *ResponderAcceptPayload) GetResponderAccountSig() []byte {
if x != nil {
return x.ResponderAccountSig
}
return nil
}
type RequesterAcknowledgePayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
}
func (x *RequesterAcknowledgePayload) Reset() {
*x = RequesterAcknowledgePayload{}
if protoimpl.UnsafeEnabled {
mi := &file_handshake_handshake_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RequesterAcknowledgePayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RequesterAcknowledgePayload) ProtoMessage() {}
func (x *RequesterAcknowledgePayload) ProtoReflect() protoreflect.Message {
mi := &file_handshake_handshake_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RequesterAcknowledgePayload.ProtoReflect.Descriptor instead.
func (*RequesterAcknowledgePayload) Descriptor() ([]byte, []int) {
return file_handshake_handshake_proto_rawDescGZIP(), []int{4}
}
func (x *RequesterAcknowledgePayload) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
var File_handshake_handshake_proto protoreflect.FileDescriptor
var file_handshake_handshake_proto_rawDesc = []byte{
0x0a, 0x19, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x2f, 0x68, 0x61, 0x6e, 0x64,
0x73, 0x68, 0x61, 0x6b, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x68, 0x61, 0x6e,
0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x22, 0x1f, 0x0a, 0x0b, 0x42, 0x6f, 0x78, 0x45, 0x6e, 0x76,
0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x6f, 0x78, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x03, 0x62, 0x6f, 0x78, 0x22, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x70, 0x68, 0x65, 0x6d,
0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62,
0x4b, 0x65, 0x79, 0x22, 0x84, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65,
0x72, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65,
0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x22, 0x4c, 0x0a, 0x16, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65,
0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x22, 0x37, 0x0a, 0x1b, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65,
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65,
0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
0x73, 0x42, 0x2a, 0x5a, 0x28, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f,
0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x2f, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_handshake_handshake_proto_rawDescOnce sync.Once
file_handshake_handshake_proto_rawDescData = file_handshake_handshake_proto_rawDesc
)
func file_handshake_handshake_proto_rawDescGZIP() []byte {
file_handshake_handshake_proto_rawDescOnce.Do(func() {
file_handshake_handshake_proto_rawDescData = protoimpl.X.CompressGZIP(file_handshake_handshake_proto_rawDescData)
})
return file_handshake_handshake_proto_rawDescData
}
var file_handshake_handshake_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_handshake_handshake_proto_goTypes = []any{
(*BoxEnvelope)(nil), // 0: handshake.BoxEnvelope
(*HelloPayload)(nil), // 1: handshake.HelloPayload
(*RequesterAuthenticatePayload)(nil), // 2: handshake.RequesterAuthenticatePayload
(*ResponderAcceptPayload)(nil), // 3: handshake.ResponderAcceptPayload
(*RequesterAcknowledgePayload)(nil), // 4: handshake.RequesterAcknowledgePayload
}
var file_handshake_handshake_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_handshake_handshake_proto_init() }
func file_handshake_handshake_proto_init() {
if File_handshake_handshake_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_handshake_handshake_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*BoxEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_handshake_handshake_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*HelloPayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_handshake_handshake_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*RequesterAuthenticatePayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_handshake_handshake_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*ResponderAcceptPayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_handshake_handshake_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*RequesterAcknowledgePayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_handshake_handshake_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_handshake_handshake_proto_goTypes,
DependencyIndexes: file_handshake_handshake_proto_depIdxs,
MessageInfos: file_handshake_handshake_proto_msgTypes,
}.Build()
File_handshake_handshake_proto = out.File
file_handshake_handshake_proto_rawDesc = nil
file_handshake_handshake_proto_goTypes = nil
file_handshake_handshake_proto_depIdxs = nil
}
================================================
FILE: internal/handshake/handshake_test.go
================================================
package handshake
import (
"context"
crand "crypto/rand"
"sync"
"testing"
"time"
p2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
p2pnetwork "github.com/libp2p/go-libp2p/core/network"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"golang.org/x/crypto/nacl/box"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/testutil"
)
// Request init a handshake with the responder
func Request(stream p2pnetwork.Stream, ownAccountID p2pcrypto.PrivKey, peerAccountID p2pcrypto.PubKey) error {
reader := protoio.NewDelimitedReader(stream, 2048)
writer := protoio.NewDelimitedWriter(stream)
return RequestUsingReaderWriter(context.TODO(), zap.NewNop(), reader, writer, ownAccountID, peerAccountID)
}
// Response handle the handshake inited by the requester
func Response(stream p2pnetwork.Stream, ownAccountID p2pcrypto.PrivKey) (p2pcrypto.PubKey, error) {
reader := protoio.NewDelimitedReader(stream, 2048)
writer := protoio.NewDelimitedWriter(stream)
return ResponseUsingReaderWriter(context.TODO(), zap.NewNop(), reader, writer, ownAccountID)
}
func TestValidHandshake(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.NoError(t, err, "handshake request failed")
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
peerAccountID, err := Response(stream, mh.responder.accountID)
require.NoError(t, err, "handshake response failed")
require.True(
t,
peerAccountID.Equals(mh.requester.accountID.GetPublic()),
"received peerAccountID by responder != requester's AccountID",
)
}
runHandshakeTest(t, requesterTest, responderTest)
}
func TestInvalidRequesterHello(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
t.Log("Requester interrupts by closing stream")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
_ *testing.T,
stream p2pnetwork.Stream,
_ *mockedHandshake,
) {
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Contains(t, errcode.Codes(err), errcode.ErrCode_ErrHandshakeRequesterHello)
require.Contains(t, errcode.Codes(err), errcode.ErrCode_ErrStreamRead)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
}
func TestInvalidResponderHello(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
t.Log("Responder interrupts by closing stream")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderHello, errcode.ErrCode_ErrHandshakePeerEphemeralKeyRecv, errcode.ErrCode_ErrStreamRead})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
}
func TestInvalidRequesterAuthenticate(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
t.Log("Requester interrupts by closing stream")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
// Interrupt step by closing stream
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.requester.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrStreamRead})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester sends invalid AccountID")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
// Send invalid AccountID
request.RequesterAccountId = []byte("NotAKey")
request.RequesterAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrDeserialization})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester sends another AccountID")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
// Send another AccountID
_, wrongAccountIDPub, err := p2pcrypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err, "wrongAccountID generation failed")
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(wrongAccountIDPub)
require.NoError(t, err, "wrongAccountID marshaling failed")
request.RequesterAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoSignatureVerification})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester signs with another AccountID")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(hc.ownAccountID.GetPublic())
require.NoError(t, err, "ownAccountID marshaling failed")
// Sign with another AccountID
wrongAccountID, _, err := p2pcrypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err, "wrongAccountID generation failed")
request.RequesterAccountSig, err = wrongAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoSignatureVerification})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester signs invalid proof")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(hc.ownAccountID.GetPublic())
require.NoError(t, err, "ownAccountID marshaling failed")
// Sign invalid proof
request.RequesterAccountSig, err = hc.ownAccountID.Sign([]byte("WrongProof"))
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoSignatureVerification})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester sends invalid request content")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
// Send invalid request content
requestBytes := []byte("WrongRequestContent")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrDeserialization})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester seals box using another key")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(hc.ownAccountID.GetPublic())
require.NoError(t, err, "ownAccountID marshaling failed")
request.RequesterAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
// Seal box using another key
wrongBoxKey := &[32]byte{}
crand.Read(wrongBoxKey[:])
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
wrongBoxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoDecrypt})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester seals using another nonce")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
var request RequesterAuthenticatePayload
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(hc.ownAccountID.GetPublic())
require.NoError(t, err, "ownAccountID marshaling failed")
request.RequesterAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
requestBytes, err := proto.Marshal(&request)
require.NoError(t, err, "request marshaling failed")
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
require.NoError(t, err, "Requester Authenticate box key gen failed")
// Seals using another nonce
wrongNonce, err := cryptoutil.GenerateNonce()
require.NoError(t, err, "nonce generation failed")
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
wrongNonce,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoDecrypt})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester sends invalid box content")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
// Send invalid box content
hc.writer.WriteMsg(&BoxEnvelope{Box: []byte("WrongBoxContent")})
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAuthenticate, errcode.ErrCode_ErrCryptoDecrypt})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
}
func TestInvalidResponderAccept(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
t.Log("Responder interrupts by closing stream")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrStreamRead})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder signs with another AccountID")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrCryptoSignatureVerification})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
var response ResponderAcceptPayload
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
// Sign with another AccountID
wrongAccountID, _, err := p2pcrypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err, "wrongAccountID generation failed")
response.ResponderAccountSig, err = wrongAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
responseBytes, err := proto.Marshal(&response)
require.NoError(t, err, "response marshaling failed")
boxKey, err := hc.computeResponderAcceptBoxKey()
require.NoError(t, err, "ResponderAccept Accept box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
&nonceResponderAccept,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder signs invalid proof")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrCryptoSignatureVerification})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
var response ResponderAcceptPayload
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
// Sign invalid proof
response.ResponderAccountSig, err = hc.ownAccountID.Sign([]byte("WrongProof"))
require.NoError(t, err, "sharedEphemeral signing failed")
responseBytes, err := proto.Marshal(&response)
require.NoError(t, err, "response marshaling failed")
boxKey, err := hc.computeResponderAcceptBoxKey()
require.NoError(t, err, "ResponderAccept Accept box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
&nonceResponderAccept,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder sends invalid response content")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrDeserialization})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
// Send invalid response content
responseBytes := []byte("WrongResponseContent")
boxKey, err := hc.computeResponderAcceptBoxKey()
require.NoError(t, err, "ResponderAccept Accept box key gen failed")
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
&nonceResponderAccept,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder seals box using another key")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrCryptoDecrypt})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
var response ResponderAcceptPayload
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
response.ResponderAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
responseBytes, err := proto.Marshal(&response)
require.NoError(t, err, "response marshaling failed")
// Seal box using another key
wrongBoxKey := &[32]byte{}
crand.Read(wrongBoxKey[:])
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
&nonceResponderAccept,
wrongBoxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder seals using another nonce")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrCryptoDecrypt})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
var response ResponderAcceptPayload
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
response.ResponderAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
require.NoError(t, err, "sharedEphemeral signing failed")
responseBytes, err := proto.Marshal(&response)
require.NoError(t, err, "response marshaling failed")
boxKey, err := hc.computeResponderAcceptBoxKey()
require.NoError(t, err, "ResponderAccept Accept box key gen failed")
// Seals using another nonce
wrongNonce, err := cryptoutil.GenerateNonce()
require.NoError(t, err, "nonce generation failed")
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
wrongNonce,
boxKey,
)
hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Responder sends invalid box content")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
defer ipfsutil.FullClose(stream)
err := Request(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeResponderAccept, errcode.ErrCode_ErrCryptoDecrypt})
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
hc := newTestHandshakeContext(stream, mh.responder.accountID, nil)
err := hc.receiveRequesterHello()
require.NoError(t, err, "receive RequesterHello failed")
err = hc.sendResponderHello()
require.NoError(t, err, "send ResponderHello failed")
err = hc.receiveRequesterAuthenticate()
require.NoError(t, err, "receive RequesterAuthenticate failed")
// Send wrong boxContent
hc.writer.WriteMsg(&BoxEnvelope{Box: []byte("WrongBoxContent")})
ipfsutil.FullClose(stream)
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
}
func TestInvalidResponderAcceptAck(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
t.Log("Requester interrupts by closing stream")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
err = hc.sendRequesterAuthenticate()
require.NoError(t, err, "send RequesterAuthenticate failed")
err = hc.receiveResponderAccept()
require.NoError(t, err, "receive ResponderAccept failed")
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAcknowledge, errcode.ErrCode_ErrStreamRead})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
t.Log("Requester sends acknowledge with: success == false")
{
start := time.Now()
var requesterTest requesterTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
) {
hc := newTestHandshakeContext(
stream,
mh.requester.accountID,
mh.responder.accountID.GetPublic(),
)
err := hc.sendRequesterHello()
require.NoError(t, err, "send RequesterHello failed")
err = hc.receiveResponderHello()
require.NoError(t, err, "receive ResponderHello failed")
err = hc.sendRequesterAuthenticate()
require.NoError(t, err, "send RequesterAuthenticate failed")
err = hc.receiveResponderAccept()
require.NoError(t, err, "receive ResponderAccept failed")
acknowledge := &RequesterAcknowledgePayload{Success: false}
hc.writer.WriteMsg(acknowledge)
ipfsutil.FullClose(stream)
}
var responderTest responderTestFunc = func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
) {
defer wg.Done()
defer ipfsutil.FullClose(stream)
_, err := Response(stream, mh.responder.accountID)
require.Equal(t, errcode.Codes(err), []errcode.ErrCode{errcode.ErrCode_ErrHandshakeRequesterAcknowledge, errcode.ErrCode_ErrInvalidInput})
}
runHandshakeTest(t, requesterTest, responderTest)
t.Logf("\tduration: %s", time.Since(start))
}
}
================================================
FILE: internal/handshake/handshake_util_test.go
================================================
package handshake
import (
"context"
crand "crypto/rand"
"sync"
"testing"
"time"
p2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
p2pnetwork "github.com/libp2p/go-libp2p/core/network"
p2ppeer "github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/tinder"
)
const testProtocolID = "/berty/handshake_test/1.0.0"
type mockedPeer struct {
accountID p2pcrypto.PrivKey
coreAPI ipfsutil.CoreAPIMock
peerInfo p2ppeer.AddrInfo
}
type mockedHandshake struct {
requester *mockedPeer
responder *mockedPeer
}
type requesterTestFunc func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
)
type responderTestFunc func(
t *testing.T,
stream p2pnetwork.Stream,
mh *mockedHandshake,
wg *sync.WaitGroup,
)
func newMockedPeer(t *testing.T, ctx context.Context, ipfsOpts *ipfsutil.TestingAPIOpts) *mockedPeer {
accountID, _, err := p2pcrypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err, "can't create new identity")
coreAPI := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsOpts)
peerInfo := coreAPI.MockNode().Peerstore.PeerInfo(coreAPI.MockNode().Identity)
return &mockedPeer{
accountID: accountID,
coreAPI: coreAPI,
peerInfo: peerInfo,
}
}
func newMockedHandshake(t *testing.T, ctx context.Context) *mockedHandshake {
t.Helper()
mn := mocknet.New()
t.Cleanup(func() { mn.Close() })
opts := &ipfsutil.TestingAPIOpts{
Mocknet: mn,
DiscoveryServer: tinder.NewMockDriverServer(),
}
requester := newMockedPeer(t, ctx, opts)
responder := newMockedPeer(t, ctx, opts)
// link responder & requester
err := opts.Mocknet.LinkAll()
require.NoError(t, err, "can't link peers")
// connect responder & requester
err = opts.Mocknet.ConnectAllButSelf()
require.NoError(t, err, "can't connect peers")
return &mockedHandshake{
requester: requester,
responder: responder,
}
}
func (mh *mockedHandshake) close(t *testing.T) {
t.Helper()
mh.requester.coreAPI.Close()
mh.responder.coreAPI.Close()
}
func newTestHandshakeContext(stream p2pnetwork.Stream, ownAccountID p2pcrypto.PrivKey, peerAccountID p2pcrypto.PubKey) *handshakeContext {
return &handshakeContext{
reader: protoio.NewDelimitedReader(stream, 2048),
writer: protoio.NewDelimitedWriter(stream),
ownAccountID: ownAccountID,
peerAccountID: peerAccountID,
sharedEphemeral: &[32]byte{},
}
}
func runHandshakeTest(t *testing.T, requesterTest requesterTestFunc, responderTest responderTestFunc) {
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
mh := newMockedHandshake(t, ctx)
defer mh.close(t)
mh.responder.coreAPI.MockNode().PeerHost.SetStreamHandler(
testProtocolID,
func(stream p2pnetwork.Stream) {
wg.Add(1)
responderTest(t, stream, mh, &wg)
},
)
stream, err := mh.requester.coreAPI.MockNode().PeerHost.NewStream(
ctx,
mh.responder.peerInfo.ID,
testProtocolID,
)
require.NoError(t, err, "requester can't dial responder")
requesterTest(t, stream, mh)
wg.Wait()
}
================================================
FILE: internal/handshake/request.go
================================================
package handshake
import (
"context"
"errors"
p2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"golang.org/x/crypto/nacl/box"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/tyber"
)
// RequestUsingReaderWriter init a handshake with the responder, using provided io reader and writer
func RequestUsingReaderWriter(ctx context.Context, logger *zap.Logger, reader protoio.Reader, writer protoio.Writer, ownAccountID p2pcrypto.PrivKey, peerAccountID p2pcrypto.PubKey) error {
hc := &handshakeContext{
reader: reader,
writer: writer,
ownAccountID: ownAccountID,
peerAccountID: peerAccountID,
sharedEphemeral: &[cryptoutil.KeySize]byte{},
}
// Handshake steps on requester side (see comments below)
if err := hc.sendRequesterHello(); err != nil {
return errcode.ErrCode_ErrHandshakeRequesterHello.Wrap(err)
}
tyber.LogStep(ctx, logger, "Sent hello", hc.toTyberStepMutator())
if err := hc.receiveResponderHello(); err != nil {
return errcode.ErrCode_ErrHandshakeResponderHello.Wrap(err)
}
tyber.LogStep(ctx, logger, "Received hello", hc.toTyberStepMutator())
if err := hc.sendRequesterAuthenticate(); err != nil {
return errcode.ErrCode_ErrHandshakeRequesterAuthenticate.Wrap(err)
}
tyber.LogStep(ctx, logger, "Sent authenticate", hc.toTyberStepMutator())
if err := hc.receiveResponderAccept(); err != nil {
return errcode.ErrCode_ErrHandshakeResponderAccept.Wrap(err)
}
tyber.LogStep(ctx, logger, "Received accept", hc.toTyberStepMutator())
if err := hc.sendRequesterAcknowledge(); err != nil {
return errcode.ErrCode_ErrHandshakeRequesterAcknowledge.Wrap(err)
}
tyber.LogStep(ctx, logger, "Sent acknowledge", hc.toTyberStepMutator())
return nil
}
// 1st step - Requester sends: a
func (hc *handshakeContext) sendRequesterHello() error {
if err := hc.generateOwnEphemeralAndSendPubKey(); err != nil {
return errcode.ErrCode_ErrHandshakeOwnEphemeralKeyGenSend.Wrap(err)
}
return nil
}
// 2nd step - Requester receives: b
func (hc *handshakeContext) receiveResponderHello() error {
if err := hc.receivePeerEphemeralPubKey(); err != nil {
return errcode.ErrCode_ErrHandshakePeerEphemeralKeyRecv.Wrap(err)
}
// Compute shared key from Ephemeral keys
box.Precompute(hc.sharedEphemeral, hc.peerEphemeral, hc.ownEphemeral)
return nil
}
// 3rd step - Requester sends: box[a.b|a.B](A,sig[A](a.b))
func (hc *handshakeContext) sendRequesterAuthenticate() error {
var (
request RequesterAuthenticatePayload
err error
)
// Set own AccountID pub key and proof (shared_a_b signed by own AccountID)
// in RequesterAuthenticatePayload message before marshaling it
request.RequesterAccountId, err = p2pcrypto.MarshalPublicKey(hc.ownAccountID.GetPublic())
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
request.RequesterAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
if err != nil {
return errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
requestBytes, err := proto.Marshal(&request)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
// Compute box key and seal marshaled RequesterAuthenticatePayload using
// constant nonce (see handshake.go)
boxKey, err := hc.computeRequesterAuthenticateBoxKey(true)
if err != nil {
return errcode.ErrCode_ErrHandshakeRequesterAuthenticateBoxKeyGen.Wrap(err)
}
boxContent := box.SealAfterPrecomputation(
nil,
requestBytes,
&nonceRequesterAuthenticate,
boxKey,
)
// Send BoxEnvelope to responder
if err = hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
return nil
}
// 4th step - Requester receives: box[a.b|A.B](sig[B](a.b))
func (hc *handshakeContext) receiveResponderAccept() error {
var (
boxEnvelope BoxEnvelope
response ResponderAcceptPayload
)
// Receive BoxEnvelope from responder
if err := hc.reader.ReadMsg(&boxEnvelope); err != nil {
return errcode.ErrCode_ErrStreamRead.Wrap(err)
}
// Compute box key and open marshaled RequesterAuthenticatePayload using
// constant nonce (see handshake.go)
boxKey, err := hc.computeResponderAcceptBoxKey()
if err != nil {
return errcode.ErrCode_ErrHandshakeResponderAcceptBoxKeyGen.Wrap(err)
}
respBytes, _ := box.OpenAfterPrecomputation(
nil,
boxEnvelope.Box,
&nonceResponderAccept,
boxKey,
)
if respBytes == nil {
err := errors.New("box opening failed")
return errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
// Unmarshal ResponderAcceptPayload
err = proto.Unmarshal(respBytes, &response)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
// Verify proof (shared_a_b signed by peer's AccountID)
valid, err := hc.peerAccountID.Verify(
hc.sharedEphemeral[:],
response.ResponderAccountSig,
)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
} else if !valid {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return nil
}
// 5th step - Requester sends: ok
func (hc *handshakeContext) sendRequesterAcknowledge() error {
acknowledge := &RequesterAcknowledgePayload{Success: true}
// Send Acknowledge to responder
if err := hc.writer.WriteMsg(acknowledge); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
return nil
}
================================================
FILE: internal/handshake/response.go
================================================
package handshake
import (
"context"
"errors"
p2pcrypto "github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"golang.org/x/crypto/nacl/box"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protoio"
"berty.tech/weshnet/v2/pkg/tyber"
)
// ResponseUsingReaderWriter handle the handshake inited by the requester, using provided io reader and writer
func ResponseUsingReaderWriter(ctx context.Context, logger *zap.Logger, reader protoio.Reader, writer protoio.Writer, ownAccountID p2pcrypto.PrivKey) (p2pcrypto.PubKey, error) {
hc := &handshakeContext{
reader: reader,
writer: writer,
ownAccountID: ownAccountID,
sharedEphemeral: &[cryptoutil.KeySize]byte{},
}
// Handshake steps on responder side (see comments below)
if err := hc.receiveRequesterHello(); err != nil {
return nil, errcode.ErrCode_ErrHandshakeRequesterHello.Wrap(err)
}
tyber.LogStep(ctx, logger, "Received hello", hc.toTyberStepMutator(), tyber.ForceReopen)
if err := hc.sendResponderHello(); err != nil {
return nil, errcode.ErrCode_ErrHandshakeResponderHello.Wrap(err)
}
tyber.LogStep(ctx, logger, "Sent hello", hc.toTyberStepMutator(), tyber.ForceReopen)
if err := hc.receiveRequesterAuthenticate(); err != nil {
return nil, errcode.ErrCode_ErrHandshakeRequesterAuthenticate.Wrap(err)
}
tyber.LogStep(ctx, logger, "Received authenticate", hc.toTyberStepMutator(), tyber.ForceReopen)
if err := hc.sendResponderAccept(); err != nil {
return nil, errcode.ErrCode_ErrHandshakeResponderAccept.Wrap(err)
}
tyber.LogStep(ctx, logger, "Sent accept", hc.toTyberStepMutator(), tyber.ForceReopen)
if err := hc.receiveRequesterAcknowledge(); err != nil {
return nil, errcode.ErrCode_ErrHandshakeRequesterAcknowledge.Wrap(err)
}
tyber.LogStep(ctx, logger, "Received acknowledge", hc.toTyberStepMutator(), tyber.ForceReopen)
return hc.peerAccountID, nil
}
// 1st step - Responder receives: a
func (hc *handshakeContext) receiveRequesterHello() error {
if err := hc.receivePeerEphemeralPubKey(); err != nil {
return errcode.ErrCode_ErrHandshakePeerEphemeralKeyRecv.Wrap(err)
}
return nil
}
// 2nd step - Responder sends: b
func (hc *handshakeContext) sendResponderHello() error {
if err := hc.generateOwnEphemeralAndSendPubKey(); err != nil {
return errcode.ErrCode_ErrHandshakeOwnEphemeralKeyGenSend.Wrap(err)
}
// Compute shared key from Ephemeral keys
box.Precompute(hc.sharedEphemeral, hc.peerEphemeral, hc.ownEphemeral)
return nil
}
// 3rd step - Responder receives: box[a.b|a.B](A,sig[A](a.b))
func (hc *handshakeContext) receiveRequesterAuthenticate() error {
var (
boxEnvelope BoxEnvelope
request RequesterAuthenticatePayload
)
// Receive BoxEnvelope from requester
if err := hc.reader.ReadMsg(&boxEnvelope); err != nil {
return errcode.ErrCode_ErrStreamRead.Wrap(err)
}
// Compute box key and open marshaled RequesterAuthenticatePayload using
// constant nonce (see handshake.go)
boxKey, err := hc.computeRequesterAuthenticateBoxKey(false)
if err != nil {
return errcode.ErrCode_ErrHandshakeRequesterAuthenticateBoxKeyGen.Wrap(err)
}
requestBytes, _ := box.OpenAfterPrecomputation(
nil,
boxEnvelope.Box,
&nonceRequesterAuthenticate,
boxKey,
)
if requestBytes == nil {
err := errors.New("box opening failed")
return errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
// Unmarshal RequesterAuthenticatePayload and RequesterAccountId
err = proto.Unmarshal(requestBytes, &request)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
hc.peerAccountID, err = p2pcrypto.UnmarshalPublicKey(request.RequesterAccountId)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
// Verify proof (shared_a_b signed by peer's AccountID)
valid, err := hc.peerAccountID.Verify(
hc.sharedEphemeral[:],
request.RequesterAccountSig,
)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
} else if !valid {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return nil
}
// 4th step - Responder sends: box[a.b|A.B](sig[B](a.b))
func (hc *handshakeContext) sendResponderAccept() error {
var (
response ResponderAcceptPayload
err error
)
// Set proof (shared_a_b signed by own AccountID) in ResponderAcceptPayload
// before marshaling it
response.ResponderAccountSig, err = hc.ownAccountID.Sign(hc.sharedEphemeral[:])
if err != nil {
return errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
responseBytes, err := proto.Marshal(&response)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
// Compute box key and seal marshaled ResponderAcceptPayload using
// constant nonce (see handshake.go)
boxKey, err := hc.computeResponderAcceptBoxKey()
if err != nil {
return errcode.ErrCode_ErrHandshakeResponderAcceptBoxKeyGen.Wrap(err)
}
boxContent := box.SealAfterPrecomputation(
nil,
responseBytes,
&nonceResponderAccept,
boxKey,
)
// Send BoxEnvelope to requester
if err = hc.writer.WriteMsg(&BoxEnvelope{Box: boxContent}); err != nil {
return errcode.ErrCode_ErrStreamWrite.Wrap(err)
}
return nil
}
// 5th step - Responder receives: ok
func (hc *handshakeContext) receiveRequesterAcknowledge() error {
var acknowledge RequesterAcknowledgePayload
// Receive Acknowledge from requester
if err := hc.reader.ReadMsg(&acknowledge); err != nil {
return errcode.ErrCode_ErrStreamRead.Wrap(err)
}
if !acknowledge.Success {
return errcode.ErrCode_ErrInvalidInput
}
return nil
}
================================================
FILE: internal/notify/notify.go
================================================
package notify
import (
"context"
"sync"
)
type Notify struct {
L sync.Locker
cc chan struct{}
mu sync.Mutex
}
func New(l sync.Locker) *Notify {
return &Notify{L: l}
}
func (n *Notify) getChan() <-chan struct{} {
n.mu.Lock()
defer n.mu.Unlock()
if n.cc == nil {
n.cc = make(chan struct{})
}
return n.cc
}
func (n *Notify) Wait(ctx context.Context) (ok bool) {
signal := n.getChan()
n.L.Unlock()
select {
case <-ctx.Done():
ok = false
case <-signal:
ok = true
}
n.L.Lock()
return
}
func (n *Notify) Broadcast() {
n.mu.Lock()
if n.cc != nil {
close(n.cc)
n.cc = nil
}
n.mu.Unlock()
}
================================================
FILE: internal/notify/notify_test.go
================================================
package notify
import (
"context"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNotify(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
locker := sync.Mutex{}
ntfy := New(&locker)
locker.Lock()
var ok bool = false
go func() {
locker.Lock()
assert.False(t, ok)
ok = true
ntfy.Broadcast()
locker.Unlock()
}()
ctxok := ntfy.Wait(ctx)
assert.True(t, ctxok)
assert.True(t, ok)
locker.Unlock()
}
func TestNotifyConcurrentWait(t *testing.T) {
const n = 200
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
locker := sync.Mutex{}
notify := New(&locker)
running := make(chan int, n)
awake := make(chan int, n)
for i := 0; i < n; i++ {
go func(g int) {
locker.Lock()
ok := true
for ok {
running <- g
ok = notify.Wait(ctx)
awake <- g
}
locker.Unlock()
}(i)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
<-running // Will deadlock unless n are running.
}
select {
case g := <-awake:
require.FailNow(t, "goroutine should be asleep", "goroutine #%d not asleep", g)
default:
}
locker.Lock()
if i == n-1 {
cancel()
} else {
notify.Broadcast()
}
locker.Unlock()
seen := make([]bool, n)
for j := 0; j < n; j++ {
g := <-awake
require.Falsef(t, seen[g], "goroutine #%d woke up twice", g)
seen[g] = true
}
}
select {
case g := <-running:
require.FailNow(t, "goroutine should not be running", "goroutine #%d still running", g)
default:
}
}
================================================
FILE: internal/queue/metrics.go
================================================
package queue
type MetricsTracer[T any] interface {
ItemQueued(name string, item T)
ItemPop(name string, item T)
}
var _ MetricsTracer[any] = (*noopTracer[any])(nil)
type noopTracer[T any] struct{}
// nolint:revive
func (*noopTracer[T]) ItemQueued(name string, item T) {}
// nolint:revive
func (*noopTracer[T]) ItemPop(name string, item T) {}
================================================
FILE: internal/queue/priority.go
================================================
package queue
import (
"container/heap"
"sync"
)
type ICounter interface {
Counter() uint64
}
// A priorityMessageQueue implements heap.Interface and holds Items.
type PriorityQueue[T ICounter] struct {
name string
metrics MetricsTracer[T]
items []T
muMessages sync.RWMutex
}
func NewPriorityQueue[T ICounter](name string, tracer MetricsTracer[T]) *PriorityQueue[T] {
queue := &PriorityQueue[T]{
name: name,
metrics: tracer,
items: []T{},
}
heap.Init(queue)
return queue
}
func (pq *PriorityQueue[T]) Add(m T) {
pq.muMessages.Lock()
heap.Push(pq, m)
pq.metrics.ItemQueued(pq.name, m)
pq.muMessages.Unlock()
}
func (pq *PriorityQueue[T]) NextAll(cb func(next T) error) error {
pq.muMessages.Lock()
defer pq.muMessages.Unlock()
for len(pq.items) > 0 {
item := heap.Pop(pq).(T)
if err := cb(item); err != nil {
return err
}
}
return nil
}
func (pq *PriorityQueue[T]) Next() (item T) {
pq.muMessages.Lock()
if len(pq.items) > 0 {
item = heap.Pop(pq).(T)
}
pq.muMessages.Unlock()
return
}
func (pq *PriorityQueue[T]) Size() (l int) {
pq.muMessages.RLock()
l = pq.Len()
pq.muMessages.RUnlock()
return
}
func (pq *PriorityQueue[T]) Len() (l int) {
l = len(pq.items)
return
}
func (pq *PriorityQueue[T]) Less(i, j int) bool {
// We want Pop to give us the lowest, not highest, priority so we use lower than here.
return pq.items[i].Counter() < pq.items[j].Counter()
}
func (pq *PriorityQueue[T]) Swap(i, j int) {
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
}
func (pq *PriorityQueue[T]) Push(x any) {
pq.items = append(pq.items, x.(T))
pq.metrics.ItemQueued(pq.name, x.(T))
}
func (pq *PriorityQueue[T]) Pop() (item any) {
var null T
if n := len(pq.items); n > 0 {
item = pq.items[n-1]
pq.metrics.ItemPop(pq.name, item.(T))
pq.items, pq.items[n-1] = pq.items[:n-1], null
}
return item
}
================================================
FILE: internal/queue/simple.go
================================================
package queue
import (
"container/list"
"context"
"sync"
)
type SimpleQueue[T any] struct {
name string
list *list.List
metrics MetricsTracer[T]
signal chan struct{}
mu sync.Mutex
}
func NewSimpleQueue[T any](name string, tracer MetricsTracer[T]) *SimpleQueue[T] {
return &SimpleQueue[T]{
name: name,
metrics: tracer,
list: list.New(),
signal: make(chan struct{}),
}
}
// Add pushes an item to the queue
func (q *SimpleQueue[T]) Add(m T) {
q.mu.Lock()
defer q.mu.Unlock()
_ = q.list.PushBack(m)
q.metrics.ItemQueued(q.name, m)
// signal that we got a new item
select {
case q.signal <- struct{}{}:
default:
}
}
// Pop removes and returns the first item from the queue.
// If the queue is empty, the second returned value will be false.
func (q *SimpleQueue[T]) Pop() (m T, ok bool) {
q.mu.Lock()
defer q.mu.Unlock()
if q.list.Len() > 0 {
element := q.list.Front()
q.list.Remove(element)
m = element.Value.(T)
ok = true
}
return
}
// WaitForItem blocks until a new item is available or the context is canceled.
// It returns the new item along with a boolean value indicating whether context has expired.
func (q *SimpleQueue[T]) WaitForItem(ctx context.Context) (item T, ok bool) {
q.mu.Lock()
defer q.mu.Unlock()
// Keep attempting to retrieve a new item until the context is canceled
for ctx.Err() == nil {
if q.list.Len() == 0 {
// queue is empty, wait for either a signal of a new item or a
// context cancellation
q.mu.Unlock()
select {
case <-q.signal:
case <-ctx.Done():
}
q.mu.Lock()
continue
}
// pop front item from the queue
element := q.list.Front()
q.list.Remove(element)
return element.Value.(T), true
}
return
}
================================================
FILE: internal/queue/simple_test.go
================================================
package queue
import (
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
)
type testSimpleQueue = *SimpleQueue[int]
func newTestSimpleQueue() testSimpleQueue {
return NewSimpleQueue[int]("test", &noopTracer[int]{})
}
func TestQueue(t *testing.T) {
queue := newTestSimpleQueue()
e, ok := queue.Pop()
require.Equal(t, 0, e)
require.False(t, ok)
queue.Add(1)
e, ok = queue.Pop()
require.Equal(t, 1, e)
require.True(t, ok)
e, ok = queue.Pop()
require.Equal(t, 0, e)
require.False(t, ok)
}
func TestSyncQueue(t *testing.T) {
cases := []struct{ N int }{
{1}, {10}, {100}, {1000}, {10000},
}
for _, tc := range cases {
name := fmt.Sprintf("%d_elements", tc.N)
t.Run(name, func(t *testing.T) {
queue := newTestSimpleQueue()
for i := 0; i < tc.N; i++ {
queue.Add(i + 1)
}
for i := 0; i < tc.N; i++ {
e, ok := queue.Pop()
require.Equal(t, i+1, e)
require.True(t, ok)
}
})
}
}
func TestAsyncQueue(t *testing.T) {
cases := []struct{ N int }{
{1}, {10}, {100}, {1000}, {10000},
}
for _, tc := range cases {
name := fmt.Sprintf("%d_elements", tc.N)
t.Run(name, func(t *testing.T) {
queue := newTestSimpleQueue()
wg := sync.WaitGroup{}
wg.Add(tc.N)
elems := map[int]struct{}{}
for i := 0; i < tc.N; i++ {
elems[i+1] = struct{}{}
go func(i int) {
queue.Add(i + 1)
wg.Done()
}(i)
}
wg.Wait()
for i := 0; i < tc.N; i++ {
e, ok := queue.Pop()
require.True(t, ok)
_, exist := elems[e]
require.True(t, exist)
delete(elems, e)
}
require.Len(t, elems, 0)
})
}
}
func TestWaitnForItemQueue(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cases := []struct{ N int }{
{1}, {10}, {100}, {1000}, {10000},
}
for _, tc := range cases {
name := fmt.Sprintf("%d_elements", tc.N)
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
queue := newTestSimpleQueue()
cc := make(chan int, tc.N)
go func() {
defer close(cc)
for {
e, ok := queue.WaitForItem(ctx)
if !ok {
return
}
cc <- e
}
}()
for i := 0; i < tc.N; i++ {
queue.Add(i + 1)
}
for i := 0; i < tc.N; i++ {
select {
case e := <-cc:
require.Equal(t, i+1, e)
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for event")
}
}
})
}
}
================================================
FILE: internal/sysutil/sysutil.go
================================================
package sysutil
import (
"os"
"runtime"
"syscall"
"go.uber.org/multierr"
"moul.io/openfiles"
"berty.tech/weshnet/v2/internal/bertyversion"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/username"
)
func SystemInfoProcess() (*protocoltypes.SystemInfo_Process, error) {
var errs error
// openfiles
nofile, nofileErr := openfiles.Count()
errs = multierr.Append(errs, nofileErr)
// hostname
hn, err := os.Hostname()
errs = multierr.Append(errs, err)
// working dir
wd, err := syscall.Getwd()
errs = multierr.Append(errs, err)
reply := protocoltypes.SystemInfo_Process{
Nofile: nofile,
TooManyOpenFiles: openfiles.IsTooManyError(nofileErr),
NumCpu: int64(runtime.NumCPU()),
GoVersion: runtime.Version(),
HostName: hn,
NumGoroutine: int64(runtime.NumGoroutine()),
OperatingSystem: runtime.GOOS,
Arch: runtime.GOARCH,
Version: bertyversion.Version,
VcsRef: bertyversion.VcsRef,
Pid: int64(syscall.Getpid()),
Uid: int64(syscall.Getuid()),
Ppid: int64(syscall.Getppid()),
WorkingDir: wd,
SystemUsername: username.GetUsername(),
}
// see sysutil_.go files
err = appendCustomSystemInfo(&reply)
errs = multierr.Append(errs, err)
return &reply, errs
}
================================================
FILE: internal/sysutil/sysutil_unix.go
================================================
//go:build linux || darwin
package sysutil
import (
"syscall"
"go.uber.org/multierr"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func appendCustomSystemInfo(reply *protocoltypes.SystemInfo_Process) error {
var errs error
// rlimit
rlimitNofile := syscall.Rlimit{}
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimitNofile)
errs = multierr.Append(errs, err)
reply.RlimitCur = rlimitNofile.Cur
reply.RlimitMax = rlimitNofile.Max
// rusage
rusage := syscall.Rusage{}
err = syscall.Getrusage(syscall.RUSAGE_SELF, &rusage)
errs = multierr.Append(errs, err)
reply.UserCpuTimeMs = int64(rusage.Utime.Sec*1000) + int64(rusage.Utime.Usec/1000) // nolint:unconvert // on some archs, those vars may be int32 instead of int64
reply.SystemCpuTimeMs = int64(rusage.Stime.Sec*1000) + int64(rusage.Stime.Usec/1000) // nolint:unconvert // on some archs, those vars may be int32 instead of int64
// process priority
prio, err := syscall.Getpriority(syscall.PRIO_PROCESS, 0)
errs = multierr.Append(errs, err)
reply.Priority = int64(prio)
return errs
}
================================================
FILE: internal/sysutil/sysutil_unsupported.go
================================================
//go:build !linux && !darwin
package sysutil
import "berty.tech/weshnet/v2/pkg/protocoltypes"
func appendCustomSystemInfo(reply *protocoltypes.SystemInfo_Process) error {
return nil
}
================================================
FILE: internal/tools/example_test.go
================================================
package tools_test
================================================
FILE: internal/tools/tools.go
================================================
//go:build tools
// Package tools ensures that `go mod` detect some required dependencies.
//
// This package should not be imported directly.
package tools
import (
// build tool
_ "github.com/buicongtan1997/protoc-gen-swagger-config"
// required by Makefile
_ "github.com/daixiang0/gci"
// required by protoc
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway"
// required by protoc
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger"
// required by Makefile
_ "github.com/mdomke/git-semver/v5"
// required by protoc
_ "github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc"
// required by protoc
_ "github.com/srikrsna/protoc-gen-gotag"
// required by protoc
_ "github.com/srikrsna/protoc-gen-gotag/tagger"
// required by protoc
_ "golang.org/x/tools/cmd/goimports"
// required by protoc
_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
// required by protoc
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
// required by protoc
_ "google.golang.org/protobuf/proto"
// required by Makefile
_ "moul.io/testman"
// required by Makefile
_ "mvdan.cc/gofumpt"
)
================================================
FILE: internal/tools/tools_untool.go
================================================
//go:build !tools
// Package tools ensures that `go mod` detect some required dependencies.
//
// This package should not be imported directly.
//
// This file is a noop to make `go list` happy.
package tools
================================================
FILE: message_marshaler.go
================================================
package weshnet
import (
"encoding/json"
"fmt"
"sync"
"github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
"google.golang.org/protobuf/proto"
"berty.tech/go-ipfs-log/enc"
"berty.tech/go-ipfs-log/entry"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/rendezvous"
"berty.tech/weshnet/v2/pkg/secretstore"
)
type PeerDeviceGroup struct {
Group *protocoltypes.Group
DevicePK crypto.PubKey
}
type OrbitDBMessageMarshaler struct {
rp *rendezvous.RotationInterval
sharedKeys map[string]enc.SharedKey
topicGroup map[string]*protocoltypes.Group
deviceCaches map[peer.ID]*PeerDeviceGroup
muMarshall sync.RWMutex
selfid peer.ID
secretStore secretstore.SecretStore
// in Replication Mode DeviceKey should not be sent
useReplicationMode bool
}
func NewOrbitDBMessageMarshaler(selfid peer.ID, secretStore secretstore.SecretStore, rp *rendezvous.RotationInterval, useReplicationMode bool) *OrbitDBMessageMarshaler {
return &OrbitDBMessageMarshaler{
selfid: selfid,
sharedKeys: make(map[string]enc.SharedKey),
deviceCaches: make(map[peer.ID]*PeerDeviceGroup),
topicGroup: make(map[string]*protocoltypes.Group),
rp: rp,
secretStore: secretStore,
useReplicationMode: useReplicationMode,
}
}
func (m *OrbitDBMessageMarshaler) RegisterSharedKeyForTopic(topic string, sk enc.SharedKey) {
m.muMarshall.Lock()
m.sharedKeys[topic] = sk
m.muMarshall.Unlock()
}
func (m *OrbitDBMessageMarshaler) RegisterGroup(sid string, group *protocoltypes.Group) {
m.muMarshall.Lock()
m.topicGroup[sid] = group
m.muMarshall.Unlock()
}
func (m *OrbitDBMessageMarshaler) GetDevicePKForPeerID(id peer.ID) (pdg *PeerDeviceGroup, ok bool) {
m.muMarshall.RLock()
pdg, ok = m.deviceCaches[id]
m.muMarshall.RUnlock()
return
}
func (m *OrbitDBMessageMarshaler) getSharedKeyFor(topic string) (sk enc.SharedKey, ok bool) {
sk, ok = m.sharedKeys[topic]
return
}
func (m *OrbitDBMessageMarshaler) Marshal(msg *iface.MessageExchangeHeads) ([]byte, error) {
topic := msg.Address
m.muMarshall.RLock()
defer m.muMarshall.RUnlock()
// marshall binary always return nil has error
pid, _ := m.selfid.MarshalBinary()
point, err := m.rp.PointForTopic(topic)
if err != nil {
return nil, fmt.Errorf("unable to get rendezvous for period: %w", err)
}
group, ok := m.topicGroup[topic]
if !ok {
return nil, fmt.Errorf("unknown group for topic: %s", topic)
}
var ownPK []byte
// in replication mode, it doesn't make sense to send DevicePK
if !m.useReplicationMode {
ownDevice, err := m.secretStore.GetOwnMemberDeviceForGroup(group)
if err != nil {
return nil, fmt.Errorf("unable to get own member device key for group: %w", err)
}
ownPK, err = ownDevice.Device().Raw()
if err != nil {
return nil, fmt.Errorf("unable to get raw pk for device: %w", err)
}
}
// @TODO(gfanton): use protobuf for this ?
heads, err := json.Marshal(msg.Heads)
if err != nil {
return nil, fmt.Errorf("unable to marshal heads: %w", err)
}
box := &protocoltypes.OrbitDBMessageHeads_Box{
Address: msg.Address,
Heads: heads,
DevicePk: ownPK,
PeerId: pid,
}
sealedBox, err := m.sealBox(msg.Address, box)
if err != nil {
return nil, fmt.Errorf("unable to seal box: %w", err)
}
msghead := protocoltypes.OrbitDBMessageHeads{
RawRotation: point.RawRotationTopic(),
SealedBox: sealedBox,
}
payload, err := proto.Marshal(&msghead)
if err != nil {
return nil, fmt.Errorf("unable to marshal payload: %w", err)
}
return payload, nil
}
func (m *OrbitDBMessageMarshaler) Unmarshal(payload []byte, msg *iface.MessageExchangeHeads) error {
m.muMarshall.Lock()
defer m.muMarshall.Unlock()
if msg == nil {
msg = &iface.MessageExchangeHeads{}
}
msghead := protocoltypes.OrbitDBMessageHeads{}
if err := proto.Unmarshal(payload, &msghead); err != nil {
return fmt.Errorf("unable to unmarshal payload `%x`: %w", payload, err)
}
rotation := msghead.GetRawRotation()
point, err := m.rp.PointForRawRotation(rotation)
if err != nil {
return fmt.Errorf("unable to get topic for rendezvous: %w", err)
}
box, err := m.openBox(point.Topic(), msghead.GetSealedBox())
if err != nil {
return fmt.Errorf("unable to open sealed box: %w", err)
}
var entries []*entry.Entry
if err := json.Unmarshal(box.Heads, &entries); err != nil {
return fmt.Errorf("unable to unmarshal entries: %w", err)
}
msg.Address = box.Address
msg.Heads = entries
if box.DevicePk == nil {
// @NOTE(gfanton): this is probably a message from a replication server
// which should not have a DevicePK
return nil
}
pid, err := peer.IDFromBytes(box.PeerId)
if err != nil {
return fmt.Errorf("unable to parse peer id: %w", err)
}
// store device into cache
var pdg PeerDeviceGroup
pub, err := crypto.UnmarshalEd25519PublicKey(box.DevicePk)
if err != nil {
return fmt.Errorf("unable to unmarshal remote device pk: %w", err)
}
pdg.DevicePK = pub
group, ok := m.topicGroup[msg.Address]
if ok {
// @FIXME(gfanton): do we need to raise an error here ?
pdg.Group = group
}
m.deviceCaches[pid] = &pdg
return nil
}
func (m *OrbitDBMessageMarshaler) sealBox(topic string, box *protocoltypes.OrbitDBMessageHeads_Box) ([]byte, error) {
sk, ok := m.getSharedKeyFor(topic)
if !ok {
return nil, fmt.Errorf("unable to get shared key for topic")
}
rawBox, err := proto.Marshal(box)
if err != nil {
return nil, fmt.Errorf("unable to marshal box %w", err)
}
sealedBox, err := sk.Seal(rawBox)
if err != nil {
return nil, fmt.Errorf("unable to seal box: %w", err)
}
return sealedBox, nil
}
func (m *OrbitDBMessageMarshaler) openBox(topic string, payload []byte) (*protocoltypes.OrbitDBMessageHeads_Box, error) {
sk, ok := m.getSharedKeyFor(topic)
if !ok {
return nil, fmt.Errorf("unable to get shared key for topic")
}
rawBox, err := sk.Open(payload)
if err != nil {
return nil, fmt.Errorf("unable to open sealed box: %w", err)
}
box := &protocoltypes.OrbitDBMessageHeads_Box{}
if err := proto.Unmarshal(rawBox, box); err != nil {
return nil, fmt.Errorf("unable to unmarshal box: %w", err)
}
return box, nil
}
================================================
FILE: message_marshaler_test.go
================================================
package weshnet
import (
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"berty.tech/go-ipfs-log/enc"
"berty.tech/go-ipfs-log/entry"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/rendezvous"
"berty.tech/weshnet/v2/pkg/secretstore"
)
var (
testSeed1 = []byte("secretsecretsecretsecretsecretse") // 32 bytes seed
testSeed2 = []byte("badbadbadbadbadbadbadbadbadbadba") // 32 bytes seed
)
func TestRotationMessageMarshaler(t *testing.T) {
key, err := enc.NewSecretbox(testSeed1)
require.NoError(t, err)
msg := &iface.MessageExchangeHeads{
Address: "address_1",
Heads: []*entry.Entry{},
}
mn := mocknet.New()
defer mn.Close()
p, err := mn.GenPeer()
require.NoError(t, err)
// generate keystore
acc1, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
rp := rendezvous.NewStaticRotationInterval()
m := NewOrbitDBMessageMarshaler(p.ID(), acc1, rp, false)
g, _, err := NewGroupMultiMember()
require.NoError(t, err)
m.RegisterGroup(msg.Address, g)
rp.RegisterRotation(time.Now(), msg.Address, testSeed1)
m.RegisterSharedKeyForTopic(msg.Address, key)
// marshal with register topic, should succeed
payload, err := m.Marshal(msg)
require.NoError(t, err)
require.NotNil(t, payload)
ret := iface.MessageExchangeHeads{}
err = m.Unmarshal(payload, &ret)
require.NoError(t, err)
assert.Equal(t, msg.Address, ret.Address)
}
func TestRotationMessageMarshalUnknownTopic(t *testing.T) {
mn := mocknet.New()
defer mn.Close()
msg := &iface.MessageExchangeHeads{
Address: "address_1",
Heads: []*entry.Entry{},
}
p, err := mn.GenPeer()
require.NoError(t, err)
// generate keystore
acc, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
rp := rendezvous.NewStaticRotationInterval()
m := NewOrbitDBMessageMarshaler(p.ID(), acc, rp, false)
// marshal without register topic, should fail
payload, err := m.Marshal(msg)
require.Error(t, err)
require.Nil(t, payload)
}
func TestRotationMessageUnmarshalUnknownTopic(t *testing.T) {
mn := mocknet.New()
defer mn.Close()
msg := &iface.MessageExchangeHeads{
Address: "address_1",
Heads: []*entry.Entry{},
}
key1, err := enc.NewSecretbox(testSeed1)
require.NoError(t, err)
key2, err := enc.NewSecretbox(testSeed2)
require.NoError(t, err)
p1, err := mn.GenPeer()
require.NoError(t, err)
p2, err := mn.GenPeer()
require.NoError(t, err)
// generate keystore
acc1, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
acc2, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
g1, _, err := NewGroupMultiMember()
require.NoError(t, err)
g2, _, err := NewGroupMultiMember()
require.NoError(t, err)
rp1 := rendezvous.NewStaticRotationInterval()
rp1.RegisterRotation(time.Now(), msg.Address, testSeed1)
rp2 := rendezvous.NewStaticRotationInterval()
m1 := NewOrbitDBMessageMarshaler(p1.ID(), acc1, rp1, false)
m1.RegisterSharedKeyForTopic(msg.Address, key1)
m1.RegisterGroup(msg.Address, g1)
payload, err := m1.Marshal(msg)
require.NoError(t, err)
m2 := NewOrbitDBMessageMarshaler(p2.ID(), acc2, rp2, false)
m2.RegisterSharedKeyForTopic(msg.Address, key2)
m2.RegisterGroup(msg.Address, g2)
var ret iface.MessageExchangeHeads
// marshal with wrong key should fail
err = m2.Unmarshal(payload, &ret)
require.Error(t, err)
assert.NotEqual(t, ret.Address, msg.Address)
}
func TestRotationMessageMarshalWrongKey(t *testing.T) {
mn := mocknet.New()
defer mn.Close()
msg := &iface.MessageExchangeHeads{
Address: "address_1",
Heads: []*entry.Entry{},
}
key1, err := enc.NewSecretbox(testSeed1)
require.NoError(t, err)
key2, err := enc.NewSecretbox(testSeed2)
require.NoError(t, err)
p1, err := mn.GenPeer()
require.NoError(t, err)
p2, err := mn.GenPeer()
require.NoError(t, err)
g1, _, err := NewGroupMultiMember()
require.NoError(t, err)
g2, _, err := NewGroupMultiMember()
require.NoError(t, err)
// generate keystore
acc1, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
acc2, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
rp1 := rendezvous.NewStaticRotationInterval()
rp1.RegisterRotation(time.Now(), msg.Address, testSeed1)
rp2 := rendezvous.NewStaticRotationInterval()
rp2.RegisterRotation(time.Now(), msg.Address, testSeed2)
m1 := NewOrbitDBMessageMarshaler(p1.ID(), acc1, rp1, false)
m1.RegisterSharedKeyForTopic(msg.Address, key1)
m1.RegisterGroup(msg.Address, g1)
payload, err := m1.Marshal(msg)
require.NoError(t, err)
m2 := NewOrbitDBMessageMarshaler(p2.ID(), acc2, rp2, false)
m2.RegisterSharedKeyForTopic(msg.Address, key2)
m2.RegisterGroup(msg.Address, g2)
var ret iface.MessageExchangeHeads
// marshal with wrong key should fail
err = m2.Unmarshal(payload, &ret)
require.Error(t, err)
assert.NotEqual(t, ret.Address, msg.Address)
// marshal with good key should succeed
err = m1.Unmarshal(payload, &ret)
require.NoError(t, err)
assert.Equal(t, ret.Address, msg.Address)
}
================================================
FILE: orbitdb.go
================================================
package weshnet
import (
"context"
"encoding/base64"
"fmt"
"sync"
"time"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
coreiface "github.com/ipfs/kubo/core/coreiface"
"github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/go-ipfs-log/enc"
"berty.tech/go-ipfs-log/entry"
"berty.tech/go-ipfs-log/identityprovider"
"berty.tech/go-ipfs-log/io"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/baseorbitdb"
"berty.tech/go-orbit-db/iface"
"berty.tech/go-orbit-db/pubsub/pubsubcoreapi"
"berty.tech/go-orbit-db/stores"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/rendezvous"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/tyber"
)
type GroupOpenMode uint64
const (
GroupOpenModeUndefined GroupOpenMode = iota
GroupOpenModeReplicate
GroupOpenModeWrite
)
var _ = GroupOpenModeUndefined
type loggable interface {
setLogger(*zap.Logger)
}
type NewOrbitDBOptions struct {
baseorbitdb.NewOrbitDBOptions
Datastore datastore.Batching
SecretStore secretstore.SecretStore
RotationInterval *rendezvous.RotationInterval
PrometheusRegister prometheus.Registerer
GroupMetadataStoreType string
GroupMessageStoreType string
ReplicationMode bool
}
func (n *NewOrbitDBOptions) applyDefaults() {
if n.Datastore == nil {
n.Datastore = ds_sync.MutexWrap(datastore.NewMapDatastore())
}
if n.PrometheusRegister == nil {
n.PrometheusRegister = prometheus.DefaultRegisterer
}
if n.Cache == nil {
n.Cache = NewOrbitDatastoreCache(n.Datastore)
}
if n.Logger == nil {
n.Logger = zap.NewNop()
}
if n.RotationInterval == nil {
n.RotationInterval = rendezvous.NewStaticRotationInterval()
}
if n.Logger == nil {
n.Logger = zap.NewNop()
}
n.Logger = n.Logger.Named("odb")
if n.GroupMetadataStoreType == "" {
n.GroupMetadataStoreType = "wesh_group_metadata"
}
if n.GroupMessageStoreType == "" {
n.GroupMessageStoreType = "wesh_group_messages"
}
}
type (
GroupMap = sync.Map
GroupContextMap = sync.Map
GroupsSigPubKeyMap = sync.Map
)
type WeshOrbitDB struct {
baseorbitdb.BaseOrbitDB
keyStore *BertySignedKeyStore
secretStore secretstore.SecretStore
pubSub iface.PubSubInterface
rotationInterval *rendezvous.RotationInterval
messageMarshaler *OrbitDBMessageMarshaler
replicationMode bool
prometheusRegister prometheus.Registerer
groupMetadataStoreType string
groupMessageStoreType string
ctx context.Context
// FIXME(gfanton): use real map instead of sync.Map
groups *GroupMap // map[string]*protocoltypes.Group
groupContexts *GroupContextMap // map[string]*GroupContext
groupsSigPubKey *GroupsSigPubKeyMap // map[string]crypto.PubKey
}
func (s *WeshOrbitDB) registerGroupPrivateKey(g *protocoltypes.Group) error {
groupID := g.GroupIDAsString()
gSigSK, err := g.GetSigningPrivKey()
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
if err := s.SetGroupSigPubKey(groupID, gSigSK.GetPublic()); err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
if err := s.keyStore.SetKey(gSigSK); err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
return nil
}
func (s *WeshOrbitDB) registerGroupSigningPubKey(g *protocoltypes.Group) error {
groupID := g.GroupIDAsString()
var gSigPK crypto.PubKey
gSigSK, err := g.GetSigningPrivKey()
if err == nil && gSigSK != nil {
gSigPK = gSigSK.GetPublic()
} else {
gSigPK, err = g.GetSigningPubKey()
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
}
if err := s.SetGroupSigPubKey(groupID, gSigPK); err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
return nil
}
func NewWeshOrbitDB(ctx context.Context, ipfs coreiface.CoreAPI, options *NewOrbitDBOptions) (*WeshOrbitDB, error) {
var err error
if options == nil {
options = &NewOrbitDBOptions{}
}
options.applyDefaults()
ks := &BertySignedKeyStore{}
options.Keystore = ks
options.Identity = &identityprovider.Identity{}
self, err := ipfs.Key().Self(ctx)
if err != nil {
return nil, err
}
if options.PubSub == nil {
options.PubSub = pubsubcoreapi.NewPubSub(ipfs, self.ID(), time.Second, options.Logger, options.Tracer)
}
mm := NewOrbitDBMessageMarshaler(self.ID(), options.SecretStore, options.RotationInterval, options.ReplicationMode)
options.MessageMarshaler = mm
orbitDB, err := baseorbitdb.NewOrbitDB(ctx, ipfs, &options.NewOrbitDBOptions)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
bertyDB := &WeshOrbitDB{
ctx: ctx,
messageMarshaler: mm,
BaseOrbitDB: orbitDB,
keyStore: ks,
secretStore: options.SecretStore,
rotationInterval: options.RotationInterval,
pubSub: options.PubSub,
groups: &GroupMap{},
groupContexts: &GroupContextMap{}, // map[string]*GroupContext
groupsSigPubKey: &GroupsSigPubKeyMap{}, // map[string]crypto.PubKey
groupMetadataStoreType: options.GroupMetadataStoreType,
groupMessageStoreType: options.GroupMessageStoreType,
replicationMode: options.ReplicationMode,
prometheusRegister: options.PrometheusRegister,
}
if err := bertyDB.RegisterAccessControllerType(NewSimpleAccessController); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
bertyDB.RegisterStoreType(bertyDB.groupMetadataStoreType, constructorFactoryGroupMetadata(bertyDB, options.Logger))
bertyDB.RegisterStoreType(bertyDB.groupMessageStoreType, constructorFactoryGroupMessage(bertyDB, options.Logger))
return bertyDB, nil
}
func (s *WeshOrbitDB) openAccountGroup(ctx context.Context, options *orbitdb.CreateDBOptions, ipfsCoreAPI ipfsutil.ExtendedCoreAPI) (*GroupContext, error) {
l := s.Logger()
if options == nil {
options = &orbitdb.CreateDBOptions{}
}
if options.EventBus == nil {
options.EventBus = s.EventBus()
}
group, _, err := s.secretStore.GetGroupForAccount()
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
l.Debug("Got account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: group.String()}})...)
gc, err := s.OpenGroup(ctx, group, options)
if err != nil {
return nil, errcode.ErrCode_ErrGroupOpen.Wrap(err)
}
l.Debug("Opened account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
gc.TagGroupContextPeers(ipfsCoreAPI, 84)
if err := gc.ActivateGroupContext(nil); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
l.Debug("TagGroupContextPeers done", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
return gc, nil
}
func (s *WeshOrbitDB) setHeadsForGroup(ctx context.Context, g *protocoltypes.Group, metaHeads, messageHeads []cid.Cid) error {
groupID := g.GroupIDAsString()
var (
err error
metaImpl, messagesImpl orbitdb.Store
)
existingGC, err := s.getGroupContext(groupID)
if err != nil && !errcode.Is(err, errcode.ErrCode_ErrMissingMapKey) {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if err == nil {
metaImpl = existingGC.metadataStore
messagesImpl = existingGC.messageStore
}
if metaImpl == nil || messagesImpl == nil {
s.groups.Store(groupID, g)
if err := s.registerGroupSigningPubKey(g); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
s.Logger().Debug("OpenGroup", zap.Any("public key", g.PublicKey), zap.Any("secret", g.Secret), zap.Stringer("type", g.GroupType))
if metaImpl == nil {
metaImpl, err = s.storeForGroup(ctx, s, g, nil, s.groupMetadataStoreType, GroupOpenModeReplicate)
if err != nil {
return errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
defer func() { _ = metaImpl.Close() }()
}
if messagesImpl == nil {
messagesImpl, err = s.storeForGroup(ctx, s, g, nil, s.groupMessageStoreType, GroupOpenModeReplicate)
if err != nil {
return errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
defer func() { _ = messagesImpl.Close() }()
}
}
if messagesImpl == nil {
return errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("message store is nil"))
}
if metaImpl == nil {
return errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("metadata store is nil"))
}
var wg sync.WaitGroup
// load and wait heads for metadata and message stores
wg.Add(2)
go func() {
// load meta heads
if err := s.loadHeads(ctx, metaImpl, metaHeads); err != nil {
s.Logger().Error("unable to load metadata heads", zap.Error(err))
}
wg.Done()
}()
go func() {
// load message heads
if err := s.loadHeads(ctx, messagesImpl, messageHeads); err != nil {
s.Logger().Error("unable to load message heads", zap.Error(err))
}
wg.Done()
}()
wg.Wait()
return nil
}
func (s *WeshOrbitDB) loadHeads(ctx context.Context, store iface.Store, heads []cid.Cid) (err error) {
sub, err := store.EventBus().Subscribe(new(stores.EventReplicated),
eventbus.Name("weshnet/load-heads"))
if err != nil {
return fmt.Errorf("unable to subscribe to EventReplicated")
}
defer sub.Close()
// check and generate missing entries if needed
headsEntries := make([]ipfslog.Entry, len(heads))
for i, h := range heads {
if _, ok := store.OpLog().Get(h); !ok {
headsEntries[i] = &entry.Entry{Hash: h}
}
}
if len(headsEntries) == 0 {
return nil
}
store.Replicator().Load(ctx, headsEntries)
for found := 0; found < len(heads); {
// wait for load to finish
select {
case e := <-sub.Out():
evt := e.(stores.EventReplicated)
// iterate over entries from replicated event to search for our heads
for _, headEntry := range headsEntries {
for _, evtEntry := range evt.Entries {
if evtEntry.Equals(headEntry) {
found++
break
}
}
}
case <-s.ctx.Done():
return s.ctx.Err()
}
}
return nil
}
func (s *WeshOrbitDB) OpenGroup(ctx context.Context, g *protocoltypes.Group, options *orbitdb.CreateDBOptions) (*GroupContext, error) {
if s.secretStore == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("db open in naive mode"))
}
groupID := g.GroupIDAsString()
existingGC, err := s.getGroupContext(groupID)
if err != nil && !errcode.Is(err, errcode.ErrCode_ErrMissingMapKey) {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
if err == nil {
return existingGC, nil
}
s.groups.Store(groupID, g)
if err := s.registerGroupPrivateKey(g); err != nil {
return nil, err
}
s.Logger().Debug("OpenGroup", tyber.FormatStepLogFields(s.ctx, tyber.ZapFieldsToDetails(zap.Any("public key", g.PublicKey), zap.Any("secret", g.Secret), zap.Stringer("type", g.GroupType)))...)
memberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
mpkb, err := crypto.MarshalPublicKey(memberDevice.Member())
if err != nil {
mpkb = []byte{}
}
s.Logger().Debug("Got member device", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{{Name: "DevicePublicKey", Description: base64.RawURLEncoding.EncodeToString(mpkb)}})...)
// Force secret generation if missing
if _, err := s.secretStore.GetShareableChainKey(s.ctx, g, memberDevice.Member()); err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
s.Logger().Debug("Got device chain key", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
metaImpl, err := s.groupMetadataStore(ctx, g, options)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
s.messageMarshaler.RegisterGroup(metaImpl.Address().String(), g)
s.Logger().Debug("Got metadata store", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
// force to unshare the same EventBus between groupMetadataStore and groupMessageStore
// to avoid having a bunch of events which are not for the correct group
if options != nil && options.EventBus != nil {
options.EventBus = eventbus.NewBus(
eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(s.prometheusRegister))))
}
messagesImpl, err := s.groupMessageStore(ctx, g, options)
if err != nil {
metaImpl.Close()
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
s.messageMarshaler.RegisterGroup(messagesImpl.Address().String(), g)
s.Logger().Debug("Got message store", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
gc := NewContextGroup(g, metaImpl, messagesImpl, s.secretStore, memberDevice, s.Logger())
s.Logger().Debug("Created group context", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
s.groupContexts.Store(groupID, gc)
s.Logger().Debug("Stored group context", tyber.FormatStepLogFields(s.ctx, []tyber.Detail{})...)
return gc, nil
}
func (s *WeshOrbitDB) OpenGroupReplication(ctx context.Context, g *protocoltypes.Group, options *orbitdb.CreateDBOptions) (iface.Store, iface.Store, error) {
if g == nil || len(g.PublicKey) == 0 {
return nil, nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("missing group or group pubkey"))
}
groupID := g.GroupIDAsString()
gc, err := s.getGroupContext(groupID)
if err != nil && !errcode.Is(err, errcode.ErrCode_ErrMissingMapKey) {
return nil, nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
if err == nil {
return gc.metadataStore, gc.messageStore, nil
}
s.groups.Store(groupID, g)
if err := s.registerGroupSigningPubKey(g); err != nil {
return nil, nil, err
}
metadataStore, err := s.storeForGroup(ctx, s, g, options, s.groupMetadataStoreType, GroupOpenModeReplicate)
if err != nil {
_ = metadataStore.Close()
return nil, nil, errors.Wrap(err, "unable to open database")
}
messageStore, err := s.storeForGroup(ctx, s, g, options, s.groupMessageStoreType, GroupOpenModeReplicate)
if err != nil {
return nil, nil, errors.Wrap(err, "unable to open database")
}
return metadataStore, messageStore, nil
}
func (s *WeshOrbitDB) getGroupContext(id string) (*GroupContext, error) {
g, ok := s.groupContexts.Load(id)
if !ok {
return nil, errcode.ErrCode_ErrMissingMapKey
}
gc, ok := g.(*GroupContext)
if !ok {
s.groupContexts.Delete(id)
return nil, errors.New("cannot cast object to GroupContext")
}
if gc.IsClosed() {
s.groupContexts.Delete(id)
return nil, errcode.ErrCode_ErrMissingMapKey
}
return g.(*GroupContext), nil
}
// SetGroupSigPubKey registers a new group signature pubkey, mainly used to
// replicate a store data without needing to access to its content
func (s *WeshOrbitDB) SetGroupSigPubKey(groupID string, pubKey crypto.PubKey) error {
if pubKey == nil {
return errcode.ErrCode_ErrInvalidInput
}
s.groupsSigPubKey.Store(groupID, pubKey)
return nil
}
func (s *WeshOrbitDB) storeForGroup(ctx context.Context, o iface.BaseOrbitDB, g *protocoltypes.Group, options *orbitdb.CreateDBOptions, storeType string, groupOpenMode GroupOpenMode) (iface.Store, error) {
l := s.Logger()
if options == nil {
options = &orbitdb.CreateDBOptions{}
}
// setup eventbus metrics
if options.EventBus == nil {
options.EventBus = eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(s.prometheusRegister))))
}
options, err := DefaultOrbitDBOptions(g, options, s.keyStore, storeType, groupOpenMode)
if err != nil {
return nil, err
}
l.Debug("Opening store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}, {Name: "Options", Description: fmt.Sprint(options)}}, tyber.Status(tyber.Running))...)
options.StoreType = &storeType
name := fmt.Sprintf("%s_%s", g.GroupIDAsString(), storeType)
addr, err := o.DetermineAddress(ctx, name, storeType, &orbitdb.DetermineAddressOptions{AccessController: options.AccessController})
if err != nil {
return nil, err
}
s.messageMarshaler.RegisterGroup(addr.String(), g)
linkKey, err := g.GetLinkKeyArray()
if err != nil {
return nil, err
}
if key := linkKey[:]; len(key) > 0 {
sk, err := enc.NewSecretbox(key)
if err != nil {
return nil, err
}
cborIO := io.CBOR()
cborIO.ApplyOptions(&io.CBOROptions{LinkKey: sk})
options.IO = cborIO
l.Debug("opening store: register rotation", zap.String("topic", addr.String()))
s.messageMarshaler.RegisterSharedKeyForTopic(addr.String(), sk)
s.rotationInterval.RegisterRotation(time.Now(), addr.String(), key)
}
store, err := o.Open(ctx, name, options)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
l.Debug("Loading store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}, {Name: "StoreType", Description: store.Type()}, {Name: "Store", Description: store.Address().String()}}, tyber.Status(tyber.Running))...)
_ = store.Load(ctx, -1)
l.Debug("Loaded store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}})...)
return store, nil
}
func (s *WeshOrbitDB) groupMetadataStore(ctx context.Context, g *protocoltypes.Group, options *orbitdb.CreateDBOptions) (*MetadataStore, error) {
if options == nil {
options = &orbitdb.CreateDBOptions{}
}
l := s.Logger().Named("metadataStore")
options.Logger = l
l.Debug("Opening group metadata store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}, {Name: "Options", Description: fmt.Sprint(options)}}, tyber.Status(tyber.Running))...)
store, err := s.storeForGroup(ctx, s, g, options, s.groupMetadataStoreType, GroupOpenModeWrite)
if err != nil {
return nil, tyber.LogFatalError(ctx, l, "Failed to get group store", errors.Wrap(err, "unable to open database"))
}
l.Debug("Got group store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "DBName", Description: store.DBName()}})...)
sStore, ok := store.(*MetadataStore)
if !ok {
return nil, tyber.LogFatalError(ctx, l, "Failed to cast group store", errors.New("unable to cast store to metadata store"))
}
l.Debug("Opened group metadata store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}})...)
return sStore, nil
}
func (s *WeshOrbitDB) groupMessageStore(ctx context.Context, g *protocoltypes.Group, options *orbitdb.CreateDBOptions) (*MessageStore, error) {
if options == nil {
options = &orbitdb.CreateDBOptions{}
}
l := s.Logger().Named("messageStore")
options.Logger = l
l.Debug("Opening group message store", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Group", Description: g.String()}, {Name: "Options", Description: fmt.Sprint(options)}}, tyber.Status(tyber.Running))...)
store, err := s.storeForGroup(ctx, s, g, options, s.groupMessageStoreType, GroupOpenModeWrite)
if err != nil {
return nil, errors.Wrap(err, "unable to open database")
}
mStore, ok := store.(*MessageStore)
if !ok {
return nil, errors.New("unable to cast store to message store")
}
return mStore, nil
}
func (s *WeshOrbitDB) getGroupFromOptions(options *iface.NewStoreOptions) (*protocoltypes.Group, error) {
groupIDs, err := options.AccessController.GetAuthorizedByRole(identityGroupIDKey)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
if len(groupIDs) != 1 {
return nil, errcode.ErrCode_ErrInvalidInput
}
g, ok := s.groups.Load(groupIDs[0])
if !ok {
return nil, errcode.ErrCode_ErrInvalidInput
}
typed, ok := g.(*protocoltypes.Group)
if !ok {
return nil, errcode.ErrCode_ErrInvalidInput
}
return typed, nil
}
func (s *WeshOrbitDB) IsGroupLoaded(groupID string) bool {
gc, ok := s.groups.Load(groupID)
return ok && gc != nil
}
func (s *WeshOrbitDB) GetDevicePKForPeerID(id peer.ID) (pdg *PeerDeviceGroup, ok bool) {
return s.messageMarshaler.GetDevicePKForPeerID(id)
}
================================================
FILE: orbitdb_datastore_cache.go
================================================
package weshnet
import (
"context"
datastore "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
"berty.tech/go-orbit-db/address"
"berty.tech/go-orbit-db/cache"
"berty.tech/weshnet/v2/internal/datastoreutil"
)
type datastoreCache struct {
ds datastore.Batching
}
//nolint:revive
func (d *datastoreCache) Load(directory string, dbAddress address.Address) (datastore.Datastore, error) {
return datastoreutil.NewNamespacedDatastore(d.ds, datastore.NewKey(dbAddress.String())), nil
}
func (d *datastoreCache) Close() error {
return nil
}
//nolint:revive
func (d *datastoreCache) Destroy(directory string, dbAddress address.Address) error {
keys, err := datastoreutil.NewNamespacedDatastore(d.ds, datastore.NewKey(dbAddress.String())).Query(context.TODO(), query.Query{KeysOnly: true})
if err != nil {
return nil
}
for {
val, hasValue := keys.NextSync()
if !hasValue {
return nil
}
if err := d.ds.Delete(context.TODO(), datastore.NewKey(val.Key)); err != nil {
return err
}
}
}
func NewOrbitDatastoreCache(ds datastore.Batching) cache.Interface {
return &datastoreCache{
ds: datastoreutil.NewNamespacedDatastore(ds, datastore.NewKey(NamespaceOrbitDBDatastore)),
}
}
var _ cache.Interface = (*datastoreCache)(nil)
================================================
FILE: orbitdb_many_adds_berty_test.go
================================================
package weshnet
import (
"context"
"fmt"
"os"
"path"
"sync"
"testing"
"time"
sync_ds "github.com/ipfs/go-datastore/sync"
"github.com/juju/fslock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
)
func testAddBerty(ctx context.Context, t *testing.T, node ipfsutil.CoreAPIMock, g *protocoltypes.Group, pathBase string, storageKey []byte, storageSalt []byte, amountToAdd, amountCurrentlyPresent int) {
t.Helper()
testutil.FilterSpeed(t, testutil.Fast)
t.Logf("TestAddBerty: amountToAdd: %d, amountCurrentlyPresent: %d\n", amountToAdd, amountCurrentlyPresent)
api := node.API()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
lock := fslock.New(path.Join(pathBase, "lock"))
err := lock.TryLock()
require.NoError(t, err)
defer lock.Unlock()
baseDS, err := GetRootDatastoreForPath(pathBase, storageKey, storageSalt, zap.NewNop())
require.NoError(t, err)
baseDS = sync_ds.MutexWrap(baseDS)
defer testutil.Close(t, baseDS)
secretStore, err := secretstore.NewSecretStore(baseDS, nil)
require.NoError(t, err)
defer secretStore.Close()
odb, err := NewWeshOrbitDB(ctx, api, &NewOrbitDBOptions{
Datastore: baseDS,
SecretStore: secretStore,
})
require.NoError(t, err)
defer testutil.Close(t, odb)
replicate := false
gc, err := odb.OpenGroup(ctx, g, &iface.CreateDBOptions{
Replicate: &replicate,
})
require.NoError(t, err)
defer gc.Close()
defer testutil.Close(t, gc)
wg := sync.WaitGroup{}
wg.Add(amountToAdd * 2)
amountCurrentlyFound := 0
messages, err := gc.MessageStore().ListEvents(ctx, nil, nil, false)
require.NoError(t, err)
for range messages {
amountCurrentlyFound++
}
sub, err := gc.MessageStore().EventBus().Subscribe(new(*protocoltypes.GroupMessageEvent))
require.NoError(t, err)
defer sub.Close()
// Watch for incoming new messages
go func() {
for range sub.Out() {
wg.Done()
}
}()
_, err = gc.MetadataStore().AddDeviceToGroup(ctx)
require.NoError(t, err)
for i := 0; i < amountToAdd; i++ {
_, err := gc.MessageStore().AddMessage(ctx, []byte(fmt.Sprintf("%d", i)))
require.NoError(t, err)
wg.Done()
}
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
case <-time.After(30 * time.Second):
}
require.Equal(t, amountCurrentlyPresent, amountCurrentlyFound)
}
func TestAddBerty(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
api := ipfsutil.TestingCoreAPI(ctx, t)
pathBase, err := os.MkdirTemp("", "manyaddstest")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(pathBase)
g, _, err := NewGroupMultiMember()
require.NoError(t, err)
storageKey := []byte("42424242424242424242424242424242")
storageSalt := []byte("2121212121212121")
testAddBerty(ctx, t, api, g, pathBase, storageKey, storageSalt, 20, 0)
testAddBerty(ctx, t, api, g, pathBase, storageKey, storageSalt, 0, 20)
testAddBerty(ctx, t, api, g, pathBase, storageKey, storageSalt, 20, 20)
testAddBerty(ctx, t, api, g, pathBase, storageKey, storageSalt, 0, 40)
// FIXME: use github.com/stretchr/testify/suite
}
================================================
FILE: orbitdb_many_adds_test.go
================================================
package weshnet
import (
"context"
crand "crypto/rand"
"fmt"
"os"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func TestAdd(t *testing.T) {
amount := 20 // speeding up tests, 2000 takes ~25 seconds
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ipfs := ipfsutil.TestingCoreAPI(ctx, t)
dir := "./orbitdb/benchmarks"
defer os.RemoveAll(dir)
orbit, err := orbitdb.NewOrbitDB(ctx, ipfs.API(), &orbitdb.NewOrbitDBOptions{Directory: &dir})
if err != nil {
t.Fatal(err)
}
defer orbit.Close()
if err := orbit.RegisterAccessControllerType(NewSimpleAccessController); err != nil {
t.Fatal(err)
}
sigk, _, err := crypto.GenerateEd25519Key(crand.Reader)
if err != nil {
t.Fatal(err)
}
ks := &BertySignedKeyStore{}
err = ks.SetKey(sigk)
if err != nil {
t.Fatal(err)
}
sigkB, err := cryptoutil.SeedFromEd25519PrivateKey(sigk)
if err != nil {
t.Fatal(err)
}
pubkB, err := sigk.GetPublic().Raw()
if err != nil {
t.Fatal(err)
}
g := &protocoltypes.Group{PublicKey: pubkB, Secret: sigkB}
replicate := false
opts, err := DefaultOrbitDBOptions(g, &orbitdb.CreateDBOptions{Replicate: &replicate}, ks, "log", GroupOpenModeWrite)
if err != nil {
t.Fatal(err)
}
db, err := orbit.Log(ctx, "DemoLog", opts)
if err != nil {
t.Fatal(err)
}
defer db.Drop()
defer db.Close()
for n := 0; n < amount; n++ {
if _, err := db.Add(ctx, []byte(fmt.Sprintf("%d", n))); err != nil {
t.Fatal(err)
}
}
}
================================================
FILE: orbitdb_signed_entry_accesscontroller.go
================================================
package weshnet
import (
"context"
"encoding/json"
"sync"
cid "github.com/ipfs/go-cid"
mh "github.com/multiformats/go-multihash"
"github.com/pkg/errors"
"go.uber.org/zap"
logac "berty.tech/go-ipfs-log/accesscontroller"
"berty.tech/go-ipfs-log/identityprovider"
"berty.tech/go-orbit-db/accesscontroller"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/errcode"
)
type simpleAccessController struct {
allowedKeys map[string][]string
logger *zap.Logger
lock sync.RWMutex
}
func (o *simpleAccessController) SetLogger(logger *zap.Logger) {
o.lock.Lock()
defer o.lock.Unlock()
o.logger = logger
}
func (o *simpleAccessController) Logger() *zap.Logger {
o.lock.RLock()
defer o.lock.RUnlock()
return o.logger
}
//nolint:revive
func (o *simpleAccessController) Grant(ctx context.Context, capability string, keyID string) error {
return nil
}
//nolint:revive
func (o *simpleAccessController) Revoke(ctx context.Context, capability string, keyID string) error {
return nil
}
//nolint:revive
func (o *simpleAccessController) Load(ctx context.Context, address string) error {
return nil
}
func simpleAccessControllerCID(allowedKeys map[string][]string) (cid.Cid, error) {
d, err := json.Marshal(allowedKeys)
if err != nil {
return cid.Undef, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
c, err := cid.Prefix{
Version: 1,
Codec: cid.Raw,
MhType: mh.SHA2_256,
MhLength: -1,
}.Sum(d)
if err != nil {
return cid.Undef, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
return c, nil
}
func (o *simpleAccessController) Save(context.Context) (accesscontroller.ManifestParams, error) {
c, err := simpleAccessControllerCID(o.allowedKeys)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
return accesscontroller.NewManifestParams(c, true, "simple"), nil
}
func (o *simpleAccessController) Close() error {
return nil
}
func (o *simpleAccessController) Type() string {
return "bertysimple"
}
func (o *simpleAccessController) GetAuthorizedByRole(role string) ([]string, error) {
return o.allowedKeys[role], nil
}
func (o *simpleAccessController) CanAppend(e logac.LogEntry, _ identityprovider.Interface, _ accesscontroller.CanAppendAdditionalContext) error {
for _, id := range o.allowedKeys["write"] {
if e.GetIdentity().ID == id || id == "*" {
return nil
}
}
return errors.New("not allowed to write entry")
}
// NewSimpleAccessController Returns a non configurable access controller
func NewSimpleAccessController(_ context.Context, _ iface.BaseOrbitDB, params accesscontroller.ManifestParams, options ...accesscontroller.Option) (accesscontroller.Interface, error) {
if params == nil {
return &simpleAccessController{}, errors.New("an options object is required")
}
ac := &simpleAccessController{
allowedKeys: params.GetAllAccess(),
}
for _, o := range options {
o(ac)
}
return ac, nil
}
var _ accesscontroller.Interface = &simpleAccessController{}
================================================
FILE: orbitdb_signed_entry_identity_provider.go
================================================
package weshnet
import (
"context"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/go-ipfs-log/identityprovider"
"berty.tech/weshnet/v2/pkg/errcode"
)
const (
identityGroupIDKey = "group_id"
storeTypeKey = "store_type"
identityType = "betry_group_entry"
)
type bertySignedIdentityProvider struct {
keyStore *BertySignedKeyStore
}
func (b *bertySignedIdentityProvider) UnmarshalPublicKey(data []byte) (crypto.PubKey, error) {
return crypto.UnmarshalPublicKey(data)
}
func (b *bertySignedIdentityProvider) GetID(_ context.Context, opts *identityprovider.CreateIdentityOptions) (string, error) {
return opts.ID, nil
}
//nolint:revive
func (b *bertySignedIdentityProvider) SignIdentity(ctx context.Context, data []byte, id string) ([]byte, error) {
return nil, nil
}
func (b *bertySignedIdentityProvider) GetType() string {
return identityType
}
func (b *bertySignedIdentityProvider) VerifyIdentity(*identityprovider.Identity) error {
return nil
}
func (b *bertySignedIdentityProvider) Sign(ctx context.Context, identity *identityprovider.Identity, bytes []byte) ([]byte, error) {
key, err := b.keyStore.GetKey(ctx, identity.ID)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
sig, err := key.Sign(bytes)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return sig, nil
}
func (b *bertySignedIdentityProvider) signID(ctx context.Context, id string) (crypto.PubKey, []byte, error) {
privKey, err := b.keyStore.GetKey(ctx, id)
if err != nil {
return nil, nil, err
}
idSignature, err := b.keyStore.Sign(privKey, []byte(id))
if err != nil {
return nil, nil, err
}
return privKey.GetPublic(), idSignature, nil
}
func (b *bertySignedIdentityProvider) createIdentity(ctx context.Context, options *identityprovider.CreateIdentityOptions) (*identityprovider.Identity, error) {
id, err := b.GetID(ctx, options)
if err != nil {
return nil, err
}
publicKey, idSignature, err := b.signID(ctx, id)
if err != nil {
return nil, err
}
publicKeyRaw, err := publicKey.Raw()
if err != nil {
return nil, err
}
publicKeyBytes, err := crypto.MarshalPublicKey(publicKey)
if err != nil {
return nil, err
}
pubKeyIDSignature, err := b.SignIdentity(ctx, append(publicKeyRaw, idSignature...), options.ID)
if err != nil {
return nil, err
}
return &identityprovider.Identity{
ID: id,
PublicKey: publicKeyBytes,
Signatures: &identityprovider.IdentitySignature{
ID: idSignature,
PublicKey: pubKeyIDSignature,
},
Type: b.GetType(),
Provider: b,
}, nil
}
var _ identityprovider.Interface = (*bertySignedIdentityProvider)(nil)
================================================
FILE: orbitdb_signed_entry_keystore.go
================================================
package weshnet
import (
"context"
"encoding/hex"
"sync"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/go-ipfs-log/keystore"
"berty.tech/weshnet/v2/pkg/errcode"
)
type BertySignedKeyStore struct {
sync.Map
}
func (s *BertySignedKeyStore) SetKey(pk crypto.PrivKey) error {
pubKeyBytes, err := pk.GetPublic().Raw()
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
keyID := hex.EncodeToString(pubKeyBytes)
s.Store(keyID, pk)
return nil
}
func (s *BertySignedKeyStore) HasKey(_ context.Context, id string) (bool, error) {
_, ok := s.Load(id)
return ok, nil
}
func (s *BertySignedKeyStore) CreateKey(ctx context.Context, id string) (crypto.PrivKey, error) {
return s.GetKey(ctx, id)
}
func (s *BertySignedKeyStore) GetKey(_ context.Context, id string) (crypto.PrivKey, error) {
if privKey, ok := s.Load(id); ok {
if pk, ok := privKey.(crypto.PrivKey); ok {
return pk, nil
}
}
return nil, errcode.ErrCode_ErrGroupMemberUnknownGroupID
}
func (s *BertySignedKeyStore) Sign(privKey crypto.PrivKey, bytes []byte) ([]byte, error) {
return privKey.Sign(bytes)
}
func (s *BertySignedKeyStore) Verify(signature []byte, publicKey crypto.PubKey, data []byte) error {
ok, err := publicKey.Verify(data, signature)
if err != nil {
return err
}
if !ok {
return errcode.ErrCode_ErrGroupMemberLogEventSignature
}
return nil
}
func (s *BertySignedKeyStore) getIdentityProvider() *bertySignedIdentityProvider {
return &bertySignedIdentityProvider{
keyStore: s,
}
}
var _ keystore.Interface = (*BertySignedKeyStore)(nil)
================================================
FILE: orbitdb_test.go
================================================
package weshnet
import (
"context"
"encoding/hex"
"os"
"strings"
"testing"
"time"
datastore "github.com/ipfs/go-datastore"
sync_ds "github.com/ipfs/go-datastore/sync"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"berty.tech/weshnet/v2/internal/datastoreutil"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
"berty.tech/weshnet/v2/pkg/tinder"
)
func TestDifferentStores(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
logger, cleanup := testutil.Logger(t)
defer cleanup()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
ipfsOpts := &ipfsutil.TestingAPIOpts{
Logger: logger,
Mocknet: mn,
DiscoveryServer: tinder.NewMockDriverServer(),
}
pathBase, err := os.MkdirTemp("", "odb_manyaddstest")
if err != nil {
t.Fatal(err)
}
require.NoError(t, mn.ConnectAllButSelf())
baseDS, err := GetRootDatastoreForPath(pathBase, nil, nil, zap.NewNop())
require.NoError(t, err)
baseDS = sync_ds.MutexWrap(baseDS)
defer testutil.Close(t, baseDS)
api1 := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsOpts)
odb1 := NewTestOrbitDB(ctx, t, logger, api1, datastoreutil.NewNamespacedDatastore(baseDS, datastore.NewKey("peer1")))
defer testutil.Close(t, odb1)
api2 := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsOpts)
odb2 := NewTestOrbitDB(ctx, t, logger, api2, datastoreutil.NewNamespacedDatastore(baseDS, datastore.NewKey("peer2")))
defer testutil.Close(t, odb2)
err = mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
gA, _, err := NewGroupMultiMember()
require.NoError(t, err)
gB, _, err := NewGroupMultiMember()
require.NoError(t, err)
assert.NotEqual(t, gA.PublicKey, gB.PublicKey)
g1a, err := odb1.OpenGroup(ctx, gA, nil)
require.NoError(t, err)
defer g1a.Close()
g2a, err := odb2.OpenGroup(ctx, gA, nil)
require.NoError(t, err)
defer g2a.Close()
g1b, err := odb1.OpenGroup(ctx, gB, nil)
require.NoError(t, err)
defer g1b.Close()
g2b, err := odb2.OpenGroup(ctx, gB, nil)
require.NoError(t, err)
defer g2b.Close()
assert.Equal(t, g1a.MetadataStore().Address().String(), g2a.MetadataStore().Address().String())
assert.Equal(t, g1b.MetadataStore().Address().String(), g2b.MetadataStore().Address().String())
assert.NotEqual(t, g1a.MetadataStore().Address().String(), g1a.MessageStore().Address().String())
assert.NotEqual(t, g1a.MetadataStore().Address().String(), g1b.MetadataStore().Address().String())
authorized1, err := g1a.MetadataStore().AccessController().GetAuthorizedByRole("write")
require.NoError(t, err)
authorized2, err := g1a.MetadataStore().AccessController().GetAuthorizedByRole("write")
require.NoError(t, err)
assert.Equal(t, strings.Join(authorized1, ","), strings.Join(authorized2, ","))
pk1, err := g1a.MetadataStore().Identity().GetPublicKey()
require.NoError(t, err)
pk2, err := g2a.MetadataStore().Identity().GetPublicKey()
require.NoError(t, err)
require.True(t, pk1.Equals(pk2))
rawPK, err := pk1.Raw()
require.NoError(t, err)
require.Equal(t, hex.EncodeToString(rawPK), authorized1[0])
_, err = g1a.MetadataStore().SendAppMetadata(ctx, []byte("From 1 - 1"))
require.NoError(t, err)
_, err = g2a.MetadataStore().SendAppMetadata(ctx, []byte("From 2 - 1"))
require.NoError(t, err)
_, err = g1b.MetadataStore().SendAppMetadata(ctx, []byte("From 1 - 2"))
require.NoError(t, err)
_, err = g2b.MetadataStore().SendAppMetadata(ctx, []byte("From 2 - 2"))
require.NoError(t, err)
_, err = g1b.MetadataStore().SendAppMetadata(ctx, []byte("From 1 - 3"))
require.NoError(t, err)
_, err = g2b.MetadataStore().SendAppMetadata(ctx, []byte("From 2 - 3"))
require.NoError(t, err)
{
var err error
var cc <-chan *protocoltypes.GroupMetadataEvent
var ops []*protocoltypes.GroupMetadataPayloadSent
assert.Eventually(t, func() bool {
cc, err = g1a.MetadataStore().ListEvents(ctx, nil, nil, false)
ops = testutil.TestFilterGroupMetadataPayloadSent(t, cc)
return len(ops) == 2
}, time.Second*2, time.Millisecond*100, "have: %d, want: %d", len(ops), 2)
require.NoError(t, err)
assert.Eventually(t, func() bool {
cc, err = g2a.MetadataStore().ListEvents(ctx, nil, nil, false)
ops = testutil.TestFilterGroupMetadataPayloadSent(t, cc)
return len(ops) == 2
}, time.Second*2, time.Millisecond*100, "have: %d, want: %d", len(ops), 2)
require.NoError(t, err)
assert.Eventually(t, func() bool {
cc, err = g1b.MetadataStore().ListEvents(ctx, nil, nil, false)
ops = testutil.TestFilterGroupMetadataPayloadSent(t, cc)
return len(ops) == 4
}, time.Second*2, time.Millisecond*100, "have: %d, want: %d", len(ops), 5)
require.NoError(t, err)
assert.Eventually(t, func() bool {
cc, err = g2b.MetadataStore().ListEvents(ctx, nil, nil, false)
ops = testutil.TestFilterGroupMetadataPayloadSent(t, cc)
return len(ops) == 4
}, time.Second*2, time.Millisecond*100, "have: %d, want: %d", len(ops), 4)
require.NoError(t, err)
}
}
================================================
FILE: orbitdb_utils_test.go
================================================
package weshnet
import (
"context"
"sync"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func inviteAllPeersToGroup(ctx context.Context, t *testing.T, peers []*mockedPeer, groupSK crypto.PrivKey) {
t.Helper()
wg := sync.WaitGroup{}
wg.Add(len(peers))
errChan := make(chan error, len(peers))
for i, p := range peers {
sub, err := p.GC.MetadataStore().EventBus().Subscribe(new(*protocoltypes.GroupMetadataEvent))
require.NoError(t, err)
go func(p *mockedPeer, peerIndex int) {
defer sub.Close()
defer wg.Done()
eventReceived := 0
for e := range sub.Out() {
evt := e.(*protocoltypes.GroupMetadataEvent)
if evt.Metadata.EventType != protocoltypes.EventType_EventTypeGroupMemberDeviceAdded {
continue
}
memdev := &protocoltypes.GroupMemberDeviceAdded{}
if err := proto.Unmarshal(evt.Event, memdev); err != nil {
errChan <- err
return
}
eventReceived++
if eventReceived == len(peers) {
return
}
}
}(p, i)
}
for i, p := range peers {
_, err := p.GC.MetadataStore().AddDeviceToGroup(ctx)
require.NoError(t, err)
if i == 0 {
_, err := p.GC.MetadataStore().ClaimGroupOwnership(ctx, groupSK)
require.NoError(t, err)
}
}
// Wait for all events to be received in all peers's member log (or timeout)
wg.Wait()
close(errChan)
for err := range errChan {
t.Fatal(err)
}
}
func waitForBertyEventType(ctx context.Context, t *testing.T, ms *MetadataStore, eventType protocoltypes.EventType, eventCount int, done chan struct{}) {
t.Helper()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
handledEvents := map[string]struct{}{}
sub, err := ms.EventBus().Subscribe(new(*protocoltypes.GroupMetadataEvent))
require.NoError(t, err)
defer sub.Close()
for {
var e any
select {
case e = <-sub.Out():
case <-ctx.Done():
return
}
switch evt := e.(type) {
case *protocoltypes.GroupMetadataEvent:
if evt.Metadata.EventType != eventType {
continue
}
eID := string(evt.EventContext.Id)
if _, ok := handledEvents[eID]; ok {
continue
}
handledEvents[eID] = struct{}{}
e := &protocoltypes.GroupDeviceChainKeyAdded{}
if err := proto.Unmarshal(evt.Event, e); err != nil {
t.Fatalf(" err: %+v\n", err.Error())
}
// fmt.Println(string(e.DevicePK), string(e.DestMemberPK))
eventCount--
if eventCount == 0 {
done <- struct{}{}
} else {
// fmt.Println(eventCount, "more to go")
}
}
}
}
================================================
FILE: pkg/androidnearby/bridge_android.go
================================================
//go:build android && !noproximitytransport
package androidnearby
import (
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
// Supported is used by main package as default value for enable this driver.
// While UI actually enable or not the Java Android Nearby driver.
// TODO: remove this when UI will be able to handle this for the first App launching.
const Supported = true
// Noop implementation for Android
// Real driver is given from Java directly here: berty/js/android/app/src/main/java/tech/berty/gobridge/nearby
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
logger = logger.Named("Nearby")
logger.Info("NewDriver(): Java driver not found")
return proximity.NewNoopProximityDriver(ProtocolCode, ProtocolName, DefaultAddr)
}
================================================
FILE: pkg/androidnearby/bridge_unsupported.go
================================================
//go:build !android || noproximitytransport
package androidnearby
import (
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
const Supported = false
// Noop implementation for platform that are not Darwin
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
logger = logger.Named("Nearby")
logger.Info("NewDriver(): incompatible system")
return proximity.NewNoopProximityDriver(ProtocolCode, ProtocolName, DefaultAddr)
}
================================================
FILE: pkg/androidnearby/const.go
================================================
package androidnearby
const (
DefaultAddr = "/nearby/Qmeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
ProtocolCode = 0x0044
ProtocolName = "nearby"
)
================================================
FILE: pkg/androidnearby/example_test.go
================================================
package androidnearby_test
================================================
FILE: pkg/androidnearby/init.go
================================================
package androidnearby
import (
ma "github.com/multiformats/go-multiaddr"
)
// Add MC to the list of libp2p's multiaddr protocols
// FIXME: remove this init
func init() { // nolint:gochecknoinits
err := ma.AddProtocol(newProtocol())
if err != nil {
panic(err)
}
}
================================================
FILE: pkg/androidnearby/multiaddr.go
================================================
package androidnearby
import (
peer "github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
func newProtocol() ma.Protocol {
transcoderMC := ma.NewTranscoderFromFunctions(mcStB, mcBtS, mcVal)
return ma.Protocol{
Name: ProtocolName,
Code: ProtocolCode,
VCode: ma.CodeToVarint(ProtocolCode),
Size: -1,
Path: false,
Transcoder: transcoderMC,
}
}
func mcStB(s string) ([]byte, error) {
_, err := peer.Decode(s)
if err != nil {
return nil, err
}
return []byte(s), nil
}
func mcBtS(b []byte) (string, error) {
_, err := peer.Decode(string(b))
if err != nil {
return "", err
}
return string(b), nil
}
func mcVal(b []byte) error {
_, err := peer.Decode(string(b))
return err
}
================================================
FILE: pkg/bertyvcissuer/client.go
================================================
package bertyvcissuer
import (
"context"
"crypto"
crand "crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"github.com/piprate/json-gold/ld"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/verifiablecredstypes"
)
const DefaultRedirectURI = "berty://vc"
type Client struct {
serverRoot string
redirectURI string
httpClient *http.Client
state string
bertyURL string
}
func NewClient(serverRoot string) *Client {
return &Client{
serverRoot: serverRoot,
redirectURI: DefaultRedirectURI,
httpClient: http.DefaultClient,
}
}
func (c *Client) Init(ctx context.Context, bertyURL string, accountPriv crypto.Signer) (string, error) {
c.state = base64.RawURLEncoding.EncodeToString([]byte(time.Now().String()))
c.bertyURL = bertyURL
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/%s?%s=%s&%s=%s&%s=%s", c.serverRoot, PathChallenge, ParamBertyID, url.QueryEscape(bertyURL), ParamRedirectURI, url.QueryEscape(c.redirectURI), ParamState, url.QueryEscape(c.state)), nil)
if err != nil {
return "", errcode.ErrCode_ErrInternal.Wrap(err)
}
res, err := c.httpClient.Do(req)
if err != nil {
return "", errcode.ErrCode_ErrStreamRead.Wrap(err)
}
resBytes, err := io.ReadAll(res.Body)
if err != nil {
return "", errcode.ErrCode_ErrStreamRead.Wrap(err)
}
_ = res.Body.Close()
if res.StatusCode != http.StatusOK {
return "", errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf(string(resBytes)))
}
challengeStruct := &verifiablecredstypes.AccountCryptoChallenge{}
err = json.Unmarshal(resBytes, challengeStruct)
if err != nil {
return "", errcode.ErrCode_ErrDeserialization.Wrap(err)
}
challenge, err := base64.URLEncoding.DecodeString(challengeStruct.Challenge)
if err != nil {
return "", errcode.ErrCode_ErrDeserialization.Wrap(err)
}
challengeSig, err := accountPriv.Sign(crand.Reader, challenge, crypto.Hash(0))
if err != nil {
return "", errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
return fmt.Sprintf("%s/%s?&%s=%s&%s=%s", c.serverRoot, PathAuthenticate, ParamChallenge, challengeStruct.Challenge, ParamChallengeSig, base64.URLEncoding.EncodeToString(challengeSig)), nil
}
func (c *Client) Complete(uri string) (string, string, *verifiable.Credential, error) {
parsedURI, err := url.Parse(uri)
if err != nil {
return "", "", nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
if parsedURI.Query().Get(ParamState) != c.state {
return "", "", nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unexpected state value"))
}
credentialsStr := parsedURI.Query().Get(ParamCredentials)
if len(credentialsStr) == 0 {
return "", "", nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("missing credentials value"))
}
credentials, err := base64.StdEncoding.DecodeString(credentialsStr)
if err != nil {
return "", "", nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
parsedCredential, err := verifiable.ParseCredential(
credentials,
verifiable.WithPublicKeyFetcher(EmbeddedPublicKeyFetcher),
verifiable.WithJSONLDDocumentLoader(ld.NewDefaultDocumentLoader(http.DefaultClient)),
)
if err != nil {
return "", "", nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if c.bertyURL != parsedCredential.ID {
return "", "", nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("credential is not delivered for the current berty url (%s != %s)", c.bertyURL, parsedCredential.ID))
}
identifier, err := ExtractSubjectFromVC(parsedCredential)
if err != nil {
return "", "", nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
return string(credentials), identifier, parsedCredential, nil
}
func ExtractSubjectFromVC(credential *verifiable.Credential) (string, error) {
if credential.Subject == nil {
return "", errcode.ErrCode_ErrNotFound
}
if subjectList, ok := credential.Subject.([]verifiable.Subject); ok {
if len(subjectList) == 0 {
return "", errcode.ErrCode_ErrNotFound
}
return subjectList[0].ID, nil
} else if subject, ok := credential.Subject.(string); ok && subject != "" {
return subject, nil
}
return "", errcode.ErrCode_ErrNotFound
}
================================================
FILE: pkg/bertyvcissuer/urls.go
================================================
package bertyvcissuer
import (
"encoding/base64"
"fmt"
)
const (
PathChallenge = "/challenge"
PathAuthenticate = "/authenticate"
PathProof = "/proof"
ParamBertyID = "berty_id"
ParamState = "state"
ParamRedirectURI = "redirect_uri"
ParamChallenge = "challenge"
ParamChallengeSig = "challenge_sig"
ParamCode = "code"
ParamContext = "context"
ParamCredentials = "credentials"
ParamIdentifier = "identifier"
)
func MakeAuthenticateURL(serverBaseRoot, flowCtxStr string) string {
return fmt.Sprintf("%s%s?%s=%s", serverBaseRoot, PathAuthenticate, ParamContext, flowCtxStr)
}
func MakeProofURL(serverBaseRoot, flowCtxStr string) string {
return fmt.Sprintf("%s%s?%s=%s", serverBaseRoot, PathProof, ParamContext, flowCtxStr)
}
func MakeRedirectSuccessURI(redirectURI, state string, credentials []byte) string {
return fmt.Sprintf("%s%s?%s=%s&%s=%s", redirectURI, PathProof, ParamState, state, ParamCredentials, base64.URLEncoding.EncodeToString(credentials))
}
================================================
FILE: pkg/bertyvcissuer/verifiable_public_key_fetcher.go
================================================
package bertyvcissuer
import (
"crypto/ed25519"
"fmt"
"slices"
"strings"
"github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
"github.com/hyperledger/aries-framework-go/pkg/kms"
"github.com/multiformats/go-multibase"
"berty.tech/weshnet/v2/pkg/errcode"
)
func embeddedPublicKeyFetcher(issuerID string, allowList []string) (*verifier.PublicKey, error) {
if !strings.HasPrefix(issuerID, "did:key:z6Mk") {
return nil, fmt.Errorf("unexpected key format")
}
if len(allowList) > 0 {
found := slices.Contains(allowList, issuerID)
if !found {
return nil, errcode.ErrCode_ErrServicesDirectoryInvalidVerifiedCredentialID.Wrap(fmt.Errorf("issuer is not allowed"))
}
}
_, rawData, err := multibase.Decode(issuerID[8:])
if err != nil {
return nil, err
}
if len(rawData) != ed25519.PublicKeySize+2 {
return nil, errcode.ErrCode_ErrInvalidInput
}
return &verifier.PublicKey{
Type: kms.ED25519,
Value: rawData[2:],
JWK: nil,
}, nil
}
// nolint:revive
func EmbeddedPublicKeyFetcher(issuerID, keyID string) (*verifier.PublicKey, error) {
return embeddedPublicKeyFetcher(issuerID, nil)
}
// nolint:revive
func EmbeddedPublicKeyFetcherAllowList(allowList []string) func(issuerID, keyID string) (*verifier.PublicKey, error) {
return func(issuerID, keyID string) (*verifier.PublicKey, error) {
return embeddedPublicKeyFetcher(issuerID, allowList)
}
}
================================================
FILE: pkg/ble-driver/BertyDevice_darwin.h
================================================
//
// BertyDevice.h
// ble
//
// Created by sacha on 03/06/2019.
// Copyright © 2019 berty. All rights reserved.
//
#import
#import
#import "ConnectedPeer.h"
#import "CircularQueue.h"
#import "BleQueue.h"
#import "Logger.h"
#import "CountDownLatch_darwin.h"
NS_ASSUME_NONNULL_BEGIN
@class BleManager;
typedef void (^BertyDeviceConnectCallbackBlockType)(BertyDevice * __nullable, NSError * __nullable);
typedef void (^BertyDeviceServiceCallbackBlockType)(NSArray * __nullable, NSError * __nullable);
typedef void (^BertyDeviceWriteCallbackBlockType)(NSError * __nullable);
#define _BERTY_ON_D_THREAD(block) dispatch_async(self.dQueue, block)
#define _BERTY_ON_W_THREAD(block) dispatch_async(self.writeQueue, block)
@interface BertyDevice : NSObject
@property (nonatomic, strong, nonnull) Logger *logger;
@property (nonatomic, strong, nonnull) NSString *name;
@property (nonatomic, strong, nonnull) NSDictionary *serviceDict;
@property (nonatomic, strong, nullable) CBPeripheral *peripheral;
@property (nonatomic, strong, nonnull) NSString *serverSideIdentifier;
@property (nonatomic, strong, nonnull) NSString *clientSideIdentifier;
@property (nonatomic, assign, nullable) BleManager *manager;
@property (nonatomic, strong, nonnull) BleQueue *connectionQ;
@property (nonatomic, strong, nonnull) BleQueue *writeQ;
@property (nonatomic, strong, nonnull) BleQueue *readQ;
@property (nonatomic, strong, nullable) NSObject *writerLatch;
@property (nonatomic, strong, nullable) CBCharacteristic *peerIDCharacteristic;
@property (nonatomic, strong, nullable) CBCharacteristic *writerCharacteristic;
@property (nonatomic, strong, nonnull) NSDictionary* characteristicHandlers;
@property (nonatomic, strong, nonnull) NSDictionary* characteristicData;
@property (nonatomic, strong, nullable) NSData *remainingData;
@property (nonatomic, strong, nullable) NSString *remotePeerID;
@property (readwrite) int psm;
@property (nonatomic, strong, nullable) ConnectedPeer *peer;
@property (nonatomic, strong, nonnull) CBCentral *cbCentral;
@property (nonatomic, strong, nonnull) CircularQueue *dataCache;
@property (readwrite) BOOL isDisconnecting;
- (instancetype __nullable)initWithIdentifier:(NSString *__nonnull)identifier logger:(Logger *__nonnull)logger central:(BleManager *__nonnull)manager asClient:(BOOL)client;
- (instancetype __nullable)initWithPeripheral:(CBPeripheral *__nonnull)peripheral logger:(Logger *__nonnull)logger central:(BleManager *__nonnull)manager withName:(NSString *__nonnull)name;
- (void)closeBertyDevice;
- (BOOL)writeToCharacteristic:(NSData *__nonnull)data forCharacteristic:(CBCharacteristic *__nonnull)characteristic withEOD:(BOOL)eod;
- (void)handshake;
- (void)handleConnect:(NSError * __nullable)error;
- (void)connectWithOptions:(NSDictionary * __nullable)options;
- (NSString *__nonnull)getIdentifier;
- (void)flushCache;
@end
API_AVAILABLE(ios(11.0))
@interface BertyDevice()
@property (strong, nullable) NSThread *l2capThread;
@property (strong, nullable) CBL2CAPChannel *l2capChannel;
@property (strong, nullable) NSData *l2capWriteData;
@property (readwrite) NSInteger l2capWriteIndex;
@property (readwrite) BOOL useL2cap;
@property (readwrite) BOOL l2capClientHandshakeRunning;
@property (readwrite) BOOL l2capServerHandshakeRunning;
@property (strong, nullable) CountDownLatch *l2capHandshakeLatch;
@property (readwrite) BOOL l2capHandshakeStepStatus;
@property (copy, nullable) dispatch_block_t l2capHandshakeBlock;
@property (strong, nullable) NSMutableData *l2capHandshakeData;
@property (strong, nullable) NSMutableData *l2capHandshakeRecvData;
@property (readwrite) NSUInteger l2capHandshakeRecvDataLen;
- (BOOL)l2capWrite:(NSData *__nonnull)data;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/BertyDevice_darwin.m
================================================
// +build darwin,!noproximitytransport
//
// BertyDevice.m
// ble
//
// Created by sacha on 03/06/2019.
// Copyright © 2019 berty. All rights reserved.
//
#import "BertyDevice_darwin.h"
#import "BleManager_darwin.h"
extern unsigned short handlePeerFound(char *, char *);
extern void receiveFromDevice(char *, void *, int);
static NSString* const __nonnull EOD = @"EOD";
static const int L2CAP_BUFFER = 4096;
static const int L2CAP_HANDSHAKE_DATA = 1024;
CBService *getService(NSArray *services, NSString *uuid) {
CBService *result = nil;
for (CBService *service in services) {
if ([service.UUID.UUIDString containsString:uuid] != NSNotFound) {
result = service;
}
}
return result;
}
@implementation BertyDevice
- (instancetype)initWithPeripheral:(CBPeripheral *)peripheral logger:(Logger *__nonnull)logger
central:(BleManager *)manager withName:(NSString *__nonnull)name {
self = [self initWithIdentifier:[peripheral.identifier UUIDString] logger:logger central:manager asClient:TRUE];
if (self) {
_peripheral = [peripheral retain];
_name = name;
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier logger:(Logger *__nonnull)logger central:(BleManager *)manager asClient:(BOOL)client{
self = [super init];
if (self) {
if (client) {
_clientSideIdentifier = [identifier retain];
} else {
_serverSideIdentifier = [identifier retain];
}
_logger = [logger retain];
_peripheral = nil;
_manager = manager;
_remotePeerID = nil;
_psm = 0;
_connectionQ = [[BleQueue alloc] init: dispatch_get_main_queue() logger:logger];
_writeQ = [[BleQueue alloc] init: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) logger:logger];
_readQ = [[BleQueue alloc] init: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) logger:logger];
BOOL (^peerIDHandler)(NSData *data) = ^BOOL(NSData *data) {
return [self handlePeerID:data];
};
BOOL (^writeHandler)(NSData *data) = ^BOOL(NSData *data) {
return [self handleIncomingData:data];
};
_characteristicHandlers = [@{
[BleManager.writerUUID UUIDString]: [[writeHandler copy] autorelease],
[BleManager.peerUUID UUIDString]: [[peerIDHandler copy] autorelease],
} retain];
_characteristicData = [@{
[BleManager.writerUUID UUIDString]: [NSMutableData data],
[BleManager.peerUUID UUIDString]: [NSMutableData data],
} retain];
// put inside incoming message arrived before handshake is completed
_dataCache = [[CircularQueue alloc] initWithCapacity:10];
_writerLatch = [[NSObject alloc] init];
}
return self;
}
- (void)dealloc {
[_logger release];
[_clientSideIdentifier release];
[_serverSideIdentifier release];
[_peripheral release];
_manager = nil;
[_remotePeerID release];
[_connectionQ release];
[_writeQ release];
[_readQ release];
[_characteristicHandlers release];
[_characteristicData release];
[_dataCache release];
[_writerLatch release];
[super dealloc];
}
- (NSString *__nonnull)getIdentifier {
if (self.clientSideIdentifier != nil) {
return self.clientSideIdentifier;
}
return self.serverSideIdentifier;
}
- (void)closeL2cap {
[self.logger d:@"closeL2cap: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (self.l2capChannel != nil) {
[self.l2capChannel.inputStream close];
[self.l2capChannel.outputStream close];
if (self.l2capThread != nil) {
[self.l2capThread cancel];
[self.l2capThread release];
self.l2capThread = nil;
}
}
}
- (void)closeBertyDevice {
@synchronized (self) {
[self.logger d:@"closeBertyDevice: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (!self.isDisconnecting) {
self.isDisconnecting = TRUE;
[self.connectionQ clear];
[self.writeQ clear];
[self.readQ clear];
[self closeL2cap];
if (self.peer != nil) {
[self.manager.peerManager unregisterDevice:self];
self.peer = nil;
}
} else {
[self.logger d:@"closeBertyDevice: device=%@ is already disconnecting", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
self.isDisconnecting = FALSE;
}
}
- (BOOL)handlePeerID:(NSData *__nonnull)peerIDData {
if (self.peer != nil && [self.peer isConnected]) {
[self.logger e:@"handlePeerID: device=%@: peer already connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
NSMutableData *tmpData = [self.characteristicData objectForKey:[BleManager.peerUUID UUIDString]];
if ([peerIDData isEqual:[EOD dataUsingEncoding:NSUTF8StringEncoding]]) {
// adding 0 byte
unsigned char zeroByte = 0;
@synchronized (tmpData) {
[tmpData appendBytes:&zeroByte length:1];
}
NSString *remotePeerID = [NSString stringWithUTF8String:[tmpData bytes]];
// reset tmpData
[tmpData setLength:0];
[self.logger d:@"handlePeerID: device=%@: current peerID=%@, new peerID=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:self.remotePeerID], [self.logger SensitiveNSObject:remotePeerID]];
self.remotePeerID = remotePeerID;
} else {
@synchronized (tmpData) {
[self.logger d:@"handlePeerID: device=%@: add to buffer data=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:peerIDData]];
[tmpData appendData:peerIDData];
}
}
return TRUE;
}
- (BOOL)putIncomingDataInCache:(NSData *__nonnull)data {
@try {
[self.dataCache offer:data];
}
@catch (NSException *e) {
[self.logger e:@"putIncomingDataInCache error: device=%@: cannot add data in cache", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
return TRUE;
}
- (BOOL)handleIncomingData:(NSData *__nonnull)data {
[self.logger d:@"handleIncomingData called: identifier=%@ len=%lu base64=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [data length], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]]];
if ([self.logger showSensitiveData]) {
[BleManager printLongLog:[BleManager NSDataToHex:data]];
}
if (self.l2capClientHandshakeRunning) {
[self.l2capHandshakeRecvData appendBytes:data length:[data length]];
if ([self.l2capHandshakeRecvData length] < L2CAP_HANDSHAKE_DATA) {
[self.logger d:@"handleIncomingData: device=%@: client handshake received incompleted payload: length=%lu", [self.logger SensitiveNSObject:[self getIdentifier]], [self.l2capHandshakeRecvData length]];
} else if ([self.l2capHandshakeRecvData length] == L2CAP_HANDSHAKE_DATA) {
if ([data isEqualToData:self.l2capHandshakeData]) {
[self.logger d:@"handleIncomingData: device=%@: client handshake received payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capHandshakeStepStatus = TRUE;
dispatch_block_cancel(self.l2capHandshakeBlock);
[self.l2capHandshakeLatch countDown];
} else {
[self.logger e:@"handleIncomingData: device=%@: client handshake received wrong payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
dispatch_block_cancel(self.l2capHandshakeBlock);
[self.l2capHandshakeLatch countDown];
[self.manager disconnect:self];
}
} else {
[self.logger e:@"handleIncomingData: device=%@: client handshake received bigger payload than expected: length=%lu", [self.logger SensitiveNSObject:[self getIdentifier]], [self.l2capHandshakeRecvData length]];;
}
} else if (self.l2capServerHandshakeRunning) {
if (!self.l2capHandshakeStepStatus) {
[self.logger d:@"handleIncomingData: device=%@: server handshake received payload, going to write it back", [self.logger SensitiveNSObject:[self getIdentifier]]];
// the server side needs to know when it receives all 1st step data, so it must count data len
self.l2capHandshakeRecvDataLen += [data length];
if (self.l2capHandshakeRecvDataLen == L2CAP_HANDSHAKE_DATA) {
self.l2capHandshakeStepStatus = TRUE;
self.l2capHandshakeRecvDataLen = 0;
}
if (![self l2capWrite:data]) {
[self.logger e:@"handleIncomingData: device=%@: server handshake write error", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capServerHandshakeRunning = FALSE;
self.l2capHandshakeStepStatus = FALSE;
}
} else if ([data isEqualToData:[self.manager.localPID dataUsingEncoding:NSUTF8StringEncoding]]) {
[self.logger d:@"handleIncomingData: device=%@: server handshake received second payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capServerHandshakeRunning = FALSE;
self.useL2cap = TRUE;
} else {
[self.logger e:@"handleIncomingData: device=%@: server handshake received wrong payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
} else {
if (!self.peer) {
[self.logger e:@"handleIncomingData: device=%@: peer not existing", [self.logger SensitiveNSObject:[self getIdentifier]]];
return [self putIncomingDataInCache:data];
}
if (![self.peer isConnected]) {
[self.logger d:@"handleIncomingData: device=%@: peer not connected, put data in cache", [self.logger SensitiveNSObject:[self getIdentifier]]];
return [self putIncomingDataInCache:data];
}
[self.readQ add:^{
BLEBridgeReceiveFromPeer(self.remotePeerID, data);
[self.readQ completedTask:nil];
} withCallback:nil withDelay:0];
}
return TRUE;
}
// Need to copy blocks into the heap because writing is async and the handshake function's stack should not be available
- (void)handshake {
if (![self writeToCharacteristic:[self.manager.localPID dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.peerIDCharacteristic withEOD:TRUE]) {
[self.manager disconnect:self];
return ;
}
if (![self readToCharacteristic:self.peerIDCharacteristic]) {
[self.manager disconnect:self];
return ;
}
[self negotiateL2cap];
if (![self setNotifyValue]) {
[self.manager disconnect:self];
}
}
- (BOOL)setNotifyValue {
if (self.peripheral != nil && self.peripheral.state == CBPeripheralStateConnected) {
[self.logger d:@"setNotifyValue: going to subscribe to writer notifications"];
[self.writeQ add:^{
if (self.peripheral != nil && self.peripheral.state == CBPeripheralStateConnected) {
[self.logger d:@"setNotifyValue: subscribing to writer notifications"];
[self.peripheral setNotifyValue:TRUE forCharacteristic:self.writerCharacteristic];
}
} withCallback:nil withDelay:0];
return TRUE;
}
return FALSE;
}
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices {
CBService *service = getService(invalidatedServices, [BleManager.serviceUUID UUIDString]);
if (service == nil) {
return;
}
[self.logger d:@"didModifyServices: device=%@ service=%@", [self.logger SensitiveNSObject:[self getIdentifier]], invalidatedServices];
[self.manager disconnect:self];
}
- (void)handleConnect:(NSError *)error {
[self.connectionQ completedTask:error];
if (error) {
[self.logger e:@"handleConnect error: device=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], error];
[self.manager disconnect:self];
return;
}
[self.logger i:@"handleConnect: device=%@: connection successed", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self discoverServices:@[self.manager.serviceUUID]];
}
- (void)connectWithOptions:(NSDictionary *)options {
[self.logger d:@"connectWithOptions called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.connectionQ add:^{
[self.logger d:@"connectWithOptions: device=%@: in queue for connecting", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager.cManager connectPeripheral:self.peripheral options:nil];
} withCallback:nil withDelay:0];
}
#pragma mark - write functions
- (void)flushCache {
[self.logger d:@"flushCache called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
while ([self.dataCache element] != [NSNull null]) {
NSData *data = [[self.dataCache poll] retain];
[self.logger d:@"flushCache: device=%@ base64=%@ data=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]], [self.logger SensitiveNSObject:[BleManager NSDataToHex:data]]];
BLEBridgeReceiveFromPeer(self.remotePeerID, data);
[data release];
}
}
- (NSData *)getDataToSend {
NSData *result = nil;
if (self.remainingData == nil || self.remainingData.length <= 0) {
return result;
}
NSUInteger chunckSize = self.remainingData.length > [self.peripheral maximumWriteValueLengthForType:CBCharacteristicWriteWithResponse] ? [self.peripheral maximumWriteValueLengthForType:CBCharacteristicWriteWithResponse] : self.remainingData.length;
result = [NSData dataWithBytes:[self.remainingData bytes] length:chunckSize];
if (self.remainingData.length <= chunckSize) {
self.remainingData = nil;
} else {
self.remainingData = [[NSData alloc]
initWithBytes:[self.remainingData bytes] + chunckSize
length:[self.remainingData length] - chunckSize];
}
return result;
}
- (BOOL)writeToCharacteristic:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic withEOD:(BOOL)eod {
@synchronized (self.writerLatch) {
[self.logger d:@"writeToCharacteristic called: device=%@ base64=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]]];
if ([self.logger showSensitiveData]) {
[BleManager printLongLog:[BleManager NSDataToHex:data]];
}
__block BOOL success = FALSE;
NSData *toSend = nil;
self.remainingData = data;
while (self.remainingData.length > 0) {
if (self.peripheral != nil && self.peripheral.state == CBPeripheralStateConnected) {
toSend = [[self getDataToSend] retain];
CountDownLatch *countDownLatch = [[CountDownLatch alloc] initCount:1];
[self.logger d:@"writeToCharacteristic: device=%@: going to write payload=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:[toSend base64EncodedStringWithOptions:0]]];
[self.writeQ add:^{
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"writeToCharacteristic error: device=%@ not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = FALSE;
[countDownLatch countDown];
return ;
}
[self.logger d:@"writeToCharacteristic: device=%@: writing base64=%@ data=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:[toSend base64EncodedStringWithOptions:0]], [self.logger SensitiveNSObject:[BleManager NSDataToHex:toSend]]];
[self.peripheral writeValue:toSend forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} withCallback:^(NSError *error){
[self.logger d:@"writeToCharacteristic: device=%@: callback called for payload=%@ status=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [self.logger SensitiveNSObject:[toSend base64EncodedStringWithOptions:0]], error];
success = error == nil ? TRUE : FALSE;
[countDownLatch countDown];
} withDelay:0];
[countDownLatch await];
[countDownLatch release];
[toSend release];
// don't write EOD is error occurred
if (!success) {
[self.logger e:@"writeToCharacteristic error: device=%@: cancellation of the following writes", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
} else {
[self.logger e:@"writeToCharacteristic error: device=%@ not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
}
if (eod) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self.logger d:@"writeToCharacteristic: device=%@ going to write EOD", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.writeQ add:^{
[self.logger d:@"writeToCharacteristic: device=%@ writing EOD", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.peripheral writeValue:[@"EOD" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} withCallback:^(NSError *error){
[self.logger d:@"writeToCharacteristic: device=%@: callback called for EOD", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = error == nil ? 1 : 0;
dispatch_semaphore_signal(sema);
} withDelay:0];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
return success;
}
}
- (BOOL)readToCharacteristic:(CBCharacteristic *) characteristic {
[self.logger d:@"readToCharacteristic called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"readToCharacteristic error: device=%@ is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
__block BOOL success = FALSE;
CountDownLatch *countDownLatch = [[CountDownLatch alloc] initCount:1];
[self.writeQ add:^{
[self.logger d:@"readToCharacteristic: device=%@: in queue", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"readToCharacteristic: device=%@ is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = FALSE;
[countDownLatch countDown];
return ;
}
[self.peripheral readValueForCharacteristic:characteristic];
} withCallback:^(NSError *error){
if (error == nil) {
[self.logger d:@"readToCharacteristic: device=%@: callback called with success", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = TRUE;
} else {
[self.logger e:@"readToCharacteristic error: device=%@ error=%@ in callback", [self.logger SensitiveNSObject:[self getIdentifier]], error];
success = FALSE;
}
[countDownLatch countDown];
} withDelay:0];
[countDownLatch await];
[countDownLatch release];
return success;
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
[self.writeQ completedTask:error];
if (error) {
[self.logger e:@"didUpdateNotificationStateForCharacteristic error: device=%@ characteristic=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [characteristic.UUID UUIDString], error];
[self.manager disconnect:self];
return;
}
self.peer = [self.manager.peerManager registerDevice:self withPeerID:self.remotePeerID isClient:TRUE];
if (self.peer == nil) {
[self.logger e:@"didUpdateNotificationStateForCharacteristic error: device=%@: registerDevice failed", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
} else {
[self.logger d:@"didUpdateNotificationStateForCharacteristic: device=%@: registerDevice successed", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
}
// Called when the value of the characteristic changed, whether by readValueForCharacteristic: or by a notification after a subscription
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
[self.logger d:@"didUpdateValueForCharacteristic called: device=%@ characteristic=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [characteristic.UUID UUIDString]];
if (error) {
[self.logger e:@"didUpdateValueForCharacteristic error: device=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], error];
[self.manager disconnect:self];
[self.writeQ completedTask:error];
return;
}
if ([characteristic.UUID isEqual:self.manager.peerUUID]) {
if (characteristic.value != nil) {
int psm;
[[characteristic.value subdataWithRange:NSMakeRange(0, 4)] getBytes:&psm length:sizeof(psm)];
self.psm = NSSwapBigIntToHost(psm);
NSString* remotePeerID = [NSString stringWithUTF8String: [[characteristic.value subdataWithRange:NSMakeRange(4, characteristic.value.length - 4)] bytes]];
[self.logger d:@"didUpdateValueForCharacteristic: device=%@ PSM=%d remotePID=%@", [self.logger SensitiveNSObject:[self getIdentifier]], self.psm, [self.logger SensitiveNSObject:remotePeerID]];
self.remotePeerID = remotePeerID;
[self.writeQ completedTask:nil];
} else {
[self.logger e:@"didUpdateValueForCharacteristic error: device=%@: characteristic doesn't have any value", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.writeQ completedTask:[NSError errorWithDomain:@LOCAL_DOMAIN code:200 userInfo:@{@"Error reason": @"Empty value"}]];
}
} else if ([characteristic.UUID isEqual:self.manager.writerUUID]) {
[self handleIncomingData:characteristic.value];
} else {
[self.logger e:@"didUpdateValueForCharacteristic error: device=%@: bad characteristic requested", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
[self.logger d:@"didWriteValueForCharacteristic called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (error) {
[self.logger e:@"didWriteValueForCharacteristic error: device=%@ characteristic=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [characteristic.UUID UUIDString], error];
}
[self.writeQ completedTask:error];
}
#pragma mark - Characteristic Discovery
- (void)discoverCharacteristics:(nullable NSArray *)characteristics forService:(CBService *)service {
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"discoverCharacteristics error: device=%@ is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
return ;
}
[self.connectionQ add:^{
[self.peripheral discoverCharacteristics:characteristics forService:service];
} withCallback:nil withDelay:0];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
[self.logger d:@"didDiscoverCharacteristicsForService called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.connectionQ completedTask:error];
if (error) {
[self.logger e:@"didDiscoverCharacteristicsForService error: device=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], error];
[self.manager disconnect:self];
return;
}
for (CBCharacteristic *chr in service.characteristics) {
if ([chr.UUID isEqual:self.manager.peerUUID]) {
self.peerIDCharacteristic = chr;
[self.logger d:@"didDiscoverCharacteristicsForService: device=%@: peerID characteristic found", [self.logger SensitiveNSObject:[self getIdentifier]]];
} else if ([chr.UUID isEqual:self.manager.writerUUID]) {
self.writerCharacteristic = chr;
[self.logger d:@"didDiscoverCharacteristicsForService: device=%@: writer characteristic found", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
}
if (self.peerIDCharacteristic == nil || self.writerCharacteristic == nil) {
[self.logger e:@"didDiscoverCharacteristicsForService error: device=%@: not all characteristics found", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
return ;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self handshake];
});
}
#pragma mark - Services Discovery
- (void)discoverServices:(NSArray *)serviceUUIDs {
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"discoverServices error: device=%@ is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
return ;
}
self.peripheral.delegate = self;
[self.connectionQ add:^{
[self.peripheral discoverServices:serviceUUIDs];
} withCallback:nil withDelay:0];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
[self.logger d:@"didDiscoverServices called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.connectionQ completedTask:error];
if (error) {
[self.logger e:@"didDiscoverServices error: device=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], error];
[self.manager disconnect:self];
return;
}
CBService *service = getService(self.peripheral.services, [self.manager.serviceUUID UUIDString]);
if (service == nil) {
[self.logger e:@"didDiscoverServices error: device=%@: service not found", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
return;
}
[self discoverCharacteristics:@[self.manager.peerUUID, self.manager.writerUUID,] forService:service];
}
#pragma mark - L2cap
- (BOOL) negotiateL2cap {
[self.logger d:@"negotiateL2cap called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (self.peripheral == nil || self.peripheral.state != CBPeripheralStateConnected) {
[self.logger e:@"negotiateL2cap error: device=%@ is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
__block BOOL success = FALSE;
CountDownLatch *countDownLatch = [[CountDownLatch alloc] initCount:1];
if (@available(iOS 11.0, *)) {
if (self.psm != 0) {
[self.connectionQ add:^{
[self.logger d:@"negotiateL2cap: device=%@: opening L2cap channel", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.peripheral openL2CAPChannel:self.psm];
} withCallback:^(NSError *error){
if (error == nil) {
[self.logger d:@"negotiateL2cap: device=%@: callback called with success", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = TRUE;
} else {
[self.logger e:@"negotiateL2cap error: device=%@ error=%@ in callback", [self.logger SensitiveNSObject:[self getIdentifier]], error];
success = FALSE;
}
[countDownLatch countDown];
} withDelay:0];
[countDownLatch await];
[countDownLatch release];
} else {
[self.logger d:@"negotiateL2cap: device=%@: central peripheral doesn't support L2CAP, aborting negotiation", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = TRUE; // return TRUE to continue connection without L2cap
}
} else {
[self.logger d:@"negotiateL2cap: device=%@: iOS 11+ is required", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = TRUE; // return TRUE to continue connection without L2cap
}
return success;
}
- (BOOL)l2capWrite:(NSData *__nonnull)data {
__block BOOL success = FALSE;
if (self.l2capChannel != nil) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self.writeQ add:^{
@synchronized (self.writerLatch) {
[self.logger d:@"l2capWrite: device=%@ len=%lu base64=%@", [self.logger SensitiveNSObject:[self getIdentifier]], [data length], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]]];
if ([self.logger showSensitiveData]) {
[BleManager printLongLog:[BleManager NSDataToHex:data]];
}
self.l2capWriteIndex = 0;
self.l2capWriteData = data;
if ([self.l2capChannel.outputStream hasSpaceAvailable]) {
uint8_t *readBytes = (uint8_t *)[self.l2capWriteData bytes];
NSUInteger data_len = [data length];
NSUInteger len = (data_len >= L2CAP_BUFFER) ? L2CAP_BUFFER : (data_len);
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
self.l2capWriteIndex = [self.l2capChannel.outputStream write:(const uint8_t *)buf maxLength:len];
[self.logger d:@"l2capWrite: device=%@: wrote len=%zd", [self.logger SensitiveNSObject:[self getIdentifier]], self.l2capWriteIndex];
if (self.l2capWriteIndex == -1) {
[self.logger e:@"l2capWrite error: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]], self.l2capWriteIndex];
self.l2capWriteData = nil;
[self.writeQ completedTask:[NSError errorWithDomain:@LOCAL_DOMAIN code:200 userInfo:@{@"Error reason": @"write error"}]];
return ;
}
if (self.l2capWriteIndex < data_len) { // write next data chunk when callback stream handleEvent: NSStreamEventHasSpaceAvailable is called
[self.logger d:@"l2capWrite: device=%@: write completed but need more write space to send all data, waiting...", [self.logger SensitiveNSObject:[self getIdentifier]], self.l2capWriteIndex];
} else {
[self.logger d:@"l2capWrite: device=%@: write completed and all data send", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capWriteData = nil;
[self.writeQ completedTask:nil];
}
} else {
[self.logger d:@"l2capWrite: device=%@: need some space available, waiting...", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
}
} withCallback:^(NSError *error) {
if (error == nil) {
[self.logger d:@"l2capWrite: device=%@: callback called with success", [self.logger SensitiveNSObject:[self getIdentifier]]];
success = TRUE;
} else {
[self.logger e:@"l2capWrite error: device=%@ error=%@ in callback", [self.logger SensitiveNSObject:[self getIdentifier]], error];
success = FALSE;
}
dispatch_semaphore_signal(sema);
} withDelay:0];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
return success;
} else {
[self.logger e:@"l2capWrite error: device=%@: channel not set", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
}
- (void)peripheral:(CBPeripheral *)peripheral didOpenL2CAPChannel:(CBL2CAPChannel *)channel error:(NSError *)error API_AVAILABLE(ios(11.0)) {
[self.logger d:@"didOpenL2CAPChannel called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (error != nil) {
[self.logger e:@"didOpenL2CAPChannel Error: device=%@ error=%@", [self.logger SensitiveNSObject:[self getIdentifier]], error];
[self.connectionQ completedTask:error];
return ;
}
self.l2capChannel = channel;
self.l2capThread = [[NSThread alloc] initWithTarget:self selector:@selector(setupL2capStreams) object:nil];
[self.l2capThread start];
self.l2capClientHandshakeRunning = TRUE;
self.useL2cap = [self testL2cap];
self.l2capClientHandshakeRunning = FALSE;
// wait that server complete L2CAP tests
[NSThread sleepForTimeInterval:2.0f];
[self.connectionQ completedTask:nil];
}
- (void)setupL2capStreams {
[self.logger d:@"setupL2capStreams called: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capChannel.inputStream.delegate = self;
[self.l2capChannel.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.l2capChannel.inputStream open];
self.l2capChannel.outputStream.delegate = self;
[self.l2capChannel.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.l2capChannel.outputStream open];
@autoreleasepool {
do {
[[NSRunLoop currentRunLoop] run];
} while (self.peer != nil && [self.peer isConnected]);
}
}
- (NSMutableData *__nonnull)createRandomNSData:(int) capacity
{
NSMutableData* theData = [NSMutableData dataWithCapacity:capacity];
for (unsigned int i = 0 ; i < capacity / 4 ; ++i ) {
u_int32_t randomBits = arc4random();
[theData appendBytes:(void *)&randomBits length:4];
}
return theData;
}
// Test contains 2 steps:
// 1) client sends local PID and waits for receiving remote PID
// 2) client sends remote PID in response of 1) to the server
- (BOOL)testL2cap {
self.l2capHandshakeStepStatus = FALSE;
self.l2capHandshakeRecvData = [NSMutableData dataWithCapacity:L2CAP_HANDSHAKE_DATA];
self.l2capHandshakeLatch = [[CountDownLatch alloc] initCount:1];
self.l2capHandshakeBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
[self.logger e:@"testL2cap: device=%@: timeout hired", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.l2capHandshakeLatch countDown];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), self.l2capHandshakeBlock);
// step 1
[self.logger d:@"testL2cap: device=%@: client going to write the 1st payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capHandshakeData = [self createRandomNSData:L2CAP_HANDSHAKE_DATA];
if (![self l2capWrite:self.l2capHandshakeData]) {
[self.logger e:@"testL2cap error: device=%@: client write error", [self.logger SensitiveNSObject:[self getIdentifier]]];
dispatch_block_cancel(self.l2capHandshakeBlock);
self.l2capHandshakeData = nil;
self.l2capHandshakeRecvData = nil;
return FALSE;
}
// waiting for receiving remote PID
[self.l2capHandshakeLatch await];
self.l2capHandshakeData = nil;
self.l2capHandshakeRecvData = nil;
// step 2
if (self.l2capHandshakeStepStatus) {
[self.logger d:@"testL2cap: device=%@: client going to write the 2nd payload", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (![self l2capWrite:[self.remotePeerID dataUsingEncoding:NSUTF8StringEncoding]]) {
[self.logger e:@"testL2cap error: device=%@: client write error", [self.logger SensitiveNSObject:[self getIdentifier]]];
return FALSE;
}
[self.logger d:@"testL2cap: device=%@: client handshake completed", [self.logger SensitiveNSObject:[self getIdentifier]]];
return TRUE;
}
return FALSE;
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventNone: {
[self.logger d:@"stream handleEvent: NSStreamEventNone: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
break;
}
case NSStreamEventOpenCompleted: {
[self.logger d:@"stream handleEvent: NSStreamEventOpenCompleted: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
break;
}
case NSStreamEventHasBytesAvailable: {
[self.logger d:@"stream handleEvent: NSStreamEventHasBytesAvailable: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
uint8_t buf[L2CAP_BUFFER];
NSInteger len = 0;
len = [(NSInputStream *)stream read:buf maxLength:L2CAP_BUFFER];
if(len > 0) {
NSData *received = [NSData dataWithBytes:buf length:len];
[self.logger d:@"stream handleEvent: NSStreamEventHasBytesAvailable: device=%@ read length=%lu value=%@", [self.logger SensitiveNSObject:[self getIdentifier]], len, [self.logger SensitiveNSObject:received]];
[self handleIncomingData:received];
} else {
[self.logger e:@"stream handleEvent error: NSStreamEventHasBytesAvailable: device=%@: nothing to read", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
break;
}
case NSStreamEventHasSpaceAvailable: {
[self.logger d:@"stream handleEvent: NSStreamEventHasSpaceAvailable: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if ((self.peer != nil && [self.peer isConnected]) || self.l2capServerHandshakeRunning || self.l2capClientHandshakeRunning) {
@synchronized (self.writerLatch) {
if (self.l2capWriteData != nil) {
uint8_t *readBytes = (uint8_t *)[self.l2capWriteData bytes];
readBytes += self.l2capWriteIndex;
NSUInteger data_len = [self.l2capWriteData length];
NSUInteger len = ((data_len - self.l2capWriteIndex >= L2CAP_BUFFER) ? L2CAP_BUFFER : (data_len - self.l2capWriteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
if ([self.logger showSensitiveData]) {
[self.logger d:@"stream handleEvent: NSStreamEventHasSpaceAvailable: device=%@ offset=%lu len=%lu base64=%@ data=%@", [self getIdentifier], self.l2capWriteIndex, len, [[NSData dataWithBytes:buf length:len] base64EncodedStringWithOptions:0], [BleManager NSDataToHex:[NSData dataWithBytes:buf length:len]]];
}
NSInteger wroteLen = [(NSOutputStream *)stream write:(const uint8_t *)buf maxLength:len];
[self.logger d:@"stream handleEvent: NSStreamEventHasSpaceAvailable: device=%@ wrote data offset=%lu len=%zd", [self.logger SensitiveNSObject:[self getIdentifier]], self.l2capWriteIndex, wroteLen];
if (wroteLen == -1) {
[self.logger e:@"stream handleEvent error: NSStreamEventHasSpaceAvailable: device=%@ write: error", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capWriteData = nil;
[self.writeQ completedTask:[NSError errorWithDomain:@LOCAL_DOMAIN code:200 userInfo:@{@"Error reason": @"write error"}]];
break;
}
self.l2capWriteIndex += wroteLen;
if ([self.l2capWriteData length] == self.l2capWriteIndex) {
[self.logger d:@"stream handleEvent: NSStreamEventHasSpaceAvailable: device=%@: write completed", [self.logger SensitiveNSObject:[self getIdentifier]]];
self.l2capWriteData = nil;
[self.writeQ completedTask:nil];
}
} else {
[self.logger d:@"stream handleEvent: NSStreamEventHasSpaceAvailable: device=%@: no data to write", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
}
} else {
[self.logger e:@"stream handleEvent error: NSStreamEventHasSpaceAvailable: device=%@: device is not connected", [self.logger SensitiveNSObject:[self getIdentifier]]];
}
break;
}
case NSStreamEventErrorOccurred: {
[self.logger d:@"stream handleEvent: NSStreamEventErrorOccurred: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self.manager disconnect:self];
break;
}
case NSStreamEventEndEncountered: { // (d4ryl00): not sure how to handle this case
[self.logger d:@"stream handleEvent: NSStreamEventEndEncountered: device=%@", [self.logger SensitiveNSObject:[self getIdentifier]]];
if (self.l2capChannel.outputStream == stream) {
NSData *newData = [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
if (!newData) {
[self.logger d:@"stream handleEvent: NSStreamEventEndEncountered: device=%@: no more data", [self.logger SensitiveNSObject:[self getIdentifier]]];
} else {
[self.logger d:@"stream handleEvent: NSStreamEventEndEncountered: device=%@: data to process", [self.logger SensitiveNSObject:[self getIdentifier]]];
[self handleIncomingData:newData];
}
}
stream.delegate = nil;
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
if (self.l2capThread != nil) {
[self.l2capThread cancel];
[self.l2capThread release];
self.l2capThread = nil;
}
[self.manager disconnect:self];
break;
}
}
}
@end
================================================
FILE: pkg/ble-driver/BleInterface_darwin.h
================================================
//
// BleInterface.h
// ble
//
// Created by sacha on 26/09/2018.
// Copyright © 2018 sacha. All rights reserved.
//
#import
#import
#import
#import
#import "BleManager_darwin.h"
#import "Logger.h"
#ifndef BleInterface_h
#define BleInterface_h
void BLEStart(char *localPID);
void BLEStop(void);
int BLESendToPeer(char *remotePID, void *payload, int length);
int BLEDialPeer(char *remotePID);
void BLECloseConnWithPeer(char *remotePID);
int BLEBridgeHandleFoundPeer(NSString *remotePID);
void BLEBridgeHandleLostPeer(NSString *remotePID);
void BLEBridgeReceiveFromPeer(NSString *remotePID, NSData *payload);
void BLEBridgeLog(enum level level, NSString *message);
void BLEUseExternalLogger(void);
#endif /* BleInterface_h */
================================================
FILE: pkg/ble-driver/BleInterface_darwin.m
================================================
// +build darwin,!noproximitytransport
//
// BleInterface.m
// ble
//
// Created by sacha on 26/09/2018.
// Copyright © 2018 sacha. All rights reserved.
//
#import "BleInterface_darwin.h"
// This functions are Go functions so they aren't defined here
extern int BLEHandleFoundPeer(char *);
extern void BLEHandleLostPeer(char *);
extern void BLEReceiveFromPeer(char *, void *, unsigned long);
extern void BLELog(enum level level, const char *message);
static BleManager *manager = nil;
BOOL gBLEUseExternalLogger = FALSE;
void handleException(NSException* exception) {
NSLog(@"Unhandled exception %@", exception);
}
BleManager* getManager(void) {
@synchronized([BleManager class])
{
if(!manager) {
NSLog(@"BleManager: initialization");
manager = [[BleManager alloc] initDriver:gBLEUseExternalLogger];
}
}
return manager;
}
void releaseManager(void) {
@synchronized([BleManager class])
{
if(manager) {
NSLog(@"releaseManager");
[manager release];
manager = nil;
}
}
}
#pragma mark - incoming API functions
void BLEStart(char *localPID) {
NSLog(@"BLEStart called");
@autoreleasepool {
NSString *localPIDString = [NSString stringWithUTF8String:localPID];
[getManager() setLocalPID:localPIDString];
[getManager().logger i:@"BLEStart: pid=%@", [getManager().logger SensitiveNSObject:localPIDString]];
[getManager() setID:[localPIDString substringWithRange:NSMakeRange([localPIDString length] - 4, 4)]];
[getManager() startScanning];
[getManager() startAdvertising];
NSSetUncaughtExceptionHandler(handleException);
}
}
// TODO: Implement this, check if error
void BLEStop(void) {
[getManager().logger i:@"BLEStop"];
[getManager() stopScanning];
[getManager() stopAdvertising];
[getManager() closeAllConnections];
releaseManager();
}
int BLESendToPeer(char *remotePID, void *payload, int length) {
int status = 0;
NSString *cPID = [[NSString alloc] initWithUTF8String:remotePID];
NSData *cPayload = [[NSData alloc] initWithBytes:payload length:length];
BertyDevice *bDevice = [getManager() findPeripheralFromPID:cPID];
if (bDevice == nil) {
[getManager().logger e:@"BLESendToPeer error: no device found"];
return 0;
}
if (bDevice.peer == nil) {
[getManager().logger e:@"BLESendToPeer error: peer object not found"];
return 0;
}
if (bDevice.useL2cap && bDevice.l2capChannel != nil) {
status = [bDevice l2capWrite:cPayload];
} else {
if ([bDevice.peer isClientReady]) {
status = [bDevice writeToCharacteristic:cPayload forCharacteristic:bDevice.writerCharacteristic withEOD:FALSE];
} else if ([bDevice.peer isServerReady]) {
status = [getManager() writeAndNotify:bDevice data:cPayload];
} else {
[getManager().logger e:@"BLESendToPeer error: device not connected"];
}
}
[cPID release];
[cPayload release];
return status;
}
int BLEDialPeer(char *remotePID) {
BertyDevice *bDevice = [getManager() findPeripheralFromPID:[NSString stringWithUTF8String:remotePID]];
if (bDevice != nil) {
return 1;
}
return 0;
}
// TODO: Implement this
void BLECloseConnWithPeer(char *remotePID) {
[getManager().logger i:@"BLECloseConnWithPeer called: remotePID=%@", [getManager().logger SensitiveString:remotePID]];
BertyDevice *bDevice = [getManager() findPeripheralFromPID:[NSString stringWithUTF8String:remotePID]];
if (bDevice != nil) {
[getManager() disconnect:bDevice];
}
}
// Use BLEBridgeLog to write logs to the external logger
void BLEUseExternalLogger(void) {
gBLEUseExternalLogger = TRUE;
}
#pragma mark - outgoing API functions
int BLEBridgeHandleFoundPeer(NSString *remotePID) {
char *cPID = (char *)[remotePID UTF8String];
if (BLEHandleFoundPeer(cPID)) {
return (1);
}
return (0);
}
void BLEBridgeHandleLostPeer(NSString *remotePID) {
char *cPID = (char *)[remotePID UTF8String];
BLEHandleLostPeer(cPID);
}
void BLEBridgeReceiveFromPeer(NSString *remotePID, NSData *payload) {
char *cPID = (char *)[remotePID UTF8String];
char *cPayload = (char *)[payload bytes];
int length = (int)[payload length];
BLEReceiveFromPeer(cPID, cPayload, length);
}
// Write logs to the external logger
void BLEBridgeLog(enum level level, NSString *message) {
char *cMessage = (char *)[message UTF8String];
BLELog(level, cMessage);
}
================================================
FILE: pkg/ble-driver/BleManager_darwin.h
================================================
//
// BleManager.h
// ble
//
// Created by sacha on 23/05/2019.
// Copyright © 2019 berty. All rights reserved.
//
#import
#import
#import "BleInterface_darwin.h"
#import "BertyDevice_darwin.h"
#import "PeerManager.h"
#import "CountDownLatch_darwin.h"
#import "WriteDataCache.h"
#define LOCAL_DOMAIN "tech.berty.bty"
NS_ASSUME_NONNULL_BEGIN
@interface BleManager : NSObject
+ (CBUUID *__nonnull)serviceUUID;
+ (CBUUID *__nonnull)peerUUID;
+ (CBUUID *__nonnull)writerUUID;
+ (NSString *__nonnull)NSDataToHex:(NSData *__nonnull)data;
+ (void) printLongLog:(NSString *__nonnull)message;
@property (nonatomic, strong, nullable) Logger *logger;
@property (nonatomic, strong, nonnull) PeerManager *peerManager;
@property (readwrite) BOOL pmEnable;
@property (readwrite) BOOL cmEnable;
@property (readwrite) int psm;
@property (nonatomic, strong, nonnull) CBMutableService *bertyService;
@property (nonatomic, strong, nonnull) CBMutableService *nameService;
@property (nonatomic, strong, nonnull) CBMutableCharacteristic *peerIDCharacteristic;
@property (nonatomic, strong, nonnull) CBMutableCharacteristic *writerCharacteristic;
@property (nonatomic, strong, nullable) NSString *localPID;
@property (nonatomic, strong, nonnull) NSString *ID;
@property (nonatomic, strong, nonnull) CBUUID *serviceUUID;
@property (nonatomic, strong, nonnull) CBUUID *peerUUID;
@property (nonatomic, strong, nonnull) CBUUID *writerUUID;
@property (nonatomic, strong, nonnull) NSMutableArray *bDevices;
@property (nonatomic, strong, nonnull) CBCentralManager* cManager;
@property (nonatomic, strong, nonnull) CBPeripheralManager* pManager;
@property (nonatomic, strong, nonnull) CountDownLatch *bleOn;
@property (nonatomic, strong, nonnull) CountDownLatch *serviceAdded;
@property (nonatomic, strong, nullable) NSTimer *scannerTimer;
@property (nonatomic, readwrite, getter=isScanning) BOOL scanning;
@property (nonatomic, strong, nullable) WriteDataCache *writeCache;
@property (nonatomic, strong, nullable) CountDownLatch *writerLactch;
@property (readwrite) BOOL writeStatus;
- (instancetype __nonnull) initDriver:(BOOL)useExternalLogger;
- (void)addService;
- (void)startScanning;
- (void)toggleScanner:(NSTimer *__nonnull)timer;
- (void)stopScanning;
- (void)startAdvertising;
- (void)stopAdvertising;
- (void)disconnect:(BertyDevice *__nonnull)device;
- (void)closeAllConnections;
- (BertyDevice *__nullable)findPeripheralFromIdentifier:(NSUUID *__nonnull)identifier;
- (BertyDevice *__nullable)findPeripheralFromPID:(NSString *__nonnull)peerID;
- (BOOL)writeAndNotify:(BertyDevice *__nonnull)device data:(NSData *__nonnull)data;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/BleManager_darwin.m
================================================
// +build darwin,!noproximitytransport
//
// BleManager.m
// ble
//
// Created by sacha on 23/05/2019.
// Copyright © 2019 berty. All rights reserved.
//
#import "BleManager_darwin.h"
@implementation BleManager
static NSString* const __nonnull SERVICE_UUID = @"00004240-0000-1000-8000-00805F9B34FB";
static NSString* const __nonnull WRITER_UUID = @"00004242-0000-1000-8000-00805F9B34FB";
static NSString* const __nonnull PEER_ID_UUID = @"00004241-0000-1000-8000-00805F9B34FB";
+ (CBUUID *)serviceUUID {
return [CBUUID UUIDWithString:SERVICE_UUID];
}
+ (CBUUID *)peerUUID {
return [CBUUID UUIDWithString:PEER_ID_UUID];
}
+ (CBUUID *)writerUUID {
return [CBUUID UUIDWithString:WRITER_UUID];
}
static inline char itoh(int i) {
if (i > 9) return 'A' + (i - 10);
return '0' + i;
}
+ (NSString *__nonnull)NSDataToHex:(NSData *__nonnull)data {
NSUInteger i, len;
unsigned char *buf, *bytes;
len = data.length;
bytes = (unsigned char*)data.bytes;
buf = malloc(len*2);
for (i=0; i> 4) & 0xF);
buf[i*2+1] = itoh(bytes[i] & 0xF);
}
return [[[NSString alloc] initWithBytesNoCopy:buf
length:len*2
encoding:NSASCIIStringEncoding
freeWhenDone:YES] autorelease];
}
+ (void) printLongLog:(NSString *__nonnull)message {
if ([message length] > 4000) {
NSLog(@"message.length=%lu", [message length]);
unsigned long int chunkCount = [message length] / 4000; // integer division
for (int i = 0; i <= chunkCount; i++) {
int max = 4000 * (i + 1);
if (max >= [message length]) {
NSLog(@"chunk %d of %lu: %@", i, chunkCount, [message substringWithRange:NSMakeRange(4000 * i, [message length] - (4000 * i))]);
} else {
NSLog(@"chunk %d of %lu: %@", i, chunkCount, [message substringWithRange:NSMakeRange(4000 * i, 4000)]);
}
}
} else {
NSLog(@"%@", message);
}
}
// TODO: No need to check error on this?
- (instancetype __nonnull) initDriver:(BOOL)useExternalLogger {
self = [super init];
if (self) {
BOOL showSensitiveData = FALSE;
if (useExternalLogger) {
_logger = [[Logger alloc] initWithExternalLoggerAndShowSensitiveData:showSensitiveData];
} else {
_logger = [[Logger alloc] initLocalLoggerWithSubSystem:LOCAL_DOMAIN andCategorie:"BLE" showSensitiveData:showSensitiveData];
}
_peerManager = [[PeerManager alloc] initWithLogger:_logger];
_cmEnable = FALSE;
_pmEnable = FALSE;
_scannerTimer = nil;
_bleOn = [[CountDownLatch alloc] initCount:2];
_serviceAdded = [[CountDownLatch alloc] initCount:1];
_bDevices = [[NSMutableArray alloc] init];
_cManager = [[CBCentralManager alloc]
initWithDelegate:self
queue:dispatch_queue_create("CentralManager", DISPATCH_QUEUE_SERIAL)
options:@{CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:NO]}];
_pManager = [[CBPeripheralManager alloc]
initWithDelegate:self
queue:dispatch_queue_create("PeripheralManager", DISPATCH_QUEUE_SERIAL)
options:@{CBPeripheralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:NO]}];
[self initService];
[self addService];
}
return self;
}
- (void)initService {
[self.logger d:@"initService called"];
_scanning = FALSE;
_serviceUUID = [[CBUUID UUIDWithString:SERVICE_UUID] retain];
_peerUUID = [[CBUUID UUIDWithString:PEER_ID_UUID] retain];
_writerUUID = [[CBUUID UUIDWithString:WRITER_UUID] retain];
_peerIDCharacteristic = [[CBMutableCharacteristic alloc]
initWithType:self.peerUUID
properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyWrite
value:nil
permissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];
_writerCharacteristic = [[CBMutableCharacteristic alloc]
initWithType:self.writerUUID
properties:CBCharacteristicPropertyWrite | CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsWriteable];
_bertyService = [[CBMutableService alloc] initWithType:self.serviceUUID
primary:YES];
_bertyService.characteristics = [@[self.writerCharacteristic,
self.peerIDCharacteristic] retain];
}
- (void)dealloc {
[_logger release];
[_peerManager release];
[_bleOn release];
[_serviceAdded release];
[_bDevices release];
[_cManager release];
[_pManager release];
[_serviceUUID release];
[_peerUUID release];
[_writerUUID release];
[_peerIDCharacteristic release];
[_writerCharacteristic release];
[_bertyService.characteristics release];
[_bertyService release];
[super dealloc];
}
- (void)addService {
[self.logger d:@"addService: service=%@", [self.serviceUUID UUIDString]];
[self.bleOn await:5 withCancelBlock:^{
[self.logger e:@"addService error: timeout"];
}];
if (self.cmEnable && self.pmEnable) {
[self.pManager addService:self.bertyService];
[self.serviceAdded await];
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(nullable NSError *)error {
if (error) {
[self.logger e:@"didAddService() error=%@", [error localizedFailureReason]];
}
[self.logger d:@"didAddService: service=%@", [service.UUID UUIDString]];
[self.serviceAdded countDown];
}
#pragma mark - go called functions
- (void)startScanning {
@synchronized (self.cManager) {
if (self.cmEnable && !self.scanning) {
if (self.localPID != nil) {
[self.logger d:@"startScanning called"];
NSDictionary *options = [NSDictionary
dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.cManager scanForPeripheralsWithServices:@[self.serviceUUID] options:options];
self.scanning = TRUE;
dispatch_async(dispatch_get_main_queue(), ^(void){
self.scannerTimer = [NSTimer scheduledTimerWithTimeInterval:12.0 target:self selector:@selector(toggleScanner:) userInfo:nil repeats:YES];
});
} else {
[self.logger e:@"startScanning error: localPID is null"];
}
} else {
[self.logger i:@"startScanning: scanner is already enabled"];
}
}
}
- (void)toggleScanner:(NSTimer*)timer {
if ([self.cManager isScanning]) {
[self.logger d:@"toggleScanner: disable scanner"];
[self.cManager stopScan];
} else {
[self.logger d:@"toggleScanner: enable scanner"];
NSDictionary *options = [NSDictionary
dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.cManager scanForPeripheralsWithServices:@[self.serviceUUID] options:options];
}
}
- (void)stopScanning {
@synchronized (self.cManager) {
if (self.cmEnable && self.scanning) {
[self.logger d:@"stopScanning called"];
dispatch_async(dispatch_get_main_queue(), ^{
if (self.scannerTimer != nil) {
if ([self.scannerTimer isValid]) {
[self.scannerTimer invalidate];
}
self.scannerTimer = nil;
}
if ([self.cManager isScanning]) {
[self.cManager stopScan];
}
self.scanning = FALSE;
});
}
}
}
- (void)startAdvertising {
@synchronized (self.pManager) {
if (self.pmEnable && ![self.pManager isAdvertising]) {
if (self.ID != nil) {
[self.logger d:@"startAdvertising called: ID=%@", [self.logger SensitiveNSObject:self.ID]];
// publish l2cap channel
self.psm = 0;
if (@available(iOS 11.0, *)) {
[self.pManager publishL2CAPChannelWithEncryption:false];
}
[self.pManager startAdvertising:@{ CBAdvertisementDataLocalNameKey:self.ID, CBAdvertisementDataServiceUUIDsKey:@[self.serviceUUID]}];
} else {
[self.logger e:@"startAdvertising error: local ID is null"];
}
}
}
}
- (void)stopAdvertising {
@synchronized (self.pManager) {
[self.logger d:@"stopAdvertising called"];
if (self.pmEnable && [self.pManager isAdvertising]) {
if (@available(iOS 11.0, *)) {
if (self.psm != 0) {
[self.pManager unpublishL2CAPChannel:self.psm];
}
}
[self.pManager stopAdvertising];
} else {
[self.logger e:@"stopAdvertising error: advertising not started"];
}
}
}
// Only the client side can disconnect
- (void)disconnect:(BertyDevice *__nonnull)device {
[self.logger d:@"closeAllConnections called: debice=%@", [self.logger SensitiveNSObject:[device clientSideIdentifier]]];
if (device.peripheral != nil && device.clientSideIdentifier != nil) {
[self.logger d:@"disconnect: client device=%@", [self.logger SensitiveNSObject:[device clientSideIdentifier]]];
if (device.peripheral.state == CBPeripheralStateConnecting || device.peripheral.state == CBPeripheralStateConnected) {
[self.cManager cancelPeripheralConnection:device.peripheral];
} else {
[self.logger d:@"disconnect: client device=%@ not connected", [self.logger SensitiveNSObject:[device clientSideIdentifier]]];
return ;
}
} else {
[device closeBertyDevice];
}
}
- (void)closeAllConnections {
[self.logger i:@"closeAllConnections called"];
if (self.cmEnable) {
@synchronized (self.bDevices) {
for (BertyDevice *device in self.bDevices) {
[self disconnect:device];
}
}
}
}
- (BOOL)writeAndNotify:(BertyDevice *__nonnull)device data:(NSData *__nonnull)data {
[self.logger d:@"writeAndNotify: device=%@ base64=%@", [self.logger SensitiveNSObject:[device clientSideIdentifier]], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]]];
if ([self.logger showSensitiveData]) {
[BleManager printLongLog:[BleManager NSDataToHex:data]];
}
BOOL success = FALSE;
NSUInteger mtu = device.cbCentral.maximumUpdateValueLength;
NSUInteger offset = 0;
NSUInteger dataLen = [data length];
while (offset < dataLen) {
if (![device.peer isServerReady]) {
[self.logger e:@"writeAndNotify error: device=%@ server not connected", [self.logger SensitiveNSObject:[device clientSideIdentifier]]];
return FALSE;
}
self.writerLactch = [[CountDownLatch alloc] initCount:1];
NSUInteger toWriteLen = (dataLen - offset) < mtu ? (dataLen - offset) : mtu;
NSData *toWrite = [[data subdataWithRange:NSMakeRange(offset, toWriteLen)] retain];
if ([self.logger showSensitiveData]) {
[self.logger d:@"writeAndNotify: device=%@ mtu=%lu base64=%@ data=%@", [device getIdentifier], mtu, [toWrite base64EncodedStringWithOptions:0], [BleManager NSDataToHex:toWrite]];
}
// Need to add data to the cache prior to write it because sometime peripheralManagerIsReadyToUpdateSubscribers is called before data is put to the cache
@synchronized (self.writeCache) {
self.writeCache = [[WriteDataCache alloc] initWithDevice:device withData:toWrite];
[self.logger d:@"writeAndNotify: device=%@: data put in cache successfully", [self.logger SensitiveNSObject:[device getIdentifier]]];
}
success = [self.pManager updateValue:toWrite forCharacteristic:self.writerCharacteristic onSubscribedCentrals:@[device.cbCentral]];
if (success) {
[self.writerLactch countDown];
} else {
[self.logger d:@"writeAndNotify: device=%@: operation queue is full and will be processed by the peripheralManagerIsReadyToUpdateSubscribers callback", [self.logger SensitiveNSObject:[device getIdentifier]]];
}
[self.writerLactch await];
// take write status from peripheralManagerIsReadyToUpdateSubscribers
if (!success) {
success = self.writeStatus;
}
[self.writeCache release];
self.writeCache = nil;
[self.writerLactch release];
self.writerLactch = nil;
[toWrite release];
// this time write failed, don't continue
if (!success) {
break ;
}
offset += toWriteLen;
}
[self.logger d:@"writeAndNotify: device=%@: success=%d", [self.logger SensitiveNSObject:[device getIdentifier]], success];
return success;
}
#pragma mark - BertyDevice dict helper
- (BertyDevice *)findPeripheral:(CBPeripheral *)peripheral {
BertyDevice *result = nil;
@synchronized (self.bDevices) {
for (BertyDevice *bDevice in self.bDevices) {
if (bDevice.peripheral == peripheral) {
result = bDevice;
break;
}
}
}
return result;
}
- (BertyDevice *)findPeripheralFromName:(NSString *) name {
@synchronized (self.bDevices) {
for (BertyDevice *bDevice in self.bDevices) {
if ([bDevice.name isEqualToString:name]) {
return bDevice;
}
}
}
return nil;
}
- (BertyDevice *)findPeripheralFromPID:(NSString *)peerID {
BertyDevice *result = nil;
@synchronized (self.bDevices) {
for (BertyDevice *bDevice in self.bDevices) {
if ([bDevice.remotePeerID isEqualToString:peerID]) {
result = bDevice;
break;
}
}
}
return result;
}
- (BertyDevice *)findPeripheralFromIdentifier:(NSUUID *)identifier {
BertyDevice *result = nil;
NSString *id = [identifier UUIDString];
@synchronized (self.bDevices) {
for (BertyDevice *bDevice in self.bDevices) {
if ([bDevice.clientSideIdentifier isEqual:id]) {
result = bDevice;
break;
} else if ([bDevice.serverSideIdentifier isEqual:id]) {
result = bDevice;
break;
}
}
}
return result;
}
#pragma mark - CentraManagerDelegate
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[self.logger i:@"didConnectPeripheral called: device=%@", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
BertyDevice *bDevice = [self findPeripheral:peripheral];
if (bDevice == nil) {
[self.logger e:@"didConnectPeripheral error: device=%@ not found", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
[self.cManager cancelPeripheralConnection:peripheral];
return ;
}
[bDevice handleConnect:nil];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
[self.logger i:@"didFailToConnectPeripheral called: device=%@", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
BertyDevice *bDevice = [self findPeripheral:peripheral];
if (bDevice == nil) {
[self.logger e:@"didFailToConnectPeripheral error: device=%@ not found", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
return ;
}
[bDevice handleConnect:error];
}
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSString *id = nil;
if (advertisementData && [advertisementData.allKeys containsObject:CBAdvertisementDataLocalNameKey]) {
// between 2 iOS
id = [advertisementData valueForKeyPath:CBAdvertisementDataLocalNameKey];
} else if (advertisementData && [advertisementData.allKeys containsObject:CBAdvertisementDataServiceDataKey]) {
// between Android / iOS
NSDictionary *data = [advertisementData valueForKey:CBAdvertisementDataServiceDataKey];
if (data) {
CBUUID *uuid = [CBUUID UUIDWithString:@"4240"];
id = [[NSString alloc] initWithData:[data objectForKey:uuid] encoding:NSUTF8StringEncoding];
[id autorelease];
} else {
[self.logger d:@"didDiscoverPeripheral error: device=%@: CBAdvertisementDataServiceDataKey doesn't contains any data", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
return ;
}
} else {
// verbose
// [self.logger e:@"didDiscoverPeripheral error: device=%@ has not advertisement name", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
return ;
}
if ([id length] == 0) {
[self.logger d:@"didDiscoverPeripheral error: device=%@: id is empty", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
return ;
}
// only lower id can be client
if ([self.ID compare:id] != NSOrderedAscending) {
// Verbose
// [self.logger d:@"didDiscoverPeripheral: device=%@: greater ID, cancel client connection", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
return ;
}
BertyDevice *nDevice = [self findPeripheralFromIdentifier:peripheral.identifier];
if (nDevice != nil) { // peripheral already known
if (nDevice.clientSideIdentifier != nil) { // peripheral already discovered
return ;
}
// peripheral already known by CBPeripheralManager (advertising)
// adding info given by CBCentralManager (scanning)
[self.logger d:@"didDiscoverPeripheral: device=%@ id=%@: already known", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]], [self.logger SensitiveNSObject:id]];
nDevice.peripheral = peripheral;
nDevice.clientSideIdentifier = [peripheral.identifier UUIDString];
} else {
nDevice = [self findPeripheralFromName:id];
if (nDevice != nil && nDevice.peripheral != nil) { // device already known with another peripheral object
return ;
}
// TODO: retest if bDevices is still null after @synchronized
@synchronized (self.bDevices) {
nDevice = [[BertyDevice alloc]initWithPeripheral:peripheral logger:self.logger central:self withName:id];
[self.bDevices addObject:nDevice];
[nDevice release];
[self.logger d:@"didDiscoverPeripheral: device=%@ added to BleManager.bDevices", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]]];
}
}
[self.logger d:@"didDiscoverPeripheral: device=%@ id=%@: found. Going to connect.", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]], [self.logger SensitiveNSObject:id]];
[nDevice connectWithOptions:nil];
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
[self.logger i:@"didDisconnectPeripheral called: device=%@ error=%@", [self.logger SensitiveNSObject:[peripheral.identifier UUIDString]], error];
BertyDevice *device = [self findPeripheral:peripheral];
if (device != nil) {
[device closeBertyDevice];
@synchronized (self.bDevices) {
[self.bDevices removeObject:device];
}
}
}
#pragma mark - State Management
- (void)peripheralManagerDidUpdateState:(nonnull CBPeripheralManager *)peripheral {
NSString *stateString = nil;
@synchronized (self.pManager) {
self.pmEnable = FALSE;
}
switch(peripheral.state)
{
case CBManagerStateUnknown: {
stateString = @"CBManagerStateUnknown";
break;
}
case CBManagerStateResetting: {
stateString = @"CBManagerStateResetting";
break;
}
case CBManagerStateUnsupported: {
stateString = @"CBManagerStateUnsupported";
break;
}
case CBManagerStateUnauthorized: {
stateString = @"CBManagerStateUnauthorized";
break;
}
case CBManagerStatePoweredOff: {
stateString = @"CBManagerStatePoweredOff";
break;
}
case CBManagerStatePoweredOn: {
stateString = @"CBManagerStatePoweredOn";
@synchronized (self.pManager) {
self.pmEnable = TRUE;
}
break;
}
default: {
stateString = @"State unknown, update imminent.";
break;
}
}
[self.logger i:@"peripheralManagerDidUpdateState: %@", stateString];
[self.bleOn countDown];
}
- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
NSString *stateString = nil;
@synchronized (self.cManager) {
self.cmEnable = FALSE;
}
switch(central.state)
{
case CBManagerStateResetting: {
break;
}
case CBManagerStateUnsupported: {
break;
}
case CBManagerStateUnauthorized: {
break;
}
case CBManagerStatePoweredOff: {
stateString = @"Bluetooth is currently powered off.";
break;
}
case CBManagerStatePoweredOn: {
stateString = @"Bluetooth is currently powered on and available to use.";
@synchronized (self.cManager) {
self.cmEnable = TRUE;
}
break;
}
default: {
stateString = @"State unknown, update imminent.";
break;
}
}
[self.logger i:@"centralManagerDidUpdateState: %@", stateString];
[self.bleOn countDown];
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
[self.logger d:@"peripheralManager didSubscribeToCharacteristic called: device=%@", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
BertyDevice *device;
if ((device = [self findPeripheralFromIdentifier:central.identifier]) == nil) {
[self.logger e:@"peripheralManager didSubscribeToCharacteristic error: device=%@ not found", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
return ;
}
device.cbCentral = central;
// Server doesn't know if the L2CAP handshake failed on the client side
// so we have to set it manually at this step.
device.l2capServerHandshakeRunning = FALSE;
// complete handshake
device.peer = [self.peerManager registerDevice:device withPeerID:device.remotePeerID isClient:FALSE];
if (device.peer == nil) {
[self.logger e:@"peripheralManager didSubscribeToCharacteristic error: device=%@: registerDevice failed", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
return ;
} else {
[self.logger d:@"peripheralManager didSubscribeToCharacteristic: device=%@: registerDevice successed", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
}
}
// server disconnection callback entry point
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic {
[self.logger d:@"peripheralManager didUnsubscribeFromCharacteristic called: device=%@", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
BertyDevice *device;
if ((device = [self findPeripheralFromIdentifier:central.identifier]) == nil) {
[self.logger e:@"peripheralManager didUnsubscribeFromCharacteristic error: device=%@ not found", [self.logger SensitiveNSObject:[central.identifier UUIDString]]];
return ;
}
[device closeBertyDevice];
@synchronized (self.bDevices) {
[self.bDevices removeObject:device];
}
}
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral {
[self.logger d:@"peripheralManager peripheralManagerIsReadyToUpdateSubscribers called"];
self.writeStatus = FALSE;
@synchronized(self.writeCache) {
if (self.writeCache != nil) {
if (self.logger.showSensitiveData) {
[self.logger d:@"peripheralManagerIsReadyToUpdateSubscribers: device=%@ base64=%@ data=%@", [self.writeCache.device getIdentifier], [self.writeCache.data base64EncodedStringWithOptions:0], [BleManager NSDataToHex:self.writeCache.data]];
}
if (self.writerLactch == nil) {
[self.logger e:@"peripheralManagerIsReadyToUpdateSubscribers error: writer latch is null"];
return ;
}
if (self.writeCache.device.peer == nil) {
[self.logger e:@"peripheralManagerIsReadyToUpdateSubscribers error: peer object not found"];
[self.writerLactch countDown];
return ;
}
if (![self.writeCache.device.peer isServerReady]) {
[self.logger e:@"peripheralManagerIsReadyToUpdateSubscribers error: server not connected"];
[self.writerLactch countDown];
return ;
}
self.writeStatus = [self.pManager updateValue:self.writeCache.data forCharacteristic:self.writerCharacteristic onSubscribedCentrals:@[self.writeCache.device.cbCentral]];
if (self.writeStatus) {
[self.logger d:@"peripheralManagerIsReadyToUpdateSubscribers: device=%@: data sent", [self.logger SensitiveNSObject:[self.writeCache.device getIdentifier]]];
[self.writerLactch countDown];
} else {
[self.logger d:@"peripheralManagerIsReadyToUpdateSubscribers: device=%@: operation queue is full, try later", [self.logger SensitiveNSObject:[self.writeCache.device getIdentifier]]];
return ;
}
}
}
}
#pragma mark - read
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {
[self.logger d:@"didReceiveReadRequests called: device=%@ offset=%lu", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]], request.offset];
if ([request.characteristic.UUID isEqual:self.peerUUID]) {
[self.logger d:@"didReceiveReadRequests: device=%@: use peerID characteristic", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
BertyDevice *device = [self findPeripheralFromIdentifier:request.central.identifier];
if (device == nil || device.remotePeerID == nil) {
[self.logger e:@"didReceiveReadRequests: device=%@: need writeRequest completed before readRequest", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
[peripheral respondToRequest:request withResult:CBATTErrorReadNotPermitted];
return ;
}
// Write PSM to big endian
int psm = NSSwapHostIntToBig(self.psm);
NSMutableData *toSend = [[NSMutableData alloc] initWithBytes:&psm length:sizeof(psm)];
[toSend appendData:[self.localPID dataUsingEncoding:NSUTF8StringEncoding]];
request.value = toSend;
[peripheral respondToRequest:request withResult:CBATTErrorSuccess];
[toSend release];
} else {
[self.logger e:@"didReceiveReadRequests: device=%@: bad characteristic requested", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
[peripheral respondToRequest:request withResult:CBATTErrorRequestNotSupported];
return ;
}
}
#pragma mark - write
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests {
BertyDevice *device;
NSData *data = nil;
for (CBATTRequest *request in requests) {
[self.logger d:@"didReceiveWriteRequests: device=%@ base64=%@", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]], [self.logger SensitiveNSObject:[data base64EncodedStringWithOptions:0]]];
if (self.logger.showSensitiveData) {
[BleManager printLongLog:[BleManager NSDataToHex:data]];
}
CBMutableCharacteristic *characteristic;
@synchronized (self.bDevices) {
// check if we hold a remote device of this type
device = [self findPeripheralFromIdentifier:request.central.identifier];
if (device == nil) {
device = [[BertyDevice alloc]initWithIdentifier:[request.central.identifier UUIDString] logger:self.logger central:self asClient:FALSE];
[self.bDevices addObject:device];
[device release];
[self.logger d:@"didReceiveWriteRequests: device=%@ added to BleManager.bDevices", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
}
}
if ([request.characteristic.UUID isEqual:self.writerUUID]) {
characteristic = self.writerCharacteristic;
}
else if ([request.characteristic.UUID isEqual:self.peerUUID]) {
characteristic = self.peerIDCharacteristic;
} else {
[self.logger e:@"didReceiveWriteRequests error: device=%@: bad characteristic requested", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
[device closeBertyDevice];
[peripheral respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
return ;
}
data = request.value;
BOOL(^handler)(NSData *) = [device.characteristicHandlers objectForKey:[request.characteristic.UUID UUIDString]];
if (!handler(data)) {
[self.logger e:@"didReceiveWriteRequests error: device=%@: handle failed", [self.logger SensitiveNSObject:[request.central.identifier UUIDString]]];
[device closeBertyDevice];
[peripheral respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
}
// Process response back
request.value = [self.localPID dataUsingEncoding:NSUTF8StringEncoding];
}
[peripheral respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorSuccess];
}
#pragma mark - L2cap
- (void)peripheralManager:(CBPeripheralManager *)peripheral didPublishL2CAPChannel:(CBL2CAPPSM)PSM error:(NSError *)error {
if (error != nil) {
[self.logger e:@"peripheralManager didPublishL2CAPChannel error=%@", error];
return ;
}
[self.logger d:@"peripheralManager didPublishL2CAPChannel: PSM=%hu", PSM];
self.psm = PSM;
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM error:(NSError *)error {
[self.logger d:@"peripheralManager didUnpublishL2CAPChannel called"];
self.psm = 0;
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didOpenL2CAPChannel:(CBL2CAPChannel *)channel error:(NSError *)error API_AVAILABLE(ios(11.0)) {
[self.logger d:@"peripheralManager didOpenL2CAPChannel called: device=%@", [self.logger SensitiveNSObject:[channel.peer.identifier UUIDString]]];
if (error != nil) {
[self.logger e:@"peripheralManager didOpenL2CAPChannel error=%@", error];
return ;
}
BertyDevice *device;
if ((device = [self findPeripheralFromIdentifier:channel.peer.identifier]) == nil) {
[self.logger e:@"peripheralManager didOpenL2CAPChannel error: device=%@ not found", [self.logger SensitiveNSObject:[channel.peer.identifier UUIDString]]];
return ;
}
device.l2capChannel = channel;
device.l2capThread = [[NSThread alloc] initWithBlock:^{
[self.logger d:@"peripheralManager didOpenL2CAPChannel: device=%@: in thread", [self.logger SensitiveNSObject:[device getIdentifier]]];
channel.inputStream.delegate = device;
[channel.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[channel.inputStream open];
channel.outputStream.delegate = device;
[channel.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[channel.outputStream open];
@autoreleasepool {
do {
[[NSRunLoop currentRunLoop] run];
} while (device.peer != nil && [device.peer isConnected]);
}
}];
[device.l2capThread start];
device.l2capServerHandshakeRunning = TRUE;
}
@end
================================================
FILE: pkg/ble-driver/BleQueue.h
================================================
//
// BleQueue.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/05/2021.
//
#import
#import "Logger.h"
NS_ASSUME_NONNULL_BEGIN
#define MAX_TRIES 3
@interface BleQueue : NSObject
@property (nonatomic, strong, nonnull) dispatch_queue_t queue;
@property (nonatomic, strong, nonnull) Logger *logger;
@property (nonatomic, strong, nonnull) NSMutableArray *tasks;
@property (readwrite) BOOL taskQueueBusy;
@property (readwrite) BOOL isRetrying;
@property (readwrite) int nbTries;
@property (readwrite) int index;
- (instancetype __nullable) init:(dispatch_queue_t)queue logger:(Logger *__nonnull)logger;
- (void) add:(void (^__nonnull)(void))block withCallback:(void (^__nullable)(NSError *))callback withDelay:(long)delay;
- (void) completedTask:(NSError *__nullable)error;
- (void) nextTask;
- (void) retryTask;
- (void) clear;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/BleQueue.m
================================================
// +build darwin,!noproximitytransport
//
// BleQueue.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/05/2021.
//
#import "BleQueue.h"
#import "TaskDelay.h"
@implementation BleQueue
- (instancetype __nullable) init:(dispatch_queue_t)queue logger:(Logger *__nonnull)logger {
self = [super init];
if (self) {
_tasks = [[NSMutableArray alloc] init];
_queue = [queue retain];
_logger = [logger retain];
}
return self;
}
- (void)dealloc {
[_tasks removeAllObjects];
[_tasks release];
[_queue release];
[_logger release];
[super dealloc];
}
- (void) add:(void (^__nonnull)(void))block withCallback:(void (^__nullable)(NSError *))callback withDelay:(long)delay {
@synchronized (self.tasks) {
TaskDelay *task = [[TaskDelay alloc] initWithBlock:block withCallback:callback withDelay:delay withIndex:(self.index++)];
[self.tasks addObject:task]; // add to the end of the array
[self.logger d:@"BleQueue: added task at index=%d count=%ld", task.index, [self.tasks count]];
[self nextTask];
[task release];
}
}
- (void) completedTask:(NSError *__nullable)error {
@synchronized (self.tasks) {
TaskDelay *currentTask;
if ([self.tasks count] == 0) {
[self.logger e:@"BleQueue: completedTask error: no task running"];
return ;
}
currentTask = [self.tasks objectAtIndex:0];
[self.logger d:@"BleQueue: completedTask at index=%d", currentTask.index];
if (currentTask.callback != nil) {
dispatch_async(self.queue, ^{
currentTask.callback(error);
});
}
self.isRetrying = FALSE;
self.taskQueueBusy = FALSE;
[self.tasks removeObjectAtIndex:0];
[self nextTask];
}
}
- (void) nextTask {
@synchronized (self.tasks) {
TaskDelay *nextTask;
if (self.taskQueueBusy) {
[self.logger d:@"BleQueue: nextTask: another task is running"];
return ;
}
if ([self.tasks count] == 0 ) {
[self.logger d:@"BleQueue: nextTask error: no task queued: count=%ld", [self.tasks count]];
return ;
}
nextTask = [self.tasks objectAtIndex:0];
[self.logger d:@"BleQueue: nextTask at index=%d with delay=%ld", nextTask.index, nextTask.delay];
self.taskQueueBusy = TRUE;
if (!self.isRetrying) {
self.nbTries = 0;
}
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(nextTask.delay * NSEC_PER_SEC));
dispatch_after(popTime, self.queue, nextTask.block);
}
}
- (void) retryTask {
@synchronized (self.tasks) {
TaskDelay *currentTask;
self.taskQueueBusy = FALSE;
if ([self.tasks count] == 0) {
[self.logger e:@"BleQueue: retryTask error: no task running"];
} else {
currentTask = [self.tasks objectAtIndex:0];
if (self.nbTries >= MAX_TRIES) {
[self.logger d:@"BleQueue: max number of tries reached, not retrying operation anymore for task index=%d", currentTask.index];
[self.tasks removeObjectAtIndex:0];
} else {
[self.logger d:@"BleQueue: retrying task at index=%d", currentTask.index];
self.isRetrying = TRUE;
}
}
[self nextTask];
}
}
- (void) clear {
@synchronized (self.tasks) {
[self.tasks removeAllObjects];
self.taskQueueBusy = FALSE;
}
}
@end
================================================
FILE: pkg/ble-driver/CircularQueue.h
================================================
//
// CircularQueue.h
//
// Created on 9/21/13.
//
// https://gist.github.com/werediver/5345f91c897b8173e40e
//
#import
# define DEFAULT_CAPACITY 8
@interface CircularQueue : NSObject
@property (nonatomic, strong, nonnull) NSMutableArray *data;
@property (nonatomic, assign, readwrite) NSInteger capacity;
@property (nonatomic, assign, readwrite) NSInteger writeSequence;
@property (nonatomic, assign, readwrite) NSInteger readSequence;
- (instancetype __nonnull)initWithCapacity:(NSUInteger)capacity;
- (void)offer:(id __nonnull)obj; // Enqueue
- (id __nonnull)poll; // Get object and unqueue
- (id __nonnull)element; // Get object
- (void)clean;
@end
================================================
FILE: pkg/ble-driver/CircularQueue.m
================================================
// +build darwin,!noproximitytransport
#import "CircularQueue.h"
@implementation CircularQueue
- (instancetype __nonnull)initWithCapacity:(NSUInteger)capacity {
self = [super init];
if (self) {
_capacity = capacity < 1 ? DEFAULT_CAPACITY : capacity;
_data = [[NSMutableArray alloc] initWithCapacity:_capacity];
_writeSequence = -1;
_readSequence = 0;
for (NSUInteger i = 0; i < _capacity; ++i) {
[_data addObject:[NSNull null]];
}
}
return self;
}
- (void)dealloc {
[_data release];
[super dealloc];
}
- (void)offer:(id)obj {
if ([self isNotFull]) {
NSInteger nextWrite = (self.writeSequence + 1) % self.capacity;
[self.data replaceObjectAtIndex:nextWrite withObject:obj];
self.writeSequence++;
} else {
@throw [[[NSException alloc] initWithName:NSRangeException reason:nil userInfo:nil] autorelease];
}
}
- (id)poll {
if ([self isNotEmpty]) {
NSInteger index = self.readSequence % self.capacity;
id value = [[self.data objectAtIndex:index] retain];
[self.data replaceObjectAtIndex:index withObject:[NSNull null]];
self.readSequence++;
return [value autorelease];
}
return [NSNull null];
}
- (id)element {
if ([self isNotEmpty]) {
NSInteger index = self.readSequence % self.capacity;
return [self.data objectAtIndex:index];
}
return [NSNull null];
}
- (void)clean {
for (NSUInteger i = 0; i < _capacity; ++i) {
[self.data replaceObjectAtIndex:i withObject:[NSNull null]];
}
self.readSequence = 0;
self.writeSequence = -1;
}
- (NSInteger)size {
return (self.writeSequence - self.readSequence) + 1;
}
- (BOOL)isEmpty {
return self.writeSequence < self.readSequence;
}
- (BOOL)isFull {
return [self size] >= self.capacity;
}
- (BOOL)isNotEmpty {
return ![self isEmpty];
}
- (BOOL)isNotFull {
return ![self isFull];
}
@end
================================================
FILE: pkg/ble-driver/ConnectedPeer.h
================================================
//
// ConnectedPeer.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 29/04/2021.
//
#import
NS_ASSUME_NONNULL_BEGIN
@class BertyDevice;
@interface ConnectedPeer : NSObject
@property (nonatomic, assign, nullable) BertyDevice *client;
@property (nonatomic, assign, nullable) BertyDevice *server;
@property (readwrite, getter=isConnected) BOOL connected;
- (BOOL)isClientReady;
- (BOOL)isServerReady;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/ConnectedPeer.m
================================================
// +build darwin,!noproximitytransport
//
// ConnectedPeer.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 29/04/2021.
//
#import "ConnectedPeer.h"
@implementation ConnectedPeer
- (BOOL)isClientReady {
return self.client != nil;
}
- (BOOL)isServerReady {
return self.server != nil;
}
@end
================================================
FILE: pkg/ble-driver/CountDownLatch_darwin.h
================================================
//
// CountDownLatch.h
// ble
//
// Created by sacha on 22/11/2018.
// Copyright © 2018 berty. All rights reserved.
//
#import
#ifndef CountDownLatch_h
#define CountDownLatch_h
@interface CountDownLatch : NSObject
@property (nonatomic, assign, readwrite) NSInteger count;
@property (atomic, strong, readwrite) dispatch_semaphore_t semaphore;
@property (nonatomic, strong) dispatch_queue_t dispatch_queue;
@property (readwrite) BOOL timeout;
- (instancetype)initCount:(NSInteger)count;
- (void)incrementCount;
- (void)countDown;
- (void)await;
- (void)await:(NSUInteger)timeout withCancelBlock:(void (^)(void))callback;
@end
#endif
================================================
FILE: pkg/ble-driver/CountDownLatch_darwin.m
================================================
// +build darwin,!noproximitytransport
//
// CountDownLatch.m
// ble
//
// Created by sacha on 22/11/2018.
// Copyright © 2018 berty. All rights reserved.
//
#import "CountDownLatch_darwin.h"
@implementation CountDownLatch
- (instancetype)initCount:(NSInteger)count {
if (count < 0) {
return nil;
}
self = [super self];
if (self) {
_count = count;
_semaphore = dispatch_semaphore_create(0);
_dispatch_queue = dispatch_queue_create("CountDownLatchQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)dealloc {
_semaphore = nil;
dispatch_release(_dispatch_queue);
_dispatch_queue = nil;
[super dealloc];
}
- (void)incrementCount {
dispatch_async(self.dispatch_queue, ^{
self.count++;
});
}
- (void)countDown {
dispatch_async(self.dispatch_queue, ^{
self.count--;
if (self.count == 0) {
dispatch_semaphore_signal(self.semaphore);
}
});
}
- (void)await {
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
}
- (void)await:(NSUInteger)timeout withCancelBlock:(void (^)(void))callback {
self.timeout = TRUE;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
dispatch_after(popTime, self.dispatch_queue, ^(void){
if (self.timeout) {
callback();
dispatch_semaphore_signal(self.semaphore);
}
});
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
self.timeout = FALSE;
}
@end
================================================
FILE: pkg/ble-driver/Logger.h
================================================
//
// Logger.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 08/12/2021.
//
#import
#import
NS_ASSUME_NONNULL_BEGIN
#define SENSITIVE_MASK @"####"
// Log levels
typedef NS_ENUM(uint8_t, level) {
Debug,
Info,
Warn,
Error,
};
@interface BLE_Logger : NSObject
@property (nonatomic, strong, nonnull) os_log_t logger;
@property (readwrite) BOOL showSensitiveData;
@property (readwrite) BOOL useExternalLogger;
- (instancetype __nonnull)initLocalLoggerWithSubSystem:(const char *)subSystem andCategorie:(const char*)categorie showSensitiveData:(BOOL)showSensitiveData;
- (instancetype __nonnull)initWithExternalLoggerAndShowSensitiveData:(BOOL)showSensitiveData;
- (void)log:(enum level)level withFormat:(NSString *__nonnull)format withArgs:(va_list)args;
- (void)d:(NSString *__nonnull)format, ...;
- (void)i:(NSString *__nonnull)format, ...;
- (void)e:(NSString *__nonnull)format, ...;
- (BOOL)showSensitiveData;
- (BOOL)useExternalLogger;
- (NSString *__nonnull)SensitiveNSObject:(id __nonnull)data;
- (NSString *__nonnull)SensitiveString:(const char *)data;
@end
@compatibility_alias Logger BLE_Logger;
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/Logger.m
================================================
// +build darwin,!noproximitytransport
//
// Logger.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 08/12/2021.
//
#import
#import "Logger.h"
#import "BleInterface_darwin.h"
@implementation Logger
- (instancetype __nonnull)initLocalLoggerWithSubSystem:(const char *)subSystem andCategorie:(const char*)categorie showSensitiveData:(BOOL)showSensitiveData {
self = [super init];
if (self) {
_logger = os_log_create(subSystem, categorie);
_useExternalLogger = FALSE;
_showSensitiveData = showSensitiveData;
}
return self;
}
- (instancetype __nonnull)initWithExternalLoggerAndShowSensitiveData:(BOOL)showSensitiveData {
self = [super init];
if (self) {
_logger = nil;
_useExternalLogger = TRUE;
_showSensitiveData = showSensitiveData;
}
return self;
}
- (void)log:(enum level)level withFormat:(NSString *__nonnull)format withArgs:(va_list)args {
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
if (self.useExternalLogger) {
BLEBridgeLog(level, message);
} else {
if (self.logger == nil) {
NSLog(@"log error: logger is not set");
} else {
uint8_t osLevel;
switch (level) {
case Debug:
osLevel = OS_LOG_TYPE_DEBUG;
break ;
case Info:
osLevel = OS_LOG_TYPE_INFO;
break ;
case Error:
osLevel = OS_LOG_TYPE_ERROR;
break ;
default:
osLevel = OS_LOG_TYPE_DEFAULT;
break ;
}
os_log_with_type(self.logger, osLevel, "%@", message);
}
}
[message release];
}
- (void)d:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Debug withFormat:format withArgs:args];
va_end(args);
}
- (void)i:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Info withFormat:format withArgs:args];
va_end(args);
}
- (void)e:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Error withFormat:format withArgs:args];
va_end(args);
}
- (NSString *__nonnull)SensitiveNSObject:(id __nonnull)data {
if (self.showSensitiveData) {
return [NSString stringWithFormat:@"%@", data];
} else {
return SENSITIVE_MASK;
}
}
- (NSString *__nonnull)SensitiveString:(const char *)data {
if (data == nil) {
return @"";
}
if (self.showSensitiveData) {
return [NSString stringWithFormat:@"%s", data];
} else {
return SENSITIVE_MASK;
}
}
@end
================================================
FILE: pkg/ble-driver/PeerManager.h
================================================
//
// PeerManager.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 29/04/2021.
//
#import
#import "Logger.h"
#import "ConnectedPeer.h"
NS_ASSUME_NONNULL_BEGIN
@class BertyDevice;
@interface PeerManager : NSObject
@property (nonatomic, strong, nonnull) NSMutableDictionary *connectedPeers;
@property (nonatomic, strong, nonnull) Logger *logger;
- (instancetype __nonnull)initWithLogger:(Logger *__nonnull)logger;
- (ConnectedPeer *__nonnull)getPeer:(NSString *__nonnull) peerID;
- (ConnectedPeer *__nullable)registerDevice:(BertyDevice *__nonnull)device withPeerID:(NSString *__nonnull)peerID isClient:(BOOL)isClient;
- (void)unregisterDevice:(BertyDevice *)device;
- (void)removePeer:(NSString *__nonnull) peerID;
- (void)removeAllPeers;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/PeerManager.m
================================================
// +build darwin,!noproximitytransport
//
// PeerManager.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 29/04/2021.
//
#import "PeerManager.h"
#import "BleInterface_darwin.h"
@implementation PeerManager
- (instancetype __nonnull)initWithLogger:(Logger *__nonnull)logger {
self = [super init];
if (self) {
_logger = [logger retain];
_connectedPeers = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc {
[_connectedPeers release];
[_logger release];
[super dealloc];
}
- (ConnectedPeer *__nonnull)getPeer:(NSString *__nonnull) peerID {
[self.logger d:@"getPeer called: peerID=%@", [self.logger SensitiveNSObject:peerID]];
ConnectedPeer *peer;
@synchronized (_connectedPeers) {
if ((peer = [self.connectedPeers objectForKey:peerID]) != nil) {
[self.logger d:@"getPeer: peerID=%@ alread created", [self.logger SensitiveNSObject:peerID]];
return peer;
}
[self.logger d:@"getPeer: peerID=%@ created", [self.logger SensitiveNSObject:peerID]];
peer = [[ConnectedPeer alloc] init];
[self.connectedPeers setObject:peer forKey:peerID];
[peer release];
return peer;
}
}
- (ConnectedPeer *__nullable)registerDevice:(BertyDevice *__nonnull)device withPeerID:(NSString *__nonnull)peerID isClient:(BOOL)isClient {
[self.logger d:@"registerDevice called: identifier=%@ peer=%@ isClient=%d", [self.logger SensitiveNSObject:[device getIdentifier]], [self.logger SensitiveNSObject:peerID], isClient];
ConnectedPeer *peer;
@synchronized (_connectedPeers) {
peer = [self getPeer:peerID];
if (isClient) {
peer.client = device;
} else {
peer.server = device;
}
device.peer = peer;
peer.connected = TRUE;
if (!BLEBridgeHandleFoundPeer(peerID)) {
[self.logger e:@"registerDevice error: device=%@ peer=%@: HandleFoundPeer failed", [self.logger SensitiveNSObject:[device getIdentifier]], [self.logger SensitiveNSObject:peerID]];
return NULL;
}
[device flushCache];
}
return peer;
}
- (void)unregisterDevice:(BertyDevice *)device {
[self.logger d:@"unregisterDevice called: device=%@ peerID=%@", [self.logger SensitiveNSObject:[device getIdentifier]], [self.logger SensitiveNSObject:device.remotePeerID]];
ConnectedPeer *peer;
@synchronized (_connectedPeers) {
if ((peer = [self.connectedPeers objectForKey:device.remotePeerID]) == nil) {
[self.logger e:@"unregisterDevice called: device=%@ peerID=%@: peerID not found", [self.logger SensitiveNSObject:[device getIdentifier]], [self.logger SensitiveNSObject:device.remotePeerID]];
return ;
}
if ([peer isConnected]) {
[self.logger d:@"unregisterDevice called: device=%{public}@ peerID=%{public}@: calling HandleLostPeer", [self.logger SensitiveNSObject:[device getIdentifier]], [self.logger SensitiveNSObject:device.remotePeerID]];
BLEBridgeHandleLostPeer(device.remotePeerID);
peer.connected = FALSE;
}
[self removePeer:device.remotePeerID];
}
}
- (void)removePeer:(NSString *__nonnull) peerID {
[self.logger d:@"removePeer called: peerID=%{public}@", [self.logger SensitiveNSObject:peerID]];
@synchronized (_connectedPeers) {
[self.connectedPeers removeObjectForKey:peerID];
}
}
- (void)removeAllPeers {
[self.logger d:@"removeAllPeers called"];
@synchronized (_connectedPeers) {
[self.connectedPeers removeAllObjects];
}
}
@end
================================================
FILE: pkg/ble-driver/TaskDelay.h
================================================
//
// TaskDelay.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/05/2021.
//
#import
NS_ASSUME_NONNULL_BEGIN
@interface TaskDelay : NSObject
@property (nonatomic, copy) void (^block)(void);
@property (nonatomic, copy) void (^callback)(NSError *);
@property (nonatomic, assign) long delay;
@property (nonatomic, assign) int index;
- (instancetype __nullable) initWithBlock:(void (^ __nonnull)(void))block withCallback:(void (^__nullable)(NSError *))callback withDelay:(long)delay withIndex:(int)index;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/TaskDelay.m
================================================
// +build darwin,!noproximitytransport
//
// TaskDelay.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/05/2021.
//
#import "TaskDelay.h"
@implementation TaskDelay
- (instancetype __nullable) initWithBlock:(void (^ __nonnull)(void))block withCallback:(void (^__nullable)(NSError *))callback withDelay:(long)delay withIndex:(int)index {
self = [super init];
if (self) {
_block = [block copy];
_callback = [callback copy];
_delay = delay;
_index = index;
}
return self;
}
- (void)dealloc {
[_block release];
[_callback release];
[super dealloc];
}
@end
================================================
FILE: pkg/ble-driver/WriteDataCache.h
================================================
//
// WriteDataCache.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/08/2021.
//
#import
NS_ASSUME_NONNULL_BEGIN
@class BertyDevice;
@interface WriteDataCache : NSObject
@property (nonatomic, strong, nonnull) BertyDevice *device;
@property (nonatomic, strong, nonnull) NSData *data;
- (instancetype __nonnull) initWithDevice:(BertyDevice *__nonnull)device withData:(NSData *__nonnull)data;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/ble-driver/WriteDataCache.m
================================================
// +build darwin,!noproximitytransport
//
// WriteDataCache.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 03/08/2021.
//
#import "WriteDataCache.h"
#import "BertyDevice_darwin.h"
@implementation WriteDataCache
- (instancetype __nonnull) initWithDevice:(BertyDevice *__nonnull)device withData:(NSData *__nonnull)data {
self = [super init];
if (self) {
_device = [device retain];
_data = [data retain];
}
return self;
}
- (void)dealloc {
[_device release];
[_data release];
[super dealloc];
}
@end
================================================
FILE: pkg/ble-driver/bridge_android.go
================================================
//go:build android && !noproximitytransport
package ble
import (
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
// Supported is used by main package as default value for enable the BLE driver.
// While UI actually enable or not the Java BLE driver.
// TODO: remove this when UI will be able to handle this for the first App launching.
const Supported = true
// Noop implementation for Android
// Real driver is given from Java directly here: berty/js/android/app/src/main/java/tech/berty/gobridge/bledriver
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
logger = logger.Named("BLE")
logger.Info("NewDriver(): Java driver not found")
return proximity.NewNoopProximityDriver(ProtocolCode, ProtocolName, DefaultAddr)
}
================================================
FILE: pkg/ble-driver/bridge_darwin.go
================================================
//go:build darwin && cgo && !noproximitytransport
// +build darwin,cgo,!noproximitytransport
package ble
/*
#cgo CFLAGS: -x objective-c -fno-objc-arc
#cgo darwin LDFLAGS: -framework Foundation -framework CoreBluetooth
#include
#import "BleInterface_darwin.h"
#import "Logger.h"
*/
import "C"
import (
"fmt"
"os"
"unsafe"
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
const Supported = true
var gLogger *zap.Logger
type Driver struct {
protocolCode int
protocolName string
defaultAddr string
}
// Driver is a proximity.ProximityDriver
var _ proximity.ProximityDriver = (*Driver)(nil)
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
if logger == nil {
logger = zap.NewNop()
} else {
logger = logger.Named("BLE")
logger.Debug("NewDriver()")
C.BLEUseExternalLogger()
}
gLogger = logger
return &Driver{
protocolCode: ProtocolCode,
protocolName: ProtocolName,
defaultAddr: DefaultAddr,
}
}
//export BLEHandleFoundPeer
func BLEHandleFoundPeer(remotePID *C.char) int { // nolint:revive // Need to prefix func name to avoid duplicate symbols between proximity drivers
goPID := C.GoString(remotePID)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return 0
}
if t.HandleFoundPeer(goPID) {
return 1
}
return 0
}
//export BLEHandleLostPeer
func BLEHandleLostPeer(remotePID *C.char) { // nolint:revive // Need to prefix func name to avoid duplicate symbols between proximity drivers
goPID := C.GoString(remotePID)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return
}
t.HandleLostPeer(goPID)
}
//export BLEReceiveFromPeer
func BLEReceiveFromPeer(remotePID *C.char, payload unsafe.Pointer, length C.int) { // nolint:revive // Need to prefix func name to avoid duplicate symbols between proximity drivers
goPID := C.GoString(remotePID)
goPayload := C.GoBytes(payload, length)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return
}
t.ReceiveFromPeer(goPID, goPayload)
}
//export BLELog
func BLELog(level C.enum_level, message *C.char) { //nolint:revive
if gLogger == nil {
fmt.Fprintf(os.Stderr, "logger not found\n")
return
}
goMessage := C.GoString(message)
switch level {
case C.Debug:
gLogger.Debug(goMessage)
case C.Info:
gLogger.Info(goMessage)
case C.Warn:
gLogger.Warn(goMessage)
case C.Error:
gLogger.Error(goMessage)
}
}
func (d *Driver) Start(localPID string) {
cPID := C.CString(localPID)
defer C.free(unsafe.Pointer(cPID))
C.BLEStart(cPID)
}
func (d *Driver) Stop() {
C.BLEStop()
}
func (d *Driver) DialPeer(remotePID string) bool {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
return C.BLEDialPeer(cPID) == 1
}
func (d *Driver) SendToPeer(remotePID string, payload []byte) bool {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
cPayload := C.CBytes(payload)
defer C.free(cPayload)
return C.BLESendToPeer(cPID, cPayload, C.int(len(payload))) == 1
}
func (d *Driver) CloseConnWithPeer(remotePID string) {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
C.BLECloseConnWithPeer(cPID)
}
func (d *Driver) ProtocolCode() int {
return d.protocolCode
}
func (d *Driver) ProtocolName() string {
return d.protocolName
}
func (d *Driver) DefaultAddr() string {
return d.defaultAddr
}
================================================
FILE: pkg/ble-driver/bridge_unsupported.go
================================================
//go:build (!darwin && !android) || noproximitytransport
package ble
import (
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
const Supported = false
// Noop implementation for platform that are not Darwin
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
logger = logger.Named("BLE")
logger.Info("NewDriver(): incompatible system")
return proximity.NewNoopProximityDriver(ProtocolCode, ProtocolName, DefaultAddr)
}
================================================
FILE: pkg/ble-driver/const.go
================================================
package ble
const (
DefaultAddr = "/ble/Qmeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
ProtocolCode = 0x0042
ProtocolName = "ble"
)
================================================
FILE: pkg/ble-driver/example_test.go
================================================
package ble_test
================================================
FILE: pkg/ble-driver/init.go
================================================
package ble
import (
ma "github.com/multiformats/go-multiaddr"
)
func init() { // nolint:gochecknoinits
err := ma.AddProtocol(newProtocol())
if err != nil {
panic(err)
}
}
================================================
FILE: pkg/ble-driver/multiaddr.go
================================================
package ble
import (
peer "github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
func newProtocol() ma.Protocol {
transcoderMC := ma.NewTranscoderFromFunctions(mcStB, mcBtS, mcVal)
return ma.Protocol{
Name: ProtocolName,
Code: ProtocolCode,
VCode: ma.CodeToVarint(ProtocolCode),
Size: -1,
Path: false,
Transcoder: transcoderMC,
}
}
func mcStB(s string) ([]byte, error) {
_, err := peer.Decode(s)
if err != nil {
return nil, err
}
return []byte(s), nil
}
func mcBtS(b []byte) (string, error) {
_, err := peer.Decode(string(b))
if err != nil {
return "", err
}
return string(b), nil
}
func mcVal(b []byte) error {
_, err := peer.Decode(string(b))
return err
}
================================================
FILE: pkg/cryptoutil/cryptoutil.go
================================================
package cryptoutil
import (
"crypto/aes"
"crypto/cipher"
crand "crypto/rand"
"crypto/sha256"
"crypto/sha512"
"fmt"
"filippo.io/edwards25519"
"github.com/libp2p/go-libp2p/core/crypto"
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/scrypt"
"berty.tech/weshnet/v2/pkg/errcode"
)
const (
KeySize = 32 // Key size required by box
NonceSize = 24 // Nonce size required by box
ScryptIterations = 1 << 15
ScryptR = 8
ScryptP = 1
ScryptKeyLen = 32
)
func ConcatAndHashSha256(slices ...[]byte) *[sha256.Size]byte {
var concat []byte
for _, slice := range slices {
concat = append(concat, slice...)
}
checksum := sha256.Sum256(concat)
return &checksum
}
func GenerateNonce() (*[NonceSize]byte, error) {
var nonce [NonceSize]byte
size, err := crand.Read(nonce[:])
if size != NonceSize {
err = fmt.Errorf("size read: %d (required %d)", size, NonceSize)
}
if err != nil {
return nil, errcode.ErrCode_ErrCryptoRandomGeneration.Wrap(err)
}
return &nonce, nil
}
func GenerateNonceSize(size int) ([]byte, error) {
nonce := make([]byte, size)
readSize, err := crand.Read(nonce)
if readSize != size {
err = fmt.Errorf("size read: %d (required %d)", readSize, size)
}
if err != nil {
return nil, errcode.ErrCode_ErrCryptoRandomGeneration.Wrap(err)
}
return nonce, nil
}
func NonceSliceToArray(nonceSlice []byte) (*[NonceSize]byte, error) {
var nonceArray [NonceSize]byte
if l := len(nonceSlice); l != NonceSize {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid nonce size, expected %d bytes, got %d", NonceSize, l))
}
copy(nonceArray[:], nonceSlice)
return &nonceArray, nil
}
func KeySliceToArray(keySlice []byte) (*[KeySize]byte, error) {
var keyArray [KeySize]byte
if l := len(keySlice); l != KeySize {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unable to convert slice to array, unexpected slice size: %d (expected %d)", l, KeySize))
}
copy(keyArray[:], keySlice)
return &keyArray, nil
}
func SeedFromEd25519PrivateKey(key crypto.PrivKey) ([]byte, error) {
// Similar to (*ed25519).Seed()
if key.Type() != pb.KeyType_Ed25519 {
return nil, errcode.ErrCode_ErrInvalidInput
}
r, err := key.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
if len(r) != ed25519.PrivateKeySize {
return nil, errcode.ErrCode_ErrInvalidInput
}
return r[:ed25519.PrivateKeySize-ed25519.PublicKeySize], nil
}
// EdwardsToMontgomery converts ed25519 priv/pub keys to X25519 keys.
func EdwardsToMontgomery(privKey crypto.PrivKey, pubKey crypto.PubKey) (*[32]byte, *[32]byte, error) {
mongPriv, err := EdwardsToMontgomeryPriv(privKey)
if err != nil {
return nil, nil, err
}
mongPub, err := EdwardsToMontgomeryPub(pubKey)
if err != nil {
return nil, nil, err
}
return mongPriv, mongPub, nil
}
// EdwardsToMontgomeryPub converts ed25519 pub key to X25519 pub key.
func EdwardsToMontgomeryPub(pubKey crypto.PubKey) (*[KeySize]byte, error) {
var mongPub [KeySize]byte
if pubKey.Type() != pb.KeyType_Ed25519 {
return nil, errcode.ErrCode_ErrInvalidInput
}
rawPublicKey, err := pubKey.Raw()
if err != nil {
return nil, fmt.Errorf("unable to get raw public key: %w", err)
} else if len(rawPublicKey) != ed25519.PublicKeySize {
return nil, fmt.Errorf("invalid ed25519 public key size: %w", err)
}
err = PublicKeyToCurve25519(&mongPub, (ed25519.PublicKey)(rawPublicKey))
if err != nil {
return nil, fmt.Errorf("unable to get publickey to curve 25519: %w", err)
}
return &mongPub, nil
}
// EdwardsToMontgomeryPriv converts ed25519 priv key to X25519 priv key.
func EdwardsToMontgomeryPriv(privKey crypto.PrivKey) (*[KeySize]byte, error) {
var mongPriv [KeySize]byte
if privKey.Type() != pb.KeyType_Ed25519 {
return nil, errcode.ErrCode_ErrInvalidInput
}
rawPrivateKey, err := privKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
} else if len(rawPrivateKey) != ed25519.PrivateKeySize {
return nil, errcode.ErrCode_ErrInvalidInput
}
PrivateKeyToCurve25519(&mongPriv, rawPrivateKey)
return &mongPriv, nil
}
// AESGCMEncrypt use AES+GCM to encrypt plaintext data.
//
// The generated output will be longer than the original plaintext input.
func AESGCMEncrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
}
nonce, err := GenerateNonceSize(gcm.NonceSize())
if err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext, nil
}
// AESGCMDecrypt uses AES+GCM to decrypt plaintext data.
func AESGCMDecrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
}
nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
// AESCTRStream returns a CTR stream that can be used to produce ciphertext without padding.
func AESCTRStream(key, iv []byte) (cipher.Stream, error) {
if key == nil || iv == nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
stream := cipher.NewCTR(blockCipher, iv)
return stream, nil
}
// DeriveKey takes a passphrase of any length and returns a key of fixed size.
//
// If no salt is provided, a new one will be created and returned.
func DeriveKey(passphrase, salt []byte) ([]byte, []byte, error) {
if salt == nil {
var err error
salt, err = GenerateNonceSize(ScryptKeyLen)
if err != nil {
return nil, nil, err
}
}
key, err := scrypt.Key(passphrase, salt, ScryptIterations, ScryptR, ScryptP, ScryptKeyLen)
if err != nil {
return nil, nil, err
}
return key, salt, nil
}
// PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519
// public key that would be generated from the same private key.
func PublicKeyToCurve25519(ret *[32]byte, publicKey ed25519.PublicKey) error {
point, err := edwards25519.NewGeneratorPoint().SetBytes(publicKey)
if err != nil {
return fmt.Errorf("unable to generate point from publicKey: %w", err)
}
copy(ret[:], point.BytesMontgomery())
return nil
}
// from: https://github.com/agl/ed25519/blob/5312a61534124124185d41f09206b9fef1d88403/extra25519/extra25519.go#LL16C11-L16C11
// PrivateKeyToCurve25519 converts an ed25519 private key into a corresponding
// curve25519 private key such that the resulting curve25519 public key will
// equal the result from PublicKeyToCurve25519.
func PrivateKeyToCurve25519(ret *[32]byte, privateKey ed25519.PrivateKey) {
h := sha512.New()
h.Write(privateKey.Seed())
copy(ret[:], h.Sum(nil))
ret[0] &= 248
ret[31] &= 127
ret[31] |= 64
}
================================================
FILE: pkg/cryptoutil/cryptoutil_test.go
================================================
package cryptoutil
import (
"bytes"
"crypto/aes"
"crypto/rand"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/ed25519"
"berty.tech/weshnet/v2/pkg/errcode"
)
// from: https://github.com/agl/ed25519/blob/5312a61534124124185d41f09206b9fef1d88403/extra25519/extra25519_test.go#L16-L30
func TestCurve25519Conversion(t *testing.T) {
public, private, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
var curve25519Public, curve25519Public2, curve25519Private [32]byte
PrivateKeyToCurve25519(&curve25519Private, private)
curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private)
err = PublicKeyToCurve25519(&curve25519Public2, public)
require.NoError(t, err)
require.Truef(t, bytes.Equal(curve25519Public[:], curve25519Public2[:]),
"Values didn't match: curve25519 produced %x, conversion produced %x", curve25519Public[:], curve25519Public2[:])
}
func TestSeedFromEd25519PrivateKey(t *testing.T) {
priv, _, _ := crypto.GenerateECDSAKeyPair(rand.Reader)
_, err := SeedFromEd25519PrivateKey(priv)
if err != errcode.ErrCode_ErrInvalidInput {
t.Error("Should fail with ErrInvalidInput")
}
priv, _, _ = crypto.GenerateEd25519Key(rand.Reader)
_, err = SeedFromEd25519PrivateKey(priv)
if err != nil {
t.Error(err)
}
}
func TestEdwardsToMontgomeryPub(t *testing.T) {
_, pub, _ := crypto.GenerateEd25519Key(rand.Reader)
_, err := EdwardsToMontgomeryPub(pub)
if err != nil {
t.Error(err)
}
_, pub, _ = crypto.GenerateECDSAKeyPair(rand.Reader)
_, err = EdwardsToMontgomeryPub(pub)
if err != errcode.ErrCode_ErrInvalidInput {
t.Error("Should fail with ErrInvalidInput")
}
}
func TestEdwardsToMontgomeryPriv(t *testing.T) {
priv, _, _ := crypto.GenerateEd25519Key(rand.Reader)
_, err := EdwardsToMontgomeryPriv(priv)
if err != nil {
t.Error(err)
}
priv, _, _ = crypto.GenerateECDSAKeyPair(rand.Reader)
_, err = EdwardsToMontgomeryPriv(priv)
if err != errcode.ErrCode_ErrInvalidInput {
t.Error("Should fail with ErrInvalidInput")
}
}
func TestDeriveKey(t *testing.T) {
cases := []struct {
passphrase []byte
salt []byte
}{
{nil, nil},
{[]byte{0x42}, []byte{0x42}},
{nil, []byte{0x42}},
{[]byte{0x42}, nil},
{[]byte("hello world"), []byte("hello world")},
{[]byte("morethan32bytes.................."), []byte("hello world")},
{[]byte("hello world"), []byte("morethan32bytes..................")},
{[]byte("morethan32bytes.................."), []byte("morethan32bytes..................")},
}
for _, tc := range cases {
t.Run("", func(t *testing.T) {
key, salt, err := DeriveKey(tc.passphrase, tc.salt)
require.NoError(t, err)
require.Equal(t, ScryptKeyLen, len(key))
if tc.salt != nil {
require.Equal(t, tc.salt, salt)
}
require.NotEqual(t, tc.passphrase, key)
})
}
}
func TestAESGCMEncryptDecrypt(t *testing.T) {
var (
passphrase = []byte("my priv4te k3y")
salt = []byte("my sup3r s3lt")
message = []byte("12345678901234567890123456789012")
)
key, salt, err := DeriveKey(passphrase, salt)
require.NoError(t, err)
require.Equal(t, salt, salt)
require.NotEqual(t, passphrase, key)
require.Equal(t, ScryptKeyLen, len(key))
enc, err := AESGCMEncrypt(key, message)
require.NoError(t, err)
require.NotEqual(t, message, enc)
dec, err := AESGCMDecrypt(key, enc)
require.NoError(t, err)
require.Equal(t, message, dec)
}
func TestAESCTRStream(t *testing.T) {
var (
passphrase = []byte("my priv4te k3y")
message1 = []byte("hello world!")
message2 = []byte("hi planet!")
enc1 = make([]byte, len(message1))
enc2 = make([]byte, len(message2))
)
// generate nonce with AES' blocksize
nonce, err := GenerateNonceSize(aes.BlockSize)
require.NoError(t, err)
require.NotNil(t, nonce)
// derive key for AES
key, salt, err := DeriveKey(passphrase, nonce)
require.NoError(t, err)
require.NotNil(t, key)
require.Equal(t, nonce, salt)
// encrypt
{
stream, err := AESCTRStream(key, nonce)
require.NoError(t, err)
stream.XORKeyStream(enc1, message1)
stream.XORKeyStream(enc2, message2)
require.NotEqual(t, enc1, message1)
require.NotEqual(t, enc2, message2)
require.Equal(t, len(enc1), len(message1))
require.Equal(t, len(enc2), len(message2))
}
// decrypt
{
var (
dec1 = make([]byte, len(message1))
dec2 = make([]byte, len(message2))
)
stream, err := AESCTRStream(key, nonce)
require.NoError(t, err)
stream.XORKeyStream(dec1, enc1)
stream.XORKeyStream(dec2, enc2)
require.Equal(t, dec1, message1)
require.Equal(t, dec2, message2)
}
// silently failing invalid decrypt
{
invalidKey, _, err := DeriveKey([]byte("invalid passphrase"), nonce)
var (
dec1 = make([]byte, len(message1))
dec2 = make([]byte, len(message2))
)
require.NoError(t, err)
require.NotNil(t, invalidKey)
stream, err := AESCTRStream(invalidKey, nonce)
require.NoError(t, err)
stream.XORKeyStream(dec1, enc1)
stream.XORKeyStream(dec2, enc2)
require.NotEqual(t, dec1, message1)
require.NotEqual(t, dec2, message2)
require.NotEqual(t, dec1, enc1)
require.NotEqual(t, dec2, enc2)
require.Equal(t, len(dec1), len(enc1))
require.Equal(t, len(dec2), len(enc2))
}
}
================================================
FILE: pkg/cryptoutil/doc.go
================================================
// Package cryptoutil contains generic & stateless crypto helpers.
package cryptoutil
================================================
FILE: pkg/cryptoutil/signer_wrapper.go
================================================
package cryptoutil
import (
stdcrypto "crypto"
"io"
libp2p_ci "github.com/libp2p/go-libp2p/core/crypto"
)
func NewFuncSigner(key libp2p_ci.PubKey, signer func([]byte) ([]byte, error)) stdcrypto.Signer {
return &funcSigner{
pubKey: key,
signer: signer,
}
}
type funcSigner struct {
pubKey libp2p_ci.PubKey
signer func([]byte) ([]byte, error)
}
func (f *funcSigner) Public() stdcrypto.PublicKey {
return f.pubKey
}
func (f *funcSigner) Sign(_ io.Reader, digest []byte, _ stdcrypto.SignerOpts) (signature []byte, err error) {
return f.signer(digest)
}
================================================
FILE: pkg/errcode/doc.go
================================================
// Package errcode contains the list of Berty error codes.
package errcode
================================================
FILE: pkg/errcode/errcode.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: errcode/errcode.proto
package errcode
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ErrCode int32
const (
ErrCode_Undefined ErrCode = 0 // default value, should never be set manually
ErrCode_TODO ErrCode = 666 // indicates that you plan to create an error later
ErrCode_ErrNotImplemented ErrCode = 777 // indicates that a method is not implemented yet
ErrCode_ErrInternal ErrCode = 888 // indicates an unknown error (without Code), i.e. in gRPC
ErrCode_ErrInvalidInput ErrCode = 100
ErrCode_ErrInvalidRange ErrCode = 101
ErrCode_ErrMissingInput ErrCode = 102
ErrCode_ErrSerialization ErrCode = 103
ErrCode_ErrDeserialization ErrCode = 104
ErrCode_ErrStreamRead ErrCode = 105
ErrCode_ErrStreamWrite ErrCode = 106
ErrCode_ErrStreamTransform ErrCode = 110
ErrCode_ErrStreamSendAndClose ErrCode = 111
ErrCode_ErrStreamHeaderWrite ErrCode = 112
ErrCode_ErrStreamHeaderRead ErrCode = 115
ErrCode_ErrStreamSink ErrCode = 113
ErrCode_ErrStreamCloseAndRecv ErrCode = 114
ErrCode_ErrMissingMapKey ErrCode = 107
ErrCode_ErrDBWrite ErrCode = 108
ErrCode_ErrDBRead ErrCode = 109
ErrCode_ErrDBDestroy ErrCode = 120
ErrCode_ErrDBMigrate ErrCode = 121
ErrCode_ErrDBReplay ErrCode = 122
ErrCode_ErrDBRestore ErrCode = 123
ErrCode_ErrDBOpen ErrCode = 124
ErrCode_ErrDBClose ErrCode = 125
ErrCode_ErrCryptoRandomGeneration ErrCode = 200
ErrCode_ErrCryptoKeyGeneration ErrCode = 201
ErrCode_ErrCryptoNonceGeneration ErrCode = 202
ErrCode_ErrCryptoSignature ErrCode = 203
ErrCode_ErrCryptoSignatureVerification ErrCode = 204
ErrCode_ErrCryptoDecrypt ErrCode = 205
ErrCode_ErrCryptoDecryptPayload ErrCode = 206
ErrCode_ErrCryptoEncrypt ErrCode = 207
ErrCode_ErrCryptoKeyConversion ErrCode = 208
ErrCode_ErrCryptoCipherInit ErrCode = 209
ErrCode_ErrCryptoKeyDerivation ErrCode = 210
ErrCode_ErrMap ErrCode = 300
ErrCode_ErrForEach ErrCode = 301
ErrCode_ErrKeystoreGet ErrCode = 400
ErrCode_ErrKeystorePut ErrCode = 401
ErrCode_ErrNotFound ErrCode = 404 // generic
ErrCode_ErrOrbitDBInit ErrCode = 1000
ErrCode_ErrOrbitDBOpen ErrCode = 1001
ErrCode_ErrOrbitDBAppend ErrCode = 1002
ErrCode_ErrOrbitDBDeserialization ErrCode = 1003
ErrCode_ErrOrbitDBStoreCast ErrCode = 1004
ErrCode_ErrHandshakeOwnEphemeralKeyGenSend ErrCode = 1100
ErrCode_ErrHandshakePeerEphemeralKeyRecv ErrCode = 1101
ErrCode_ErrHandshakeRequesterAuthenticateBoxKeyGen ErrCode = 1102
ErrCode_ErrHandshakeResponderAcceptBoxKeyGen ErrCode = 1103
ErrCode_ErrHandshakeRequesterHello ErrCode = 1104
ErrCode_ErrHandshakeResponderHello ErrCode = 1105
ErrCode_ErrHandshakeRequesterAuthenticate ErrCode = 1106
ErrCode_ErrHandshakeResponderAccept ErrCode = 1107
ErrCode_ErrHandshakeRequesterAcknowledge ErrCode = 1108
ErrCode_ErrContactRequestSameAccount ErrCode = 1200
ErrCode_ErrContactRequestContactAlreadyAdded ErrCode = 1201
ErrCode_ErrContactRequestContactBlocked ErrCode = 1202
ErrCode_ErrContactRequestContactUndefined ErrCode = 1203
ErrCode_ErrContactRequestIncomingAlreadyReceived ErrCode = 1204
ErrCode_ErrGroupMemberLogEventOpen ErrCode = 1300
ErrCode_ErrGroupMemberLogEventSignature ErrCode = 1301
ErrCode_ErrGroupMemberUnknownGroupID ErrCode = 1302
ErrCode_ErrGroupSecretOtherDestMember ErrCode = 1303
ErrCode_ErrGroupSecretAlreadySentToMember ErrCode = 1304
ErrCode_ErrGroupInvalidType ErrCode = 1305
ErrCode_ErrGroupMissing ErrCode = 1306
ErrCode_ErrGroupActivate ErrCode = 1307
ErrCode_ErrGroupDeactivate ErrCode = 1308
ErrCode_ErrGroupInfo ErrCode = 1309
ErrCode_ErrGroupUnknown ErrCode = 1310
ErrCode_ErrGroupOpen ErrCode = 1311
ErrCode_ErrMessageKeyPersistencePut ErrCode = 1500
ErrCode_ErrMessageKeyPersistenceGet ErrCode = 1501
ErrCode_ErrServiceReplication ErrCode = 4100
ErrCode_ErrServiceReplicationServer ErrCode = 4101
ErrCode_ErrServiceReplicationMissingEndpoint ErrCode = 4102
ErrCode_ErrServicesDirectory ErrCode = 4200
ErrCode_ErrServicesDirectoryInvalidVerifiedCredentialSubject ErrCode = 4201
ErrCode_ErrServicesDirectoryExistingRecordNotFound ErrCode = 4202
ErrCode_ErrServicesDirectoryRecordLockedAndCantBeReplaced ErrCode = 4203
ErrCode_ErrServicesDirectoryExplicitReplaceFlagRequired ErrCode = 4204
ErrCode_ErrServicesDirectoryInvalidVerifiedCredential ErrCode = 4205
ErrCode_ErrServicesDirectoryExpiredVerifiedCredential ErrCode = 4206
ErrCode_ErrServicesDirectoryInvalidVerifiedCredentialID ErrCode = 4207
)
// Enum value maps for ErrCode.
var (
ErrCode_name = map[int32]string{
0: "Undefined",
666: "TODO",
777: "ErrNotImplemented",
888: "ErrInternal",
100: "ErrInvalidInput",
101: "ErrInvalidRange",
102: "ErrMissingInput",
103: "ErrSerialization",
104: "ErrDeserialization",
105: "ErrStreamRead",
106: "ErrStreamWrite",
110: "ErrStreamTransform",
111: "ErrStreamSendAndClose",
112: "ErrStreamHeaderWrite",
115: "ErrStreamHeaderRead",
113: "ErrStreamSink",
114: "ErrStreamCloseAndRecv",
107: "ErrMissingMapKey",
108: "ErrDBWrite",
109: "ErrDBRead",
120: "ErrDBDestroy",
121: "ErrDBMigrate",
122: "ErrDBReplay",
123: "ErrDBRestore",
124: "ErrDBOpen",
125: "ErrDBClose",
200: "ErrCryptoRandomGeneration",
201: "ErrCryptoKeyGeneration",
202: "ErrCryptoNonceGeneration",
203: "ErrCryptoSignature",
204: "ErrCryptoSignatureVerification",
205: "ErrCryptoDecrypt",
206: "ErrCryptoDecryptPayload",
207: "ErrCryptoEncrypt",
208: "ErrCryptoKeyConversion",
209: "ErrCryptoCipherInit",
210: "ErrCryptoKeyDerivation",
300: "ErrMap",
301: "ErrForEach",
400: "ErrKeystoreGet",
401: "ErrKeystorePut",
404: "ErrNotFound",
1000: "ErrOrbitDBInit",
1001: "ErrOrbitDBOpen",
1002: "ErrOrbitDBAppend",
1003: "ErrOrbitDBDeserialization",
1004: "ErrOrbitDBStoreCast",
1100: "ErrHandshakeOwnEphemeralKeyGenSend",
1101: "ErrHandshakePeerEphemeralKeyRecv",
1102: "ErrHandshakeRequesterAuthenticateBoxKeyGen",
1103: "ErrHandshakeResponderAcceptBoxKeyGen",
1104: "ErrHandshakeRequesterHello",
1105: "ErrHandshakeResponderHello",
1106: "ErrHandshakeRequesterAuthenticate",
1107: "ErrHandshakeResponderAccept",
1108: "ErrHandshakeRequesterAcknowledge",
1200: "ErrContactRequestSameAccount",
1201: "ErrContactRequestContactAlreadyAdded",
1202: "ErrContactRequestContactBlocked",
1203: "ErrContactRequestContactUndefined",
1204: "ErrContactRequestIncomingAlreadyReceived",
1300: "ErrGroupMemberLogEventOpen",
1301: "ErrGroupMemberLogEventSignature",
1302: "ErrGroupMemberUnknownGroupID",
1303: "ErrGroupSecretOtherDestMember",
1304: "ErrGroupSecretAlreadySentToMember",
1305: "ErrGroupInvalidType",
1306: "ErrGroupMissing",
1307: "ErrGroupActivate",
1308: "ErrGroupDeactivate",
1309: "ErrGroupInfo",
1310: "ErrGroupUnknown",
1311: "ErrGroupOpen",
1500: "ErrMessageKeyPersistencePut",
1501: "ErrMessageKeyPersistenceGet",
4100: "ErrServiceReplication",
4101: "ErrServiceReplicationServer",
4102: "ErrServiceReplicationMissingEndpoint",
4200: "ErrServicesDirectory",
4201: "ErrServicesDirectoryInvalidVerifiedCredentialSubject",
4202: "ErrServicesDirectoryExistingRecordNotFound",
4203: "ErrServicesDirectoryRecordLockedAndCantBeReplaced",
4204: "ErrServicesDirectoryExplicitReplaceFlagRequired",
4205: "ErrServicesDirectoryInvalidVerifiedCredential",
4206: "ErrServicesDirectoryExpiredVerifiedCredential",
4207: "ErrServicesDirectoryInvalidVerifiedCredentialID",
}
ErrCode_value = map[string]int32{
"Undefined": 0,
"TODO": 666,
"ErrNotImplemented": 777,
"ErrInternal": 888,
"ErrInvalidInput": 100,
"ErrInvalidRange": 101,
"ErrMissingInput": 102,
"ErrSerialization": 103,
"ErrDeserialization": 104,
"ErrStreamRead": 105,
"ErrStreamWrite": 106,
"ErrStreamTransform": 110,
"ErrStreamSendAndClose": 111,
"ErrStreamHeaderWrite": 112,
"ErrStreamHeaderRead": 115,
"ErrStreamSink": 113,
"ErrStreamCloseAndRecv": 114,
"ErrMissingMapKey": 107,
"ErrDBWrite": 108,
"ErrDBRead": 109,
"ErrDBDestroy": 120,
"ErrDBMigrate": 121,
"ErrDBReplay": 122,
"ErrDBRestore": 123,
"ErrDBOpen": 124,
"ErrDBClose": 125,
"ErrCryptoRandomGeneration": 200,
"ErrCryptoKeyGeneration": 201,
"ErrCryptoNonceGeneration": 202,
"ErrCryptoSignature": 203,
"ErrCryptoSignatureVerification": 204,
"ErrCryptoDecrypt": 205,
"ErrCryptoDecryptPayload": 206,
"ErrCryptoEncrypt": 207,
"ErrCryptoKeyConversion": 208,
"ErrCryptoCipherInit": 209,
"ErrCryptoKeyDerivation": 210,
"ErrMap": 300,
"ErrForEach": 301,
"ErrKeystoreGet": 400,
"ErrKeystorePut": 401,
"ErrNotFound": 404,
"ErrOrbitDBInit": 1000,
"ErrOrbitDBOpen": 1001,
"ErrOrbitDBAppend": 1002,
"ErrOrbitDBDeserialization": 1003,
"ErrOrbitDBStoreCast": 1004,
"ErrHandshakeOwnEphemeralKeyGenSend": 1100,
"ErrHandshakePeerEphemeralKeyRecv": 1101,
"ErrHandshakeRequesterAuthenticateBoxKeyGen": 1102,
"ErrHandshakeResponderAcceptBoxKeyGen": 1103,
"ErrHandshakeRequesterHello": 1104,
"ErrHandshakeResponderHello": 1105,
"ErrHandshakeRequesterAuthenticate": 1106,
"ErrHandshakeResponderAccept": 1107,
"ErrHandshakeRequesterAcknowledge": 1108,
"ErrContactRequestSameAccount": 1200,
"ErrContactRequestContactAlreadyAdded": 1201,
"ErrContactRequestContactBlocked": 1202,
"ErrContactRequestContactUndefined": 1203,
"ErrContactRequestIncomingAlreadyReceived": 1204,
"ErrGroupMemberLogEventOpen": 1300,
"ErrGroupMemberLogEventSignature": 1301,
"ErrGroupMemberUnknownGroupID": 1302,
"ErrGroupSecretOtherDestMember": 1303,
"ErrGroupSecretAlreadySentToMember": 1304,
"ErrGroupInvalidType": 1305,
"ErrGroupMissing": 1306,
"ErrGroupActivate": 1307,
"ErrGroupDeactivate": 1308,
"ErrGroupInfo": 1309,
"ErrGroupUnknown": 1310,
"ErrGroupOpen": 1311,
"ErrMessageKeyPersistencePut": 1500,
"ErrMessageKeyPersistenceGet": 1501,
"ErrServiceReplication": 4100,
"ErrServiceReplicationServer": 4101,
"ErrServiceReplicationMissingEndpoint": 4102,
"ErrServicesDirectory": 4200,
"ErrServicesDirectoryInvalidVerifiedCredentialSubject": 4201,
"ErrServicesDirectoryExistingRecordNotFound": 4202,
"ErrServicesDirectoryRecordLockedAndCantBeReplaced": 4203,
"ErrServicesDirectoryExplicitReplaceFlagRequired": 4204,
"ErrServicesDirectoryInvalidVerifiedCredential": 4205,
"ErrServicesDirectoryExpiredVerifiedCredential": 4206,
"ErrServicesDirectoryInvalidVerifiedCredentialID": 4207,
}
)
func (x ErrCode) Enum() *ErrCode {
p := new(ErrCode)
*p = x
return p
}
func (x ErrCode) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ErrCode) Descriptor() protoreflect.EnumDescriptor {
return file_errcode_errcode_proto_enumTypes[0].Descriptor()
}
func (ErrCode) Type() protoreflect.EnumType {
return &file_errcode_errcode_proto_enumTypes[0]
}
func (x ErrCode) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ErrCode.Descriptor instead.
func (ErrCode) EnumDescriptor() ([]byte, []int) {
return file_errcode_errcode_proto_rawDescGZIP(), []int{0}
}
type ErrDetails struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Codes []ErrCode `protobuf:"varint,1,rep,packed,name=codes,proto3,enum=weshnet.errcode.ErrCode" json:"codes,omitempty"`
}
func (x *ErrDetails) Reset() {
*x = ErrDetails{}
if protoimpl.UnsafeEnabled {
mi := &file_errcode_errcode_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrDetails) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrDetails) ProtoMessage() {}
func (x *ErrDetails) ProtoReflect() protoreflect.Message {
mi := &file_errcode_errcode_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrDetails.ProtoReflect.Descriptor instead.
func (*ErrDetails) Descriptor() ([]byte, []int) {
return file_errcode_errcode_proto_rawDescGZIP(), []int{0}
}
func (x *ErrDetails) GetCodes() []ErrCode {
if x != nil {
return x.Codes
}
return nil
}
var File_errcode_errcode_proto protoreflect.FileDescriptor
var file_errcode_errcode_proto_rawDesc = []byte{
0x0a, 0x15, 0x65, 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x2f, 0x65, 0x72, 0x72, 0x63, 0x6f, 0x64,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x65, 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x3c, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x44,
0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x65, 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52,
0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2a, 0xdb, 0x13, 0x0a, 0x07, 0x45, 0x72, 0x72, 0x43, 0x6f,
0x64, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10,
0x00, 0x12, 0x09, 0x0a, 0x04, 0x54, 0x4f, 0x44, 0x4f, 0x10, 0x9a, 0x05, 0x12, 0x16, 0x0a, 0x11,
0x45, 0x72, 0x72, 0x4e, 0x6f, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65,
0x64, 0x10, 0x89, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x10, 0xf8, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x72, 0x72, 0x49, 0x6e, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x10, 0x64, 0x12, 0x13, 0x0a, 0x0f, 0x45,
0x72, 0x72, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x10, 0x65,
0x12, 0x13, 0x0a, 0x0f, 0x45, 0x72, 0x72, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x49, 0x6e,
0x70, 0x75, 0x74, 0x10, 0x66, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x67, 0x12, 0x16, 0x0a, 0x12, 0x45,
0x72, 0x72, 0x44, 0x65, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x10, 0x68, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x52, 0x65, 0x61, 0x64, 0x10, 0x69, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x10, 0x6a, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x72,
0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d,
0x10, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53,
0x65, 0x6e, 0x64, 0x41, 0x6e, 0x64, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x10, 0x6f, 0x12, 0x18, 0x0a,
0x14, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x57, 0x72, 0x69, 0x74, 0x65, 0x10, 0x70, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x72, 0x72, 0x53, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x61, 0x64, 0x10, 0x73,
0x12, 0x11, 0x0a, 0x0d, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x69, 0x6e,
0x6b, 0x10, 0x71, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x72, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x76, 0x10, 0x72, 0x12, 0x14,
0x0a, 0x10, 0x45, 0x72, 0x72, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x4b,
0x65, 0x79, 0x10, 0x6b, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x44, 0x42, 0x57, 0x72, 0x69,
0x74, 0x65, 0x10, 0x6c, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x44, 0x42, 0x52, 0x65, 0x61,
0x64, 0x10, 0x6d, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x44, 0x42, 0x44, 0x65, 0x73, 0x74,
0x72, 0x6f, 0x79, 0x10, 0x78, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x44, 0x42, 0x4d, 0x69,
0x67, 0x72, 0x61, 0x74, 0x65, 0x10, 0x79, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x44, 0x42,
0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x10, 0x7a, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x44,
0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x10, 0x7b, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x72,
0x72, 0x44, 0x42, 0x4f, 0x70, 0x65, 0x6e, 0x10, 0x7c, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x72, 0x72,
0x44, 0x42, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x10, 0x7d, 0x12, 0x1e, 0x0a, 0x19, 0x45, 0x72, 0x72,
0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x47, 0x65, 0x6e, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xc8, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x45, 0x72, 0x72,
0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x10, 0xc9, 0x01, 0x12, 0x1d, 0x0a, 0x18, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79,
0x70, 0x74, 0x6f, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x10, 0xca, 0x01, 0x12, 0x17, 0x0a, 0x12, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79, 0x70,
0x74, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0xcb, 0x01, 0x12, 0x23,
0x0a, 0x1e, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x10, 0xcc, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f,
0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x10, 0xcd, 0x01, 0x12, 0x1c, 0x0a, 0x17, 0x45, 0x72,
0x72, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x50, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x10, 0xce, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x72, 0x72, 0x43,
0x72, 0x79, 0x70, 0x74, 0x6f, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x10, 0xcf, 0x01, 0x12,
0x1b, 0x0a, 0x16, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x43,
0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x10, 0xd0, 0x01, 0x12, 0x18, 0x0a, 0x13,
0x45, 0x72, 0x72, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x49,
0x6e, 0x69, 0x74, 0x10, 0xd1, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x45, 0x72, 0x72, 0x43, 0x72, 0x79,
0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x10, 0xd2, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x61, 0x70, 0x10, 0xac, 0x02,
0x12, 0x0f, 0x0a, 0x0a, 0x45, 0x72, 0x72, 0x46, 0x6f, 0x72, 0x45, 0x61, 0x63, 0x68, 0x10, 0xad,
0x02, 0x12, 0x13, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x47, 0x65, 0x74, 0x10, 0x90, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x4b, 0x65, 0x79,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x75, 0x74, 0x10, 0x91, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x45,
0x72, 0x72, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0x94, 0x03, 0x12, 0x13, 0x0a,
0x0e, 0x45, 0x72, 0x72, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x49, 0x6e, 0x69, 0x74, 0x10,
0xe8, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42,
0x4f, 0x70, 0x65, 0x6e, 0x10, 0xe9, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x72, 0x72, 0x4f, 0x72,
0x62, 0x69, 0x74, 0x44, 0x42, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x10, 0xea, 0x07, 0x12, 0x1e,
0x0a, 0x19, 0x45, 0x72, 0x72, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x44, 0x65, 0x73, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xeb, 0x07, 0x12, 0x18,
0x0a, 0x13, 0x45, 0x72, 0x72, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x53, 0x74, 0x6f, 0x72,
0x65, 0x43, 0x61, 0x73, 0x74, 0x10, 0xec, 0x07, 0x12, 0x27, 0x0a, 0x22, 0x45, 0x72, 0x72, 0x48,
0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x4f, 0x77, 0x6e, 0x45, 0x70, 0x68, 0x65, 0x6d,
0x65, 0x72, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x47, 0x65, 0x6e, 0x53, 0x65, 0x6e, 0x64, 0x10, 0xcc,
0x08, 0x12, 0x25, 0x0a, 0x20, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b,
0x65, 0x50, 0x65, 0x65, 0x72, 0x45, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x4b, 0x65,
0x79, 0x52, 0x65, 0x63, 0x76, 0x10, 0xcd, 0x08, 0x12, 0x2f, 0x0a, 0x2a, 0x45, 0x72, 0x72, 0x48,
0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65,
0x72, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x6f, 0x78,
0x4b, 0x65, 0x79, 0x47, 0x65, 0x6e, 0x10, 0xce, 0x08, 0x12, 0x29, 0x0a, 0x24, 0x45, 0x72, 0x72,
0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64,
0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x42, 0x6f, 0x78, 0x4b, 0x65, 0x79, 0x47, 0x65,
0x6e, 0x10, 0xcf, 0x08, 0x12, 0x1f, 0x0a, 0x1a, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73,
0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72, 0x48, 0x65, 0x6c,
0x6c, 0x6f, 0x10, 0xd0, 0x08, 0x12, 0x1f, 0x0a, 0x1a, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e, 0x64,
0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x10, 0xd1, 0x08, 0x12, 0x26, 0x0a, 0x21, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e,
0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72, 0x41,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xd2, 0x08, 0x12, 0x20,
0x0a, 0x1b, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x10, 0xd3, 0x08,
0x12, 0x25, 0x0a, 0x20, 0x45, 0x72, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72, 0x41, 0x63, 0x6b, 0x6e, 0x6f, 0x77, 0x6c,
0x65, 0x64, 0x67, 0x65, 0x10, 0xd4, 0x08, 0x12, 0x21, 0x0a, 0x1c, 0x45, 0x72, 0x72, 0x43, 0x6f,
0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x61, 0x6d, 0x65,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0xb0, 0x09, 0x12, 0x29, 0x0a, 0x24, 0x45, 0x72,
0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x41, 0x64, 0x64,
0x65, 0x64, 0x10, 0xb1, 0x09, 0x12, 0x24, 0x0a, 0x1f, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x10, 0xb2, 0x09, 0x12, 0x26, 0x0a, 0x21, 0x45,
0x72, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
0x10, 0xb3, 0x09, 0x12, 0x2d, 0x0a, 0x28, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67,
0x41, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x10,
0xb4, 0x09, 0x12, 0x1f, 0x0a, 0x1a, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x65, 0x6e,
0x10, 0x94, 0x0a, 0x12, 0x24, 0x0a, 0x1f, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67,
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x95, 0x0a, 0x12, 0x21, 0x0a, 0x1c, 0x45, 0x72, 0x72,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x55, 0x6e, 0x6b, 0x6e, 0x6f,
0x77, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x10, 0x96, 0x0a, 0x12, 0x22, 0x0a, 0x1d,
0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4f, 0x74,
0x68, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x10, 0x97, 0x0a,
0x12, 0x26, 0x0a, 0x21, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x41, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x4d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x10, 0x98, 0x0a, 0x12, 0x18, 0x0a, 0x13, 0x45, 0x72, 0x72, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x79, 0x70, 0x65, 0x10,
0x99, 0x0a, 0x12, 0x14, 0x0a, 0x0f, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x69,
0x73, 0x73, 0x69, 0x6e, 0x67, 0x10, 0x9a, 0x0a, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x72, 0x72, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x10, 0x9b, 0x0a, 0x12,
0x17, 0x0a, 0x12, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x61, 0x63, 0x74,
0x69, 0x76, 0x61, 0x74, 0x65, 0x10, 0x9c, 0x0a, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x10, 0x9d, 0x0a, 0x12, 0x14, 0x0a, 0x0f, 0x45,
0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x9e,
0x0a, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x72, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4f, 0x70, 0x65,
0x6e, 0x10, 0x9f, 0x0a, 0x12, 0x20, 0x0a, 0x1b, 0x45, 0x72, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65,
0x50, 0x75, 0x74, 0x10, 0xdc, 0x0b, 0x12, 0x20, 0x0a, 0x1b, 0x45, 0x72, 0x72, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e,
0x63, 0x65, 0x47, 0x65, 0x74, 0x10, 0xdd, 0x0b, 0x12, 0x1a, 0x0a, 0x15, 0x45, 0x72, 0x72, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x10, 0x84, 0x20, 0x12, 0x20, 0x0a, 0x1b, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x10, 0x85, 0x20, 0x12, 0x29, 0x0a, 0x24, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d,
0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x10, 0x86,
0x20, 0x12, 0x19, 0x0a, 0x14, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x10, 0xe8, 0x20, 0x12, 0x39, 0x0a, 0x34,
0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63,
0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66,
0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x10, 0xe9, 0x20, 0x12, 0x2f, 0x0a, 0x2a, 0x45, 0x72, 0x72, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45,
0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4e, 0x6f, 0x74,
0x46, 0x6f, 0x75, 0x6e, 0x64, 0x10, 0xea, 0x20, 0x12, 0x36, 0x0a, 0x31, 0x45, 0x72, 0x72, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x6e, 0x64, 0x43,
0x61, 0x6e, 0x74, 0x42, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x10, 0xeb, 0x20,
0x12, 0x34, 0x0a, 0x2f, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44,
0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74,
0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x64, 0x10, 0xec, 0x20, 0x12, 0x32, 0x0a, 0x2d, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e,
0x76, 0x61, 0x6c, 0x69, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x10, 0xed, 0x20, 0x12, 0x32, 0x0a, 0x2d, 0x45, 0x72,
0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f,
0x72, 0x79, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65,
0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x10, 0xee, 0x20, 0x12, 0x34,
0x0a, 0x2f, 0x45, 0x72, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x44, 0x69, 0x72,
0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x56, 0x65, 0x72,
0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
0x44, 0x10, 0xef, 0x20, 0x42, 0x23, 0x5a, 0x21, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x74, 0x65,
0x63, 0x68, 0x2f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b,
0x67, 0x2f, 0x65, 0x72, 0x72, 0x63, 0x6f, 0x64, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_errcode_errcode_proto_rawDescOnce sync.Once
file_errcode_errcode_proto_rawDescData = file_errcode_errcode_proto_rawDesc
)
func file_errcode_errcode_proto_rawDescGZIP() []byte {
file_errcode_errcode_proto_rawDescOnce.Do(func() {
file_errcode_errcode_proto_rawDescData = protoimpl.X.CompressGZIP(file_errcode_errcode_proto_rawDescData)
})
return file_errcode_errcode_proto_rawDescData
}
var file_errcode_errcode_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_errcode_errcode_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_errcode_errcode_proto_goTypes = []any{
(ErrCode)(0), // 0: weshnet.errcode.ErrCode
(*ErrDetails)(nil), // 1: weshnet.errcode.ErrDetails
}
var file_errcode_errcode_proto_depIdxs = []int32{
0, // 0: weshnet.errcode.ErrDetails.codes:type_name -> weshnet.errcode.ErrCode
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_errcode_errcode_proto_init() }
func file_errcode_errcode_proto_init() {
if File_errcode_errcode_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_errcode_errcode_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*ErrDetails); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_errcode_errcode_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_errcode_errcode_proto_goTypes,
DependencyIndexes: file_errcode_errcode_proto_depIdxs,
EnumInfos: file_errcode_errcode_proto_enumTypes,
MessageInfos: file_errcode_errcode_proto_msgTypes,
}.Build()
File_errcode_errcode_proto = out.File
file_errcode_errcode_proto_rawDesc = nil
file_errcode_errcode_proto_goTypes = nil
file_errcode_errcode_proto_depIdxs = nil
}
================================================
FILE: pkg/errcode/error.go
================================================
package errcode
import (
"fmt"
"io"
"slices"
"golang.org/x/xerrors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// WithCode defines an error that can be used by helpers of this package.
type WithCode interface {
error
Code() ErrCode
}
// Codes returns a list of wrapped codes
func Codes(err error) []ErrCode {
if err == nil {
return nil
}
codes := []ErrCode{}
if st := getGRPCStatus(err); st != nil {
return codesFromGRPCStatus(st)
}
if code := currentCode(err); code != -1 {
codes = []ErrCode{code}
}
if cause := genericCause(err); cause != nil {
causeCodes := Codes(cause)
if len(causeCodes) > 0 {
codes = append(codes, Codes(cause)...)
}
}
return codes
}
// Has returns true if one of the error is or contains (wraps) an expected errcode
func Has(err error, code WithCode) bool {
codeCode := code.Code()
return slices.Contains(Codes(err), codeCode)
}
// Is returns true if the top-level error (it doesn't unwrap it) is actually an ErrCode of the same value
func Is(err error, code WithCode) bool {
return currentCode(err) == code.Code()
}
// currentCode returns the code of the actual error without trying to unwrap it, or -1.
func currentCode(err error) ErrCode {
if err == nil {
return -1
}
if typed, ok := err.(WithCode); ok {
return typed.Code()
}
if st := getGRPCStatus(err); st != nil {
codes := codesFromGRPCStatus(st)
if len(codes) > 0 {
return codes[0]
}
return -1
}
return -1
}
// Code walks the passed error and returns the code of the first ErrCode met, or -1.
func Code(err error) ErrCode {
if err == nil {
return -1
}
if code := currentCode(err); code != -1 {
return code
}
if cause := genericCause(err); cause != nil {
return Code(cause)
}
return -1
}
// LastCode walks the passed error and returns the code of the latest ErrCode, or -1.
func LastCode(err error) ErrCode {
if err == nil {
return -1
}
if cause := genericCause(err); cause != nil {
if ret := LastCode(cause); ret != -1 {
return ret
}
}
if st := getGRPCStatus(err); st != nil {
codes := codesFromGRPCStatus(st)
if len(codes) > 0 {
return codes[len(codes)-1]
}
return -1
}
return currentCode(err)
}
func genericCause(err error) error {
type causer interface{ Cause() error }
type wrapper interface{ Unwrap() error }
if causer, ok := err.(causer); ok {
return causer.Cause()
}
if wrapper, ok := err.(wrapper); ok {
return wrapper.Unwrap()
}
return nil
}
//
// Error
//
func (e ErrCode) Error() string {
name, ok := ErrCode_name[int32(e)]
if ok {
return fmt.Sprintf("%s(#%d)", name, e)
}
return fmt.Sprintf("UNKNOWN_ERRCODE(#%d)", e)
}
func (e ErrCode) Code() ErrCode {
return e
}
func (e ErrCode) Wrap(inner error) WithCode {
return wrappedError{
code: e,
inner: inner,
frame: xerrors.Caller(1),
}
}
func (e ErrCode) GRPCStatus() *status.Status {
code := grpcCodeFromWithCode(e)
st, _ := status.New(code, e.Error()).WithDetails(
&ErrDetails{Codes: Codes(e)},
)
return st
}
//
// ConfigurableError
//
type wrappedError struct {
code ErrCode
inner error
frame xerrors.Frame
}
func (e wrappedError) Error() string {
return fmt.Sprintf("%s: %v", e.code, e.inner)
}
func (e wrappedError) Code() ErrCode {
return e.code
}
// Cause returns the inner error (github.com/pkg/errors)
func (e wrappedError) Cause() error {
return e.inner
}
// Unwrap returns the inner error (go1.13)
func (e wrappedError) Unwrap() error {
return e.inner
}
func (e wrappedError) GRPCStatus() *status.Status {
code := grpcCodeFromWithCode(e)
st, _ := status.New(code, e.Error()).WithDetails(
&ErrDetails{Codes: Codes(e)},
)
return st
}
func (e wrappedError) Format(f fmt.State, c rune) {
xerrors.FormatError(e, f, c)
if f.Flag('+') {
_, _ = io.WriteString(f, "\n")
if sub := genericCause(e); sub != nil {
if typed, ok := sub.(wrappedError); ok {
sub = lightWrappedError{wrappedError: typed}
}
formatter, ok := sub.(fmt.Formatter)
if ok {
formatter.Format(f, c)
}
}
}
}
func (e wrappedError) FormatError(p xerrors.Printer) error {
p.Print(e.Error())
if p.Detail() {
e.frame.Format(p)
}
return nil
}
//
// light wrapper (used to make prettier (less verbose) stacks)
//
type lightWrappedError struct {
wrappedError
deepness int
}
func (e lightWrappedError) Error() string { return "" }
func (e lightWrappedError) Format(f fmt.State, c rune) {
xerrors.FormatError(e, f, c)
if f.Flag('+') {
_, _ = io.WriteString(f, "\n")
if sub := genericCause(e); sub != nil {
if typed, ok := sub.(wrappedError); ok {
sub = lightWrappedError{wrappedError: typed, deepness: e.deepness + 1}
}
formatter, ok := sub.(fmt.Formatter)
if ok {
formatter.Format(f, c)
}
}
}
}
func (e lightWrappedError) FormatError(p xerrors.Printer) error {
p.Printf("#%d", e.deepness+1)
e.frame.Format(p)
return nil
}
//
// gRPC helpers
//
func codesFromGRPCStatus(st *status.Status) []ErrCode {
details := st.Details()
for _, detail := range details {
if typed, ok := detail.(*ErrDetails); ok {
return typed.Codes
}
}
return nil
}
func grpcCodeFromWithCode(WithCode) codes.Code {
// here, we can do a big switch case if we plan to make accurate gRPC codes
// but we probably don't care
return codes.Unavailable
}
type gRPCStatus interface{ GRPCStatus() *status.Status }
func getGRPCStatus(err error) *status.Status {
if _, ok := err.(WithCode); !ok {
if typed, ok := err.(gRPCStatus); ok {
return typed.GRPCStatus()
}
}
return nil
}
================================================
FILE: pkg/errcode/error_test.go
================================================
package errcode
import (
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
errStdHello = fmt.Errorf("hello")
errCodeUndef = ErrCode(65530) // simulate a client receiving an error generated from a more recent API
)
func TestError(t *testing.T) {
// test instance
var (
_ ErrCode = ErrCode_ErrNotImplemented
_ error = ErrCode_ErrNotImplemented
_ WithCode = ErrCode_ErrNotImplemented
)
// table-driven tests
tests := []struct {
name string
input error
expectedString string
expectedCause error
expectedCode ErrCode
expectedLastCode ErrCode
expectedCodes []ErrCode
has777 bool
has888 bool
is777 bool
is888 bool
}{
{"ErrInternal", ErrCode_ErrInternal, "ErrInternal(#888)", ErrCode_ErrInternal, 888, 888, []ErrCode{888}, false, true, false, true},
{"ErrNotImplemented", ErrCode_ErrNotImplemented, "ErrNotImplemented(#777)", ErrCode_ErrNotImplemented, 777, 777, []ErrCode{777}, true, false, true, false},
{"ErrNotImplemented.Wrap(ErrInternal)", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal), "ErrNotImplemented(#777): ErrInternal(#888)", ErrCode_ErrInternal, 777, 888, []ErrCode{777, 888}, true, true, true, false},
{"ErrNotImplemented.Wrap(ErrInternal.Wrap(TODO))", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal.Wrap(ErrCode_TODO)), "ErrNotImplemented(#777): ErrInternal(#888): TODO(#666)", ErrCode_TODO, 777, 666, []ErrCode{777, 888, 666}, true, true, true, false},
{"ErrNotImplemented.Wrap(ErrInternal.Wrap(errStdHello))", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal.Wrap(errStdHello)), "ErrNotImplemented(#777): ErrInternal(#888): hello", errStdHello, 777, 888, []ErrCode{777, 888}, true, true, true, false},
{"ErrNotImplemented.Wrap(errStdHello)", ErrCode_ErrNotImplemented.Wrap(errStdHello), "ErrNotImplemented(#777): hello", errStdHello, 777, 777, []ErrCode{777}, true, false, true, false},
{"errCodeUndef", errCodeUndef, "UNKNOWN_ERRCODE(#65530)", errCodeUndef, 65530, 65530, []ErrCode{65530}, false, false, false, false},
{"errStdHello", errStdHello, "hello", errStdHello, -1, -1, []ErrCode{}, false, false, false, false},
{"nil", nil, "", nil, -1, -1, nil, false, false, false, false},
{`errors.Wrap(ErrNotImplemented,blah)`, errors.Wrap(ErrCode_ErrNotImplemented, "blah"), "blah: ErrNotImplemented(#777)", ErrCode_ErrNotImplemented, 777, 777, []ErrCode{777}, true, false, false, false},
{`errors.Wrap(ErrNotImplemented.Wrap(ErrInternal),blah)`, errors.Wrap(ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal), "blah"), "blah: ErrNotImplemented(#777): ErrInternal(#888)", ErrCode_ErrInternal, 777, 888, []ErrCode{777, 888}, true, true, false, false},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expectedString, fmt.Sprint(test.input))
assert.Equal(t, test.expectedCode, Code(test.input))
assert.Equal(t, test.expectedLastCode, LastCode(test.input))
assert.Equal(t, test.expectedCause, errors.Cause(test.input))
assert.Equal(t, test.expectedCodes, Codes(test.input))
assert.Equal(t, test.has777, Has(test.input, ErrCode_ErrNotImplemented))
assert.Equal(t, test.has888, Has(test.input, ErrCode_ErrInternal))
assert.Equal(t, test.is777, Is(test.input, ErrCode_ErrNotImplemented))
assert.Equal(t, test.is888, Is(test.input, ErrCode_ErrInternal))
})
}
}
func TestStatus(t *testing.T) {
tests := []struct {
name string
input error
has777 bool
has888 bool
expectedGrpcCode codes.Code
hasGrpcStatus bool
}{
{"ErrInternal", ErrCode_ErrInternal, false, true, codes.Unavailable, true},
{"ErrNotImplemented", ErrCode_ErrNotImplemented, true, false, codes.Unavailable, true},
{"ErrNotImplemented.Wrap(ErrInternal)", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal), true, true, codes.Unavailable, true},
{"ErrNotImplemented.Wrap(ErrInternal.Wrap(ErrNotImplemented))", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal.Wrap(ErrCode_ErrNotImplemented)), true, true, codes.Unavailable, true},
{"ErrNotImplemented.Wrap(ErrInternal.Wrap(TODO))", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal.Wrap(ErrCode_TODO)), true, true, codes.Unavailable, true},
{"ErrNotImplemented.Wrap(ErrInternal.Wrap(errStdHello))", ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal.Wrap(errStdHello)), true, true, codes.Unavailable, true},
{"ErrNotImplemented.Wrap(errStdHello)", ErrCode_ErrNotImplemented.Wrap(errStdHello), true, false, codes.Unavailable, true},
{"errCodeUndef", errCodeUndef, false, false, codes.Unavailable, true},
{"errStdHello", errStdHello, false, false, codes.Unknown, false},
{"nil", nil, false, false, codes.OK, true},
{`errors.Wrap(ErrNotImplemented,blah)`, errors.Wrap(ErrCode_ErrNotImplemented, "blah"), true, false, codes.Unavailable, true},
{`errors.Wrap(ErrNotImplemented.Wrap(ErrInternal},blah)`, errors.Wrap(ErrCode_ErrNotImplemented.Wrap(ErrCode_ErrInternal), "blah"), true, true, codes.Unavailable, true},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
st, ok := status.FromError(test.input)
assert.Equal(t, test.hasGrpcStatus, ok)
if test.input != nil {
assert.Error(t, st.Err())
assert.Equal(t, st.Message(), test.input.Error())
}
if test.hasGrpcStatus {
stErr := st.Err()
if test.input != nil {
assert.NotNil(t, st)
assert.Error(t, stErr)
}
assert.Equal(t, st.Code().String(), test.expectedGrpcCode.String())
assert.Equal(t, Code(test.input), Code(stErr))
assert.Equal(t, LastCode(test.input), LastCode(stErr))
assert.Equal(t, LastCode(test.input), LastCode(stErr))
assert.Equal(t, Codes(test.input), Codes(stErr))
}
})
}
}
================================================
FILE: pkg/errcode/stdproto.go
================================================
package errcode
// nolint:staticcheck // cannot use the new protobuf API while keeping gogoproto
// nolint:gochecknoinits // cannot avoid using this init func
// nolint:staticcheck // cannot use the new protobuf API while keeping gogoproto
func init() {
// the goal of this file is to register types on non-gogo proto (required by status.Details)
// proto.RegisterEnum("weshnet.errcode.ErrCode", ErrCode_name, ErrCode_value) // nolint:staticcheck // cannot use the new protobuf API while keeping gogoproto
// proto.RegisterType((*ErrDetails)(nil), "weshnet.errcode.ErrDetails") // nolint:staticcheck // cannot use the new protobuf API while keeping gogoproto
}
================================================
FILE: pkg/grpcutil/buf_listener.go
================================================
package grpcutil
import (
"context"
"net"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
)
type BufListener struct {
*bufconn.Listener
}
func NewBufListener(sz int) *BufListener {
return &BufListener{
Listener: bufconn.Listen(sz),
}
}
func (bl *BufListener) dialer(context.Context, string) (net.Conn, error) {
return bl.Dial()
}
func (bl *BufListener) NewClientConn(_ context.Context, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
mendatoryOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(bl.dialer), // set pipe dialer
}
return grpc.NewClient("passthrough://buf", append(opts, mendatoryOpts...)...)
}
================================================
FILE: pkg/grpcutil/doc.go
================================================
// Package grpcutil contains gRPC lazy codecs, messages and a buf-based listener.
package grpcutil
================================================
FILE: pkg/grpcutil/simple_auth.go
================================================
package grpcutil
import (
"context"
"google.golang.org/grpc/credentials"
)
const headerAuthorize = "authorization"
var _ credentials.PerRPCCredentials = (*unsecureSimpleAuthAccess)(nil)
// unsecureSimpleAuthAccess supplies PerRPCCredentials from a given token.
type unsecureSimpleAuthAccess struct {
token string
scheme string
}
// NewUnsecureSimpleAuthAccess constructs the PerRPCCredentials using a given token.
func NewUnsecureSimpleAuthAccess(scheme, token string) credentials.PerRPCCredentials {
return &unsecureSimpleAuthAccess{token: token, scheme: scheme}
}
// nolint:revive
func (sa *unsecureSimpleAuthAccess) GetRequestMetadata(_ context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
headerAuthorize: "bearer " + sa.token,
}, nil
}
func (unsecureSimpleAuthAccess) RequireTransportSecurity() bool {
return false
}
================================================
FILE: pkg/grpcutil/simple_auth_test.go
================================================
package grpcutil
import (
"context"
"net"
"testing"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"google.golang.org/grpc/status"
)
const testGoodToken = "hellobuddy"
func validateToken(token string) bool {
return token == testGoodToken
}
// testAuthFunc is used by a middleware to authenticate requests
func testAuthFunc(ctx context.Context) (context.Context, error) {
token, err := grpc_auth.AuthFromMD(ctx, "bearer")
if err != nil {
return nil, err
}
if !validateToken(token) {
return nil, status.Errorf(codes.Unauthenticated, "invalid auth token: %s", token)
}
tags := grpc_ctxtags.Extract(ctx).Set("auth.secret", token)
newCtx := grpc_ctxtags.SetInContext(ctx, tags)
return newCtx, nil
}
func SayHelloAuthenticated(ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "pong authenticated"}, nil
}
func TestSimpleAuth(t *testing.T) {
cases := []struct {
name string
token string
assertFunc assert.ErrorAssertionFunc
}{
{name: "Authenticated", token: testGoodToken, assertFunc: assert.NoError},
{name: "Unauthenticated", token: "badtoken", assertFunc: assert.Error},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
grpcServer := grpc.NewServer(
grpc_middleware.WithUnaryServerChain(
grpc_auth.UnaryServerInterceptor(testAuthFunc),
),
grpc_middleware.WithStreamServerChain(
grpc_auth.StreamServerInterceptor(testAuthFunc),
),
)
pb.RegisterGreeterService(grpcServer, &pb.GreeterService{SayHello: SayHelloAuthenticated})
l, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
defer l.Close()
cc, err := grpc.DialContext(ctx, l.Addr().String(), []grpc.DialOption{
grpc.WithPerRPCCredentials(NewUnsecureSimpleAuthAccess("bearer", tc.token)),
grpc.WithInsecure(), // TODO: remove this, enforce security
}...)
require.NoError(t, err)
go grpcServer.Serve(l)
client := pb.NewGreeterClient(cc)
res, err := client.SayHello(ctx, &pb.HelloRequest{})
if tc.assertFunc(t, err) && err == nil {
assert.Equal(t, "pong authenticated", res.Message)
}
})
}
}
================================================
FILE: pkg/ipfsutil/collector_bandwidth.go
================================================
package ipfsutil
import (
metrics "github.com/libp2p/go-libp2p/core/metrics"
prometheus "github.com/prometheus/client_golang/prometheus"
)
var (
protocolsBandwidthInDesc = prometheus.NewDesc(
prometheus.BuildFQName("ipfs", "bandwidth", "in"),
"protocol bandwidth in",
[]string{"protocol_id"}, nil,
)
protocolsBandwidthOutDesc = prometheus.NewDesc(
prometheus.BuildFQName("ipfs", "bandwidth", "out"),
"protocol bandwidth out",
[]string{"protocol_id"}, nil,
)
)
// BandwidthCollector is a prometheus.Collector
var _ prometheus.Collector = (*BandwidthCollector)(nil)
type BandwidthCollector struct {
reporter *metrics.BandwidthCounter
}
func NewBandwidthCollector(reporter *metrics.BandwidthCounter) *BandwidthCollector {
return &BandwidthCollector{reporter}
}
func (bc *BandwidthCollector) Collect(cmetric chan<- prometheus.Metric) {
for p, s := range bc.reporter.GetBandwidthByProtocol() {
if p == "" {
continue
}
cmetric <- prometheus.MustNewConstMetric(
protocolsBandwidthInDesc,
prometheus.GaugeValue,
s.RateIn, string(p))
cmetric <- prometheus.MustNewConstMetric(
protocolsBandwidthOutDesc,
prometheus.GaugeValue,
s.RateOut, string(p))
}
}
func (bc *BandwidthCollector) Describe(ch chan<- *prometheus.Desc) {
prometheus.DescribeByCollect(bc, ch)
}
================================================
FILE: pkg/ipfsutil/collector_host.go
================================================
package ipfsutil
import (
host "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/protocol"
ma "github.com/multiformats/go-multiaddr"
prometheus "github.com/prometheus/client_golang/prometheus"
)
var (
protocolsStreamsSumDesc = prometheus.NewDesc(
prometheus.BuildFQName("ipfs", "host", "open_stream"),
"number of open stream for this protocol",
[]string{"protocol_id"}, nil,
)
connsSumOpts = prometheus.GaugeOpts{
Name: prometheus.BuildFQName("ipfs", "host", "open_connection"),
Help: "number of opened connections",
}
// protocolStreamDurationOpts = prometheus.HistogramOpts{
// Name: prometheus.BuildFQName("ipfs", "host", "stream_duration"),
// Help: "stream duration",
// Buckets: prometheus.LinearBuckets(0, 10, 6),
// }
)
const UnknownProtocol = "UnknownProtocol"
type HostCollector struct {
host host.Host
connsCollector prometheus.Gauge
// streamsCollector *prometheus.HistogramVec
}
func NewHostCollector(h host.Host) *HostCollector {
gconns := prometheus.NewGauge(connsSumOpts)
// hstreams := prometheus.NewHistogramVec(protocolStreamDurationOpts, []string{"protocol_id"})
cc := &HostCollector{
host: h,
connsCollector: gconns,
// streamsCollector: hstreams,
}
h.Network().Notify(cc)
return cc
}
func (cc *HostCollector) Collect(cmetric chan<- prometheus.Metric) {
cc.connsCollector.Collect(cmetric)
// cc.streamsCollector.Collect(cmetric)
streamsMap := make(map[protocol.ID]int)
for _, c := range cc.host.Network().Conns() {
for _, s := range c.GetStreams() {
if s.Protocol() != "" {
streamsMap[s.Protocol()]++
} else {
streamsMap[UnknownProtocol]++
}
}
}
for p, ns := range streamsMap {
cmetric <- prometheus.MustNewConstMetric(
protocolsStreamsSumDesc,
prometheus.GaugeValue,
float64(ns), string(p))
}
}
func (cc *HostCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- protocolsStreamsSumDesc
cc.connsCollector.Describe(ch)
// cc.streamsCollector.Describe(ch)
}
func (cc *HostCollector) Listen(network.Network, ma.Multiaddr) {}
func (cc *HostCollector) ListenClose(network.Network, ma.Multiaddr) {}
func (cc *HostCollector) Connected(network.Network, network.Conn) {
cc.connsCollector.Inc()
}
func (cc *HostCollector) Disconnected(network.Network, network.Conn) {
cc.connsCollector.Dec()
}
func (cc *HostCollector) OpenedStream(network.Network, network.Stream) {}
func (cc *HostCollector) ClosedStream(network.Network, network.Stream) {
// elpased := time.Since(s.Stat().Opened)
// cc.streamsCollector.WithLabelValues(string(s.Protocol())).Observe(elpased.Seconds())
}
================================================
FILE: pkg/ipfsutil/conn_logger.go
================================================
package ipfsutil
import (
"context"
"time"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
var ignoredTags = map[string]bool{
"kbucket": true,
"relay": true,
"relay-hop-stream": true,
}
type connLogger struct {
host host.Host
logger *zap.Logger
}
func EnableConnLogger(ctx context.Context, logger *zap.Logger, h host.Host) {
notifee := &connLogger{
host: h,
logger: logger.Named("conn_logger"),
}
h.Network().Notify(notifee)
go func() {
<-ctx.Done()
h.Network().StopNotify(notifee)
}()
}
func (cl *connLogger) getPeerTags(p peer.ID) []string {
if tagInfo := cl.host.ConnManager().GetTagInfo(p); tagInfo != nil {
var tags []string
for tag := range tagInfo.Tags {
if !ignoredTags[tag] {
tags = append(tags, tag)
}
}
if len(tags) > 0 {
return tags
}
}
return nil
}
func (cl *connLogger) Listen(_ network.Network, m ma.Multiaddr) {
cl.logger.Debug("Listener opened", logutil.PrivateString("Multiaddr", m.String()))
}
func (cl *connLogger) ListenClose(_ network.Network, m ma.Multiaddr) {
cl.logger.Debug("Listener closed", logutil.PrivateString("Multiaddr", m.String()))
}
func (cl *connLogger) Connected(_ network.Network, c network.Conn) {
// Wait 10 ms until the peer has been tagged by orbit-db
go func() {
<-time.After(10 * time.Millisecond)
if tags := cl.getPeerTags(c.RemotePeer()); tags != nil {
cl.logger.Info("Connected",
logutil.PrivateString("peer", c.RemotePeer().String()),
logutil.PrivateString("to", c.LocalMultiaddr().String()),
logutil.PrivateString("from", c.RemoteMultiaddr().String()),
logutil.PrivateStrings("tags", tags),
)
}
}()
}
func (cl *connLogger) Disconnected(_ network.Network, c network.Conn) {
if tags := cl.getPeerTags(c.RemotePeer()); tags != nil {
cl.logger.Info("Disconnected",
logutil.PrivateString("peer", c.RemotePeer().String()),
logutil.PrivateString("to", c.LocalMultiaddr().String()),
logutil.PrivateString("from", c.RemoteMultiaddr().String()),
logutil.PrivateStrings("tags", tags),
)
}
}
func (cl *connLogger) OpenedStream(_ network.Network, s network.Stream) {
if tags := cl.getPeerTags(s.Conn().RemotePeer()); tags != nil {
cl.logger.Debug("Stream opened",
logutil.PrivateString("peer", s.Conn().RemotePeer().String()),
logutil.PrivateString("to", s.Conn().LocalMultiaddr().String()),
logutil.PrivateString("from", s.Conn().RemoteMultiaddr().String()),
logutil.PrivateString("protocol", string(s.Protocol())),
logutil.PrivateStrings("tags", tags),
)
}
}
func (cl *connLogger) ClosedStream(_ network.Network, s network.Stream) {
if tags := cl.getPeerTags(s.Conn().RemotePeer()); tags != nil {
cl.logger.Debug("Stream closed",
logutil.PrivateString("peer", s.Conn().RemotePeer().String()),
logutil.PrivateString("to", s.Conn().LocalMultiaddr().String()),
logutil.PrivateString("from", s.Conn().RemoteMultiaddr().String()),
logutil.PrivateString("protocol", string(s.Protocol())),
logutil.PrivateStrings("tags", tags),
)
}
}
================================================
FILE: pkg/ipfsutil/conn_manager.go
================================================
package ipfsutil
import (
"fmt"
"sync"
"github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
)
type TypeTagAction int
const (
TypeTagActionTag TypeTagAction = iota
TypeTagActionUntag
TypeTagActionUpsert
)
type EvtPeerTag struct {
Kind TypeTagAction
Peer peer.ID
Tag string
Diff int
Total int
}
var _ connmgr.ConnManager = (*BertyConnManager)(nil)
// keep track of peer of interest
type BertyConnManager struct {
connmgr.ConnManager
logger *zap.Logger
tagEmitter event.Emitter
muMarked sync.RWMutex
marked map[peer.ID]int
}
func NewBertyConnManager(logger *zap.Logger, cm connmgr.ConnManager) *BertyConnManager {
return &BertyConnManager{
ConnManager: cm,
logger: logger,
marked: make(map[peer.ID]int),
}
}
func (c *BertyConnManager) RegisterEventBus(bus event.Bus) (err error) {
if c.tagEmitter == nil {
c.tagEmitter, err = bus.Emitter(new(EvtPeerTag))
} else {
err = fmt.Errorf("event emitter already registered")
}
return err
}
func (c *BertyConnManager) GetPeerScore(p peer.ID) (score int, exist bool) {
c.muMarked.RLock()
score, exist = c.marked[p]
c.muMarked.RUnlock()
return
}
// TagPeer tags a peer with a string, associating a weight with the tag.
func (c *BertyConnManager) TagPeer(p peer.ID, tag string, score int) {
c.ConnManager.TagPeer(p, tag, score)
old, total := c.computePeerScore(p)
if old != total && c.tagEmitter != nil {
evt := EvtPeerTag{
Kind: TypeTagActionTag,
Peer: p,
Tag: tag,
Diff: total - old,
Total: total,
}
if err := c.tagEmitter.Emit(evt); err != nil {
c.logger.Error("unable to emit tag event", zap.Error(err))
}
}
}
// Untag removes the tagged value from the peer.
func (c *BertyConnManager) UntagPeer(p peer.ID, tag string) {
c.ConnManager.UntagPeer(p, tag)
old, total := c.computePeerScore(p)
if old != total && c.tagEmitter != nil {
evt := EvtPeerTag{
Kind: TypeTagActionUntag,
Peer: p,
Tag: tag,
Diff: total - old,
Total: total,
}
if err := c.tagEmitter.Emit(evt); err != nil {
c.logger.Error("unable to emit tag event", zap.Error(err))
}
}
}
// UpsertTag updates an existing tag or inserts a new one.
// The connection manager calls the upsert function supplying the current
// value of the tag (or zero if inexistent). The return value is used as
// the new value of the tag.
func (c *BertyConnManager) UpsertTag(p peer.ID, tag string, upsert func(int) int) {
c.ConnManager.UpsertTag(p, tag, upsert)
old, total := c.computePeerScore(p)
if old != total && c.tagEmitter != nil {
evt := EvtPeerTag{
Kind: TypeTagActionUpsert,
Peer: p,
Tag: tag,
Diff: total - old,
Total: total,
}
if err := c.tagEmitter.Emit(evt); err != nil {
c.logger.Error("unable to emit tag event", zap.Error(err))
}
}
}
func (c *BertyConnManager) computePeerScore(p peer.ID) (old, newScore int) {
c.muMarked.Lock()
old = c.marked[p]
if info := c.ConnManager.GetTagInfo(p); info != nil {
if newScore = info.Value; newScore > 0 {
c.marked[p] = newScore
} else {
delete(c.marked, p)
}
}
c.muMarked.Unlock()
return
}
================================================
FILE: pkg/ipfsutil/consts.go
================================================
package ipfsutil
const (
// svc ams 1
DefaultP2PRdvpMaddr = "/ip4/51.15.25.224/udp/4040/quic-v1/p2p/12D3KooWHhDBv6DJJ4XDWjzEXq6sVNEs6VuxsV1WyBBEhPENHzcZ"
// svc ams 1
DefaultP2PStaticRelay = "/ip4/51.15.25.224/udp/6363/quic-v1/p2p/12D3KooWAHcEz4K5XAgRDav9fLuhiRY2wuXip385EmT5RoRkCmjr"
)
================================================
FILE: pkg/ipfsutil/doc.go
================================================
// Package ipfsutil contains helpers around IPFS (logging, datastore, networking, core API, ...).
package ipfsutil
================================================
FILE: pkg/ipfsutil/extended_core_api.go
================================================
package ipfsutil
import (
ipfs_core "github.com/ipfs/kubo/core"
ipfs_coreapi "github.com/ipfs/kubo/core/coreapi"
coreiface "github.com/ipfs/kubo/core/coreiface"
"github.com/libp2p/go-libp2p/core/connmgr"
ipfs_host "github.com/libp2p/go-libp2p/core/host"
)
type ConnMgr interface {
connmgr.ConnManager
}
type ExtendedCoreAPI interface {
coreiface.CoreAPI
ipfs_host.Host
ConnMgr() ConnMgr
}
type extendedCoreAPI struct {
coreiface.CoreAPI
ipfs_host.Host
}
func (e *extendedCoreAPI) ConnMgr() ConnMgr {
return e.Host.ConnManager()
}
func NewExtendedCoreAPI(host ipfs_host.Host, api coreiface.CoreAPI) ExtendedCoreAPI {
return &extendedCoreAPI{
CoreAPI: api,
Host: host,
}
}
func NewExtendedCoreAPIFromNode(node *ipfs_core.IpfsNode) (ExtendedCoreAPI, error) {
api, err := ipfs_coreapi.NewCoreAPI(node)
if err != nil {
return nil, err
}
return NewExtendedCoreAPI(node.PeerHost, api), nil
}
================================================
FILE: pkg/ipfsutil/helpers.go
================================================
package ipfsutil
import (
"context"
"errors"
"fmt"
"io"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
"go.uber.org/multierr"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
func ParseAndResolveIpfsAddr(ctx context.Context, addr string) (*peer.AddrInfo, error) {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
if !madns.Matches(maddr) {
return peer.AddrInfoFromP2pAddr(maddr)
}
addrs, err := madns.Resolve(ctx, maddr)
if err != nil {
return nil, err
}
if len(addrs) == 0 {
return nil, errors.New("fail to resolve the multiaddr:" + maddr.String())
}
var info peer.AddrInfo
for _, addr := range addrs {
taddr, id := peer.SplitAddr(addr)
if id == "" {
// not an ipfs addr, skipping.
continue
}
switch info.ID {
case "":
info.ID = id
case id:
default:
return nil, fmt.Errorf(
"ambiguous maddr %s could refer to %s or %s",
maddr,
info.ID,
id,
)
}
info.Addrs = append(info.Addrs, taddr)
}
return &info, nil
}
func ParseAndResolveMaddrs(ctx context.Context, logger *zap.Logger, addrs []string) ([]*peer.AddrInfo, error) {
// Resolve all addresses
outPeersUnmatched := make([]*peer.AddrInfo, len(addrs))
var (
errs error
outLock sync.Mutex
wg sync.WaitGroup
)
wg.Add(len(addrs))
for i, v := range addrs {
go func(j int, addr string) {
defer wg.Done()
rdvpeer, err := ParseAndResolveIpfsAddr(ctx, addr)
if err != nil {
outLock.Lock()
defer outLock.Unlock()
errs = multierr.Append(errs, err)
return
}
addrStrings := make([]string, len(rdvpeer.Addrs))
for i, maddr := range rdvpeer.Addrs {
addrStrings[i] = maddr.String()
}
logger.Debug("rdvp peer resolved addrs",
logutil.PrivateString("input", addr),
// logutil.PrivateString("ID", rdvpeer.ID.Pretty()),
logutil.PrivateStrings("addrs", addrStrings),
)
outPeersUnmatched[j] = rdvpeer
}(i, v)
}
wg.Wait()
if errs != nil {
return nil, errs
}
// Match peers by ID
outPeersMatched := make(map[peer.ID][]ma.Multiaddr)
for _, v := range outPeersUnmatched {
outPeersMatched[v.ID] = append(outPeersMatched[v.ID], v.Addrs...)
}
// Create the ultimate *peer.AddrInfo
var outPeers []*peer.AddrInfo
for id, maddrs := range outPeersMatched {
outPeers = append(outPeers, &peer.AddrInfo{
ID: id,
Addrs: maddrs,
})
}
return outPeers, nil
}
var ErrExpectedEOF = errors.New("red data when expecting EOF")
const DefaultCloseTimeout = time.Second * 5
func FullClose(s network.Stream) error {
// Start the close.
err := s.CloseWrite()
if err != nil {
return err
}
// We don't want to wait indefinitely
_ = s.SetDeadline(time.Now().Add(DefaultCloseTimeout))
// Trying with a long slice to fetch `n`.
n, err := s.Read([]byte{0})
if n > 0 || err == nil {
_ = s.Reset()
return ErrExpectedEOF
}
if err == io.EOF {
return nil
}
_ = s.Reset()
return err
}
================================================
FILE: pkg/ipfsutil/helpers_test.go
================================================
package ipfsutil
import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"
"io"
mrand "math/rand"
"testing"
"time"
p2p "github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/pnet"
tcp "github.com/libp2p/go-libp2p/p2p/transport/tcp"
"moul.io/srand"
)
const closeTestPid = "/testing/close/0.1.0"
// TestFullClose creates 2 hosts (a and b). a will dial b and will then try to close the connection using FullClose.
// b will play various scenario to check that it's working fine.
func TestFullClose(t *testing.T) {
// Creating ctx
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var a, b host.Host
{
// Creating a private network
seed, err := srand.Secure()
if err != nil {
t.Fatalf("failed to fetch secure source: %s", err)
}
prov := mrand.New(mrand.NewSource(seed))
pskKey := make([]byte, 32)
// math/rand#Rand.Read can't ever fail nor return an n != len(buf)
_, _ = prov.Read(pskKey)
// Generating PSK key, pulled from https://github.com/Kubuxu/go-ipfs-swarm-key-gen/blob/0ee739ec6d322bc1892999882e4738270e97b181/ipfs-swarm-key-gen/main.go#L15-L17
psk, err := pnet.DecodeV1PSK(bytes.NewReader([]byte("/key/swarm/psk/1.0.0/\n/base16/\n" + hex.EncodeToString(pskKey))))
if err != nil {
t.Fatalf("failed to create PSK: %s", err)
}
// Creating the hosts
priv, _, err := crypto.GenerateEd25519Key(prov)
if err != nil {
t.Fatalf("failed to generate A's private key: %s", err)
}
a, err = p2p.New(p2p.DisableRelay(),
p2p.Transport(tcp.NewTCPTransport),
p2p.Identity(priv),
p2p.PrivateNetwork(psk),
p2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"),
)
if err != nil {
t.Fatalf("failed to create host A: %s", err)
}
priv, _, err = crypto.GenerateEd25519Key(prov)
if err != nil {
t.Fatalf("failed to generate B's private key: %s", err)
}
b, err = p2p.New(p2p.DisableRelay(),
p2p.Transport(tcp.NewTCPTransport),
p2p.Identity(priv),
p2p.PrivateNetwork(psk),
p2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"),
)
if err != nil {
t.Fatalf("failed to create host B: %s", err)
}
}
// Adding the hosts together
a.Peerstore().SetAddrs(b.ID(), b.Addrs(), peerstore.PermanentAddrTTL)
b.Peerstore().SetAddrs(a.ID(), a.Addrs(), peerstore.PermanentAddrTTL)
// First scenario, regular close
{
errcb := make(chan error)
b.SetStreamHandler(closeTestPid, func(s network.Stream) {
n, err := s.Read([]byte{0}) // Trying to read, should io.EOF
if n == 0 && err == io.EOF { // Good
err = s.Close() // Trying to close ourself
if err == nil {
errcb <- io.EOF // Perfect
return
}
errcb <- fmt.Errorf("error closing after EOF: %w", err)
return
}
if err != nil {
errcb <- fmt.Errorf("error not EOF while reading: %w", err)
return
}
// n > 0
errcb <- errors.New("n > 0, expected EOF")
})
errca := make(chan error)
// Dialing, we expect a fast close.
go func() {
s, err := a.NewStream(ctx, b.ID(), closeTestPid)
if err != nil {
errca <- fmt.Errorf("failed to create stream: %w", err)
return
}
errca <- FullClose(s)
}()
timec := time.After(DefaultCloseTimeout / 2) // Fast close must resolve in max half of the timeout time.
var done uint = 2
for done > 0 {
select {
case err := <-errca:
if err == nil || err == io.EOF {
done--
continue
}
t.Fatalf("error for A while fast close: %s", err)
case err := <-errcb:
if err == nil || err == io.EOF {
done--
continue
}
t.Fatalf("error for B while fast close: %s", err)
case <-timec:
t.Fatal("fast close took too long.")
}
}
}
// Second scenario, regular timeout
{
errcb := make(chan error)
var gs network.Stream // Prevent running the terminator
b.SetStreamHandler(closeTestPid, func(s network.Stream) {
gs = s // Thread unsafe if we have concurrent streams incoming, shouldn't happen thx to the pnet.
_, err := s.Read([]byte{0})
errcb <- err
})
errca := make(chan error)
// Dialing, we expect a timeout.
go func() {
s, err := a.NewStream(ctx, b.ID(), closeTestPid)
if err != nil {
errca <- fmt.Errorf("failed to create stream: %w", err)
return
}
errca <- FullClose(s)
}()
timec := time.After(DefaultCloseTimeout + time.Second) // Timeout must resolve in timeout time + 1s.
var done uint = 2
for done > 0 {
select {
case err := <-errca:
// i/o deadline reached must be checked msg.
if err == nil || err.Error() == "i/o deadline reached" {
done--
continue
}
t.Fatalf("error for A while slow close: %s", err)
case err := <-errcb:
if err == nil || err == io.EOF {
done--
continue
}
t.Fatalf("error for B while slow close: %s", err)
case <-timec:
t.Fatal("slow close took too long.")
}
}
_ = gs // Prevent running the GC Terminator.
}
}
================================================
FILE: pkg/ipfsutil/keystore_datastore.go
================================================
package ipfsutil
import (
"context"
datastore "github.com/ipfs/go-datastore"
keystore "github.com/ipfs/go-ipfs-keystore"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/errcode"
)
type datastoreKeystore struct {
ds datastore.Datastore
}
func (k *datastoreKeystore) Has(name string) (bool, error) {
return k.ds.Has(context.TODO(), datastore.NewKey(name))
}
func (k *datastoreKeystore) Put(name string, key crypto.PrivKey) error {
bytes, err := crypto.MarshalPrivateKey(key)
if err != nil {
return err
}
return k.ds.Put(context.TODO(), datastore.NewKey(name), bytes)
}
func (k *datastoreKeystore) Get(name string) (crypto.PrivKey, error) {
bytes, err := k.ds.Get(context.TODO(), datastore.NewKey(name))
if err == datastore.ErrNotFound {
return nil, keystore.ErrNoSuchKey
} else if err != nil {
return nil, err
}
return crypto.UnmarshalPrivateKey(bytes)
}
func (k *datastoreKeystore) Delete(name string) error {
return k.ds.Delete(context.TODO(), datastore.NewKey(name))
}
func (k *datastoreKeystore) List() ([]string, error) {
return nil, errcode.ErrCode_ErrNotImplemented
}
func NewDatastoreKeystore(ds datastore.Datastore) keystore.Keystore {
return &datastoreKeystore{
ds: ds,
}
}
================================================
FILE: pkg/ipfsutil/lifecycle.go
================================================
package ipfsutil
import (
"context"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/libp2p/go-libp2p/core/connmgr"
host "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/lifecycle"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/netmanager"
)
var (
ConnLifecycleGracePeriod = time.Second
ConnLifecyclePingTimeout = time.Second * 5
ConnPeerOfInterestMinScore = 20
)
type ConnLifecycle struct {
connmgr.ConnManager
rootCtx context.Context
logger *zap.Logger
peering *PeeringService
ps *ping.PingService
h host.Host
lm *lifecycle.Manager
}
func NewConnLifecycle(ctx context.Context, logger *zap.Logger, h host.Host, ps *PeeringService, lm *lifecycle.Manager, net *netmanager.NetManager) (*ConnLifecycle, error) {
cl := &ConnLifecycle{
peering: ps,
rootCtx: ctx,
logger: logger,
ps: ping.NewPingService(h),
h: h,
lm: lm,
}
// start peer of interest monitoring process
if err := cl.monitorPeerOfInterest(ctx); err != nil {
return nil, err
}
// start app state monitoring process
go cl.monitorAppState(ctx)
cl.logger.Debug("lifecycle conn started")
go func() {
currentState := net.GetCurrentState()
for {
ok, _ := net.WaitForStateChange(ctx, ¤tState, netmanager.ConnectivityStateChanged)
if !ok {
return
}
currentState = net.GetCurrentState()
if net.GetCurrentState().State == netmanager.ConnectivityStateOn {
go cl.dropUnavailableConn()
}
}
}()
return cl, nil
}
func (cl *ConnLifecycle) monitorAppState(ctx context.Context) {
currentState := lifecycle.StateActive
for {
start := time.Now()
if !cl.lm.WaitForStateChange(ctx, currentState) {
return
}
currentState = cl.lm.GetCurrentState()
if time.Since(start) <= ConnLifecycleGracePeriod {
continue
}
switch currentState {
case lifecycle.StateInactive:
cl.logger.Debug("inactive mode")
case lifecycle.StateActive:
cl.logger.Debug("active mode")
go cl.dropUnavailableConn()
}
}
}
func (cl *ConnLifecycle) dropUnavailableConn() {
cl.logger.Debug("dropping unavailable conn")
peers := make(map[peer.ID]struct{})
for _, c := range cl.h.Network().Conns() {
if _, ok := peers[c.RemotePeer()]; !ok {
peers[c.RemotePeer()] = struct{}{}
}
}
unavailable := uint32(0)
wg := sync.WaitGroup{}
ctx, cancel := context.WithCancel(cl.rootCtx)
for p := range peers {
cping := cl.ps.Ping(ctx, p)
wg.Add(1)
go func(peer peer.ID) {
defer wg.Done()
select {
case ret := <-cping:
if ret.Error == nil {
return // everything should be ok
}
case <-time.After(ConnLifecyclePingTimeout):
}
// connection should be dead
atomic.AddUint32(&unavailable, 1)
// if we are here, conn should be kill
if err := cl.h.Network().ClosePeer(peer); err != nil {
cl.logger.Warn("unable to close connection", zap.Error(err))
}
}(p)
}
wg.Wait()
cancel()
if unavailable > 0 {
available := uint32(len(peers)) - unavailable
cl.logger.Debug("dropped unavailable peers", zap.Uint32("available", available), zap.Uint32("unavailable", unavailable))
} else {
cl.logger.Debug("all peers are available")
}
}
func (cl *ConnLifecycle) monitorPeerOfInterest(ctx context.Context) error {
sub, err := cl.h.EventBus().Subscribe([]any{
new(EvtPeerTag),
}, eventbus.Name("weshnet/lifecycle/monitor-peer-of-interest"))
if err != nil {
return fmt.Errorf("unable to subscribe to `EvtPeerConnectednessChanged`: %w", err)
}
for _, p := range cl.h.Peerstore().Peers() {
if tag := cl.h.ConnManager().GetTagInfo(p); tag != nil && tag.Value >= ConnPeerOfInterestMinScore {
infos := cl.h.Peerstore().PeerInfo(p)
cl.peering.AddPeer(infos)
cl.logger.Debug("adding peer of interest", logutil.PrivateStringer("peer", p), zap.Int("score", tag.Value))
}
}
go func() {
defer sub.Close()
for {
var e any
select {
case e = <-sub.Out():
case <-ctx.Done():
return
}
evt := e.(EvtPeerTag)
oldTotal := evt.Total - evt.Diff
if evt.Total >= ConnPeerOfInterestMinScore && oldTotal < ConnPeerOfInterestMinScore {
infos := cl.h.Peerstore().PeerInfo(evt.Peer)
cl.peering.AddPeer(infos)
cl.logger.Debug("marking peer as peer of interest",
logutil.PrivateStringer("peer", evt.Peer), zap.Int("score", evt.Total), zap.Int("diff", evt.Diff), zap.String("last_tag", evt.Tag))
} else if evt.Total < ConnPeerOfInterestMinScore && oldTotal >= ConnPeerOfInterestMinScore {
cl.peering.RemovePeer(evt.Peer)
cl.logger.Debug("unmarking peer as peer of interest",
logutil.PrivateStringer("peer", evt.Peer), zap.Int("score", evt.Total), zap.Int("diff", evt.Diff), zap.String("last_tag", evt.Tag))
}
}
}()
return nil
}
================================================
FILE: pkg/ipfsutil/localrecord.go
================================================
package ipfsutil
import (
"context"
"os"
ipfs_core "github.com/ipfs/kubo/core"
coreiface "github.com/ipfs/kubo/core/coreiface"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/protocol"
ma "github.com/multiformats/go-multiaddr"
mafmt "github.com/multiformats/go-multiaddr-fmt"
manet "github.com/multiformats/go-multiaddr/net"
mc "berty.tech/weshnet/v2/pkg/multipeer-connectivity-driver"
)
const recProtocolID = protocol.ID("wesh/p2p/localrecord")
type LocalRecord struct {
host host.Host
}
// OptionLocalRecord is given to CoreAPIOption.Options when the ipfs node setup
func OptionLocalRecord(node *ipfs_core.IpfsNode, _ coreiface.CoreAPI) error {
lr := &LocalRecord{
host: node.PeerHost,
}
lr.host.Network().Notify(lr)
lr.host.SetStreamHandler(recProtocolID, lr.handleLocalRecords)
return nil
}
// called when network starts listening on an addr
func (lr *LocalRecord) Listen(network.Network, ma.Multiaddr) {}
// called when network stops listening on an addr
func (lr *LocalRecord) ListenClose(network.Network, ma.Multiaddr) {}
// called when a connection opened
func (lr *LocalRecord) Connected(_ network.Network, c network.Conn) {
ctx := context.Background() // FIXME: since go-libp2p-core@0.8.0 adds support for passed context on new call, we should think if we have a better context to pass here
go func() {
if manet.IsPrivateAddr(c.RemoteMultiaddr()) || mafmt.Base(mc.ProtocolCode).Matches(c.RemoteMultiaddr()) {
if err := lr.sendLocalRecord(ctx, c); err != nil {
return
}
}
}()
}
// called when a connection closed
func (lr *LocalRecord) Disconnected(network.Network, network.Conn) {}
// called when a stream opened
func (lr *LocalRecord) OpenedStream(network.Network, network.Stream) {}
// called when a stream closed
func (lr *LocalRecord) ClosedStream(network.Network, network.Stream) {}
func (lr *LocalRecord) sendLocalRecord(ctx context.Context, c network.Conn) error {
s, err := c.NewStream(ctx)
if err != nil {
return err
}
return s.SetProtocol(recProtocolID)
}
func (lr *LocalRecord) handleLocalRecords(network.Stream) {
os.Stderr.WriteString("handleLocalRecords")
}
================================================
FILE: pkg/ipfsutil/metrics.go
================================================
package ipfsutil
================================================
FILE: pkg/ipfsutil/mobile/host.go
================================================
package node
import (
"fmt"
ipfs_p2p "github.com/ipfs/kubo/core/node/libp2p"
p2p "github.com/libp2p/go-libp2p"
p2p_host "github.com/libp2p/go-libp2p/core/host"
p2p_peer "github.com/libp2p/go-libp2p/core/peer"
p2p_pstore "github.com/libp2p/go-libp2p/core/peerstore"
)
// HostMobile is a p2p_host.Host
var _ p2p_host.Host = (*HostMobile)(nil)
type HostConfigFunc func(p2p_host.Host) error
// @TODO: add custom mobile option here
type HostConfig struct {
// called after host init
ConfigFunc HostConfigFunc
// p2p options
Options []p2p.Option
}
func ChainHostConfig(cfgs ...HostConfigFunc) HostConfigFunc {
return func(host p2p_host.Host) (err error) {
for _, cfg := range cfgs {
if cfg == nil {
continue // skip empty config
}
if err = cfg(host); err != nil {
return
}
}
return
}
}
type HostMobile struct {
p2p_host.Host
}
func NewHostConfigOption(hopt ipfs_p2p.HostOption, cfg *HostConfig) ipfs_p2p.HostOption {
return func(id p2p_peer.ID, ps p2p_pstore.Peerstore, options ...p2p.Option) (p2p_host.Host, error) {
// add p2p custom options
if cfg.Options != nil {
options = append(options, cfg.Options...)
}
host, err := hopt(id, ps, options...)
if err != nil {
return nil, err
}
if cfg.ConfigFunc != nil {
// apply host custom config
if err := cfg.ConfigFunc(host); err != nil {
return nil, fmt.Errorf("unable to apply host config: %w", err)
}
}
return host, nil
}
}
================================================
FILE: pkg/ipfsutil/mobile/node.go
================================================
package node
import (
"context"
"fmt"
"net"
"os"
ipfs_oldcmds "github.com/ipfs/kubo/commands"
ipfs_core "github.com/ipfs/kubo/core"
ipfs_corehttp "github.com/ipfs/kubo/core/corehttp"
ipfs_p2p "github.com/ipfs/kubo/core/node/libp2p"
p2p_host "github.com/libp2p/go-libp2p/core/host"
)
type IpfsConfig struct {
HostConfig *HostConfig
HostOption ipfs_p2p.HostOption
RoutingConfig *RoutingConfig
RoutingOption ipfs_p2p.RoutingOption
RepoMobile *RepoMobile
ExtraOpts map[string]bool
}
func (c *IpfsConfig) fillDefault() error {
if c.RepoMobile == nil {
return fmt.Errorf("repo cannot be nil")
}
if c.ExtraOpts == nil {
c.ExtraOpts = make(map[string]bool)
}
if c.RoutingOption == nil {
c.RoutingOption = ipfs_p2p.DHTOption
}
if c.RoutingConfig == nil {
c.RoutingConfig = &RoutingConfig{}
}
if c.HostOption == nil {
c.HostOption = ipfs_p2p.DefaultHostOption
}
if c.HostConfig == nil {
c.HostConfig = &HostConfig{}
}
return nil
}
type IpfsMobile struct {
*ipfs_core.IpfsNode
Repo *RepoMobile
commandCtx ipfs_oldcmds.Context
}
func (im *IpfsMobile) PeerHost() p2p_host.Host {
return im.IpfsNode.PeerHost
}
func (im *IpfsMobile) Close() error {
return im.IpfsNode.Close()
}
func (im *IpfsMobile) ServeCoreHTTP(l net.Listener, opts ...ipfs_corehttp.ServeOption) error {
gatewayOpt := ipfs_corehttp.GatewayOption(ipfs_corehttp.WebUIPaths...)
opts = append(opts,
ipfs_corehttp.WebUIOption,
gatewayOpt,
ipfs_corehttp.CommandsOption(im.commandCtx),
)
return ipfs_corehttp.Serve(im.IpfsNode, l, opts...)
}
func (im *IpfsMobile) ServeGateway(l net.Listener, opts ...ipfs_corehttp.ServeOption) error {
opts = append(opts,
ipfs_corehttp.HostnameOption(),
ipfs_corehttp.GatewayOption("/ipfs", "/ipns"),
ipfs_corehttp.VersionOption(),
ipfs_corehttp.CheckVersionOption(),
ipfs_corehttp.CommandsOption(im.commandCtx),
)
return ipfs_corehttp.Serve(im.IpfsNode, l, opts...)
}
func NewNode(ctx context.Context, cfg *IpfsConfig) (*IpfsMobile, error) {
if err := cfg.fillDefault(); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}
// build config
buildcfg := &ipfs_core.BuildCfg{
Online: true,
Permanent: false,
DisableEncryptedConnections: false,
Repo: cfg.RepoMobile,
Host: NewHostConfigOption(cfg.HostOption, cfg.HostConfig),
Routing: NewRoutingConfigOption(cfg.RoutingOption, cfg.RoutingConfig),
ExtraOpts: cfg.ExtraOpts,
}
os.Setenv("IPFS_PATH", cfg.RepoMobile.Path)
// create ipfs node
inode, err := ipfs_core.NewNode(ctx, buildcfg)
if err != nil {
// unlockRepo(repoPath)
return nil, fmt.Errorf("failed to init ipfs node: %s", err)
}
// @TODO: no sure about how to init this, must be another way
cctx := ipfs_oldcmds.Context{
ConfigRoot: cfg.RepoMobile.Path,
ReqLog: &ipfs_oldcmds.ReqLog{},
ConstructNode: func() (*ipfs_core.IpfsNode, error) {
return inode, nil
},
}
return &IpfsMobile{
commandCtx: cctx,
IpfsNode: inode,
Repo: cfg.RepoMobile,
}, nil
}
================================================
FILE: pkg/ipfsutil/mobile/repo.go
================================================
package node
import (
ipfs_config "github.com/ipfs/kubo/config"
ipfs_repo "github.com/ipfs/kubo/repo"
)
var _ ipfs_repo.Repo = (*RepoMobile)(nil)
type RepoConfigPatch func(cfg *ipfs_config.Config) (err error)
type RepoMobile struct {
ipfs_repo.Repo
Path string
}
func NewRepoMobile(path string, repo ipfs_repo.Repo) *RepoMobile {
return &RepoMobile{
Repo: repo,
Path: path,
}
}
func (mr *RepoMobile) ApplyPatchs(patchs ...RepoConfigPatch) error {
cfg, err := mr.Config()
if err != nil {
return err
}
if err := ChainIpfsConfigPatch(patchs...)(cfg); err != nil {
return err
}
return mr.SetConfig(cfg)
}
func ChainIpfsConfigPatch(patchs ...RepoConfigPatch) RepoConfigPatch {
return func(cfg *ipfs_config.Config) (err error) {
for _, patch := range patchs {
if patch == nil {
continue // skip empty patch
}
if err = patch(cfg); err != nil {
return
}
}
return
}
}
================================================
FILE: pkg/ipfsutil/mobile/routing.go
================================================
package node
import (
"fmt"
ipfs_p2p "github.com/ipfs/kubo/core/node/libp2p"
p2p_host "github.com/libp2p/go-libp2p/core/host"
p2p_routing "github.com/libp2p/go-libp2p/core/routing"
)
type RoutingConfigFunc func(p2p_host.Host, p2p_routing.Routing) error
type RoutingConfig struct {
ConfigFunc RoutingConfigFunc
}
func NewRoutingConfigOption(ro ipfs_p2p.RoutingOption, rc *RoutingConfig) ipfs_p2p.RoutingOption {
return func(args ipfs_p2p.RoutingOptionArgs) (p2p_routing.Routing, error) {
routing, err := ro(args)
if err != nil {
return nil, err
}
if rc.ConfigFunc != nil {
if err := rc.ConfigFunc(args.Host, routing); err != nil {
return nil, fmt.Errorf("failed to config routing: %w", err)
}
}
return routing, nil
}
}
================================================
FILE: pkg/ipfsutil/mobile.go
================================================
package ipfsutil
import (
"context"
"fmt"
ipfs_config "github.com/ipfs/kubo/config"
ipfs_p2p "github.com/ipfs/kubo/core/node/libp2p"
p2p "github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p-kad-dht/dual"
host "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
p2p_routing "github.com/libp2p/go-libp2p/core/routing"
quict "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
tcpt "github.com/libp2p/go-libp2p/p2p/transport/tcp"
"go.uber.org/zap"
ipfs_mobile "berty.tech/weshnet/v2/pkg/ipfsutil/mobile"
)
type DHTNetworkMode int
const (
DHTNetworkLan DHTNetworkMode = iota
DHTNetworkWan
DHTNetworkDual
)
type Config func(cfg *ipfs_config.Config) ([]p2p.Option, error)
type MobileOptions struct {
Logger *zap.Logger
IpfsConfigPatch Config
// P2PStaticRelays and PeerStorePeers are only used if IpfsConfigPatch is nil
P2PStaticRelays []string
PeerStorePeers []string
HostOption ipfs_p2p.HostOption
RoutingOption ipfs_p2p.RoutingOption
HostConfigFunc ipfs_mobile.HostConfigFunc
RoutingConfigFunc ipfs_mobile.RoutingConfigFunc
ExtraOpts map[string]bool
}
func (o *MobileOptions) fillDefault() {
if o.Logger == nil {
o.Logger = zap.NewNop()
}
if o.HostOption == nil {
o.HostOption = ipfs_p2p.DefaultHostOption
}
if o.RoutingOption == nil {
o.RoutingOption = CustomRoutingOption(dht.ModeClient, DHTNetworkDual, dht.Concurrency(2))
}
if o.IpfsConfigPatch == nil {
o.IpfsConfigPatch = o.defaultIpfsConfigPatch
// P2PStaticRelays and PeerStorePeers are only used by defaultIpfsConfigPatch
if o.P2PStaticRelays == nil {
o.P2PStaticRelays = []string{DefaultP2PStaticRelay}
}
if o.PeerStorePeers == nil {
o.PeerStorePeers = []string{DefaultP2PRdvpMaddr}
}
}
// apply default extras
if o.ExtraOpts == nil {
o.ExtraOpts = make(map[string]bool)
}
// if not set, disable pubsub by default to avoid collision
if _, ok := o.ExtraOpts["pubsub"]; !ok {
o.ExtraOpts["pubsub"] = false
}
}
func NewIPFSMobile(ctx context.Context, repo *ipfs_mobile.RepoMobile, opts *MobileOptions) (*ipfs_mobile.IpfsMobile, error) {
opts.fillDefault()
var p2popts []p2p.Option
err := repo.ApplyPatchs(func(cfg *ipfs_config.Config) error {
var err error
if p2popts, err = opts.IpfsConfigPatch(cfg); err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
// check that p2p opt is set
if p2popts == nil {
return nil, fmt.Errorf("unable p2p option: cannot be nil")
}
// configure host
hostconfig := &ipfs_mobile.HostConfig{
// called after host init
ConfigFunc: opts.HostConfigFunc,
// p2p options
Options: p2popts,
}
// configure routing
routingconfig := &ipfs_mobile.RoutingConfig{
// called after host init
ConfigFunc: opts.RoutingConfigFunc,
}
// configure ipfs mobile
ipfsconfig := ipfs_mobile.IpfsConfig{
HostConfig: hostconfig,
RoutingConfig: routingconfig,
RepoMobile: repo,
ExtraOpts: opts.ExtraOpts,
HostOption: opts.HostOption,
RoutingOption: opts.RoutingOption,
}
return ipfs_mobile.NewNode(ctx, &ipfsconfig)
}
func CustomRoutingOption(mode dht.ModeOpt, net DHTNetworkMode, opts ...dht.Option) func(args ipfs_p2p.RoutingOptionArgs) (p2p_routing.Routing, error) {
return func(args ipfs_p2p.RoutingOptionArgs) (p2p_routing.Routing, error) {
opts = append(opts,
dht.Mode(mode),
dht.Datastore(args.Datastore),
dht.Validator(args.Validator),
dht.BootstrapPeers(args.BootstrapPeers...),
)
return newDualDHT(args.Ctx, args.Host, net, opts...)
}
}
func (o *MobileOptions) defaultIpfsConfigPatch(cfg *ipfs_config.Config) ([]p2p.Option, error) {
// Imitate berty setupIPFSConfig
// https://github.com/berty/berty/blob/5a8b9cb8524c1287ab2533a9e186ac8bde7f2b57/go/internal/initutil/ipfs.go#L474C19-L474C34
p2popts := []p2p.Option{}
// make sure relay is enabled
cfg.Swarm.RelayClient.Enabled = ipfs_config.True
cfg.Swarm.Transports.Network.Relay = ipfs_config.True
// add static relay
pis, err := ParseAndResolveMaddrs(context.TODO(), o.Logger, o.P2PStaticRelays)
if err != nil {
return nil, err
}
if len(pis) > 0 {
peers := make([]peer.AddrInfo, len(pis))
for i, p := range pis {
peers[i] = *p
}
p2popts = append(p2popts, p2p.EnableAutoRelayWithStaticRelays(peers))
}
// prefill peerstore with known rdvp servers
peers, err := ParseAndResolveMaddrs(context.TODO(), o.Logger, o.PeerStorePeers)
if err != nil {
return nil, err
}
for _, p := range peers {
cfg.Peering.Peers = append(cfg.Peering.Peers, *p)
}
// @NOTE(gfanton): disable quic transport so we can init a custom transport
// with reusport disabled
cfg.Swarm.Transports.Network.QUIC = ipfs_config.False
p2popts = append(p2popts, p2p.Transport(quict.NewTransport), p2p.QUICReuse(quicreuse.NewConnManager, quicreuse.DisableReuseport()))
// @NOTE(gfanton): disable tcp transport so we can init a custom transport
// with reusport disabled
cfg.Swarm.Transports.Network.TCP = ipfs_config.False
p2popts = append(p2popts, p2p.Transport(tcpt.NewTCPTransport,
tcpt.DisableReuseport(),
))
return p2popts, nil
}
const (
// from dual package dht
maxPrefixCountPerCpl = 2
maxPrefixCount = 3
)
func newDualDHT(ctx context.Context, h host.Host, net DHTNetworkMode, options ...dht.Option) (p2p_routing.Routing, error) {
switch net {
case DHTNetworkWan:
options = append(options,
dht.QueryFilter(dht.PublicQueryFilter),
dht.RoutingTableFilter(dht.PublicRoutingTableFilter),
dht.RoutingTablePeerDiversityFilter(dht.NewRTPeerDiversityFilter(h, maxPrefixCountPerCpl, maxPrefixCount)),
)
return dht.New(ctx, h, options...)
case DHTNetworkLan:
options = append(options,
dht.ProtocolExtension(dual.LanExtension),
dht.QueryFilter(dht.PrivateQueryFilter),
dht.RoutingTableFilter(dht.PrivateRoutingTableFilter),
)
return dht.New(ctx, h, options...)
default: // dual
return dual.New(ctx, h, dual.DHTOption(options...))
}
}
================================================
FILE: pkg/ipfsutil/peering.go
================================================
// mostly from: https://github.com/ipfs/kubo/blob/master/peering/peering.go
package ipfsutil
import (
"context"
"errors"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
backoff "github.com/libp2p/go-libp2p/p2p/discovery/backoff"
"github.com/multiformats/go-multiaddr"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
// Seed the random number generator.
//
// We don't need good randomness, but we do need randomness.
const (
connmgrTag = "berty-peering"
// MaximumReconnectingDelay define the maximum time a peer is able to
// reconnect, if reached peer will be remove from the store
MaximumReconnectingDelay = time.Second * 30
)
type state int
const (
stateInit state = iota
stateRunning
stateStopped
)
// PeeringService maintains connections to specified peers, reconnecting on
// disconnect with a back-off.
type PeeringService struct {
host host.Host
logger *zap.Logger
backoffFactory backoff.BackoffFactory
muPeers sync.RWMutex
peers map[peer.ID]*peerHandler
state state
}
// NewPeeringService constructs a new peering service. Peers can be added and
// removed immediately, but connections won't be formed until `Start` is called.
func NewPeeringService(logger *zap.Logger, host host.Host, fact backoff.BackoffFactory) *PeeringService {
return &PeeringService{
backoffFactory: fact,
logger: logger,
host: host,
peers: make(map[peer.ID]*peerHandler),
}
}
// Start starts the peering service, connecting and maintaining connections to
// all registered peers. It returns an error if the service has already been
// stopped.
func (ps *PeeringService) Start() error {
ps.muPeers.Lock()
defer ps.muPeers.Unlock()
switch ps.state {
case stateInit:
ps.logger.Info("starting peering service")
case stateRunning:
return nil
case stateStopped:
return errors.New("peering service already stopped")
}
ps.host.Network().Notify((*netNotifee)(ps))
ps.state = stateRunning
for _, handler := range ps.peers {
go handler.startIfDisconnected()
}
return nil
}
// Stop stops the peering service.
func (ps *PeeringService) Stop() error {
ps.host.Network().StopNotify((*netNotifee)(ps))
ps.muPeers.Lock()
defer ps.muPeers.Unlock()
switch ps.state {
case stateInit, stateRunning:
ps.logger.Info("stopping peering service")
for _, handler := range ps.peers {
handler.stop()
}
ps.state = stateStopped
}
return nil
}
// AddPeer adds a peer to the peering service. This function may be safely
// called at any time: before the service is started, while running, or after it
// stops.
//
// Add peer may also be called multiple times for the same peer. The new
// addresses will replace the old.
func (ps *PeeringService) AddPeer(info peer.AddrInfo) {
ps.muPeers.Lock()
handler, ok := ps.peers[info.ID]
ps.muPeers.Unlock()
if ok {
ps.logger.Info("updating addresses", logutil.PrivateStringer("peer", info.ID), zap.Any("addrs", info.Addrs))
handler.setAddrs(info.Addrs)
} else {
ps.logger.Info("peer added", logutil.PrivateStringer("peer", info.ID), zap.Any("addrs", info.Addrs))
ps.host.ConnManager().Protect(info.ID, connmgrTag)
handler = &peerHandler{
logger: ps.logger,
host: ps.host,
peer: info.ID,
addrs: info.Addrs,
backoffStrat: ps.backoffFactory(),
}
handler.ctx, handler.cancel = context.WithCancel(context.Background())
ps.peers[info.ID] = handler
switch ps.state {
case stateRunning:
go handler.startIfDisconnected()
case stateStopped:
// We still construct everything in this state because
// it's easier to reason about. But we should still free
// resources.
handler.cancel()
}
}
}
// ListPeers lists peers in the peering service.
func (ps *PeeringService) ListPeers() []peer.AddrInfo {
ps.muPeers.RLock()
defer ps.muPeers.RUnlock()
out := make([]peer.AddrInfo, 0, len(ps.peers))
for id, addrs := range ps.peers {
ai := peer.AddrInfo{ID: id}
ai.Addrs = append(ai.Addrs, addrs.addrs...)
out = append(out, ai)
}
return out
}
// RemovePeer removes a peer from the peering service. This function may be
// safely called at any time: before the service is started, while running, or
// after it stops.
func (ps *PeeringService) RemovePeer(id peer.ID) {
ps.muPeers.Lock()
defer ps.muPeers.Unlock()
if handler, ok := ps.peers[id]; ok {
ps.logger.Info("peer removed", logutil.PrivateStringer("peer", id))
ps.host.ConnManager().Unprotect(id, connmgrTag)
handler.stop()
delete(ps.peers, id)
}
}
type netNotifee PeeringService
func (nn *netNotifee) Connected(_ network.Network, c network.Conn) {
ps := (*PeeringService)(nn)
p := c.RemotePeer()
ps.muPeers.RLock()
defer ps.muPeers.RUnlock()
if handler, ok := ps.peers[p]; ok {
// use a goroutine to avoid blocking events.
go handler.stopIfConnected()
}
}
func (nn *netNotifee) Disconnected(_ network.Network, c network.Conn) {
ps := (*PeeringService)(nn)
p := c.RemotePeer()
ps.muPeers.RLock()
defer ps.muPeers.RUnlock()
if handler, ok := ps.peers[p]; ok {
// use a goroutine to avoid blocking events.
go handler.startIfDisconnected()
}
}
func (nn *netNotifee) OpenedStream(network.Network, network.Stream) {}
func (nn *netNotifee) ClosedStream(network.Network, network.Stream) {}
func (nn *netNotifee) Listen(network.Network, multiaddr.Multiaddr) {}
func (nn *netNotifee) ListenClose(network.Network, multiaddr.Multiaddr) {}
// peerHandler keeps track of all state related to a specific "peering" peer.
type peerHandler struct {
peer peer.ID
host host.Host
ctx context.Context
cancel context.CancelFunc
logger *zap.Logger
addrs []multiaddr.Multiaddr
backoffStrat backoff.BackoffStrategy
reconnectTimer *time.Timer
muHandler sync.Mutex
}
// setAddrs sets the addresses for this peer.
func (ph *peerHandler) setAddrs(addrs []multiaddr.Multiaddr) {
// Not strictly necessary, but it helps to not trust the calling code.
addrCopy := make([]multiaddr.Multiaddr, len(addrs))
copy(addrCopy, addrs)
ph.muHandler.Lock()
ph.addrs = addrCopy
ph.muHandler.Unlock()
}
// getAddrs returns a shared slice of addresses for this peer. Do not modify.
func (ph *peerHandler) getAddrs() []multiaddr.Multiaddr {
ph.muHandler.Lock()
defer ph.muHandler.Unlock()
return ph.addrs
}
// stop permanently stops the peer handler.
func (ph *peerHandler) stop() {
ph.cancel()
ph.muHandler.Lock()
if ph.reconnectTimer != nil {
ph.reconnectTimer.Stop()
ph.reconnectTimer = nil
}
ph.muHandler.Unlock()
}
func (ph *peerHandler) nextBackoff() time.Duration {
return ph.backoffStrat.Delay()
}
func (ph *peerHandler) reconnect() {
// Try connecting
addrs := ph.getAddrs()
ph.logger.Debug("reconnecting", logutil.PrivateStringer("peer", ph.peer), zap.Any("addrs", addrs))
err := ph.host.Connect(ph.ctx, peer.AddrInfo{ID: ph.peer, Addrs: addrs})
if err != nil {
delay := ph.nextBackoff()
if delay > MaximumReconnectingDelay {
ph.logger.Debug("peer unavailable", logutil.PrivateStringer("peer", ph.peer))
ph.stop()
return
}
ph.logger.Debug("failed to reconnect", zap.Duration("next_try", delay), logutil.PrivateStringer("peer", ph.peer), zap.Error(err))
// Ok, we failed. Extend the timeout.
ph.muHandler.Lock()
if ph.reconnectTimer != nil {
// Only counts if the reconnectTimer still exists. If not, a
// connection _was_ somehow established.
ph.reconnectTimer.Reset(delay)
}
// Otherwise, someone else has stopped us so we can assume that
// we're either connected or someone else will start us.
ph.muHandler.Unlock()
}
// Always call this. We could have connected since we processed the
// error.
ph.stopIfConnected()
}
func (ph *peerHandler) stopIfConnected() {
ph.muHandler.Lock()
defer ph.muHandler.Unlock()
if ph.reconnectTimer != nil && ph.host.Network().Connectedness(ph.peer) == network.Connected {
ph.logger.Debug("successfully reconnected", logutil.PrivateStringer("peer", ph.peer))
// stop reconnect timer
ph.reconnectTimer.Stop()
ph.reconnectTimer = nil
}
}
// startIfDisconnected is the inverse of stopIfConnected.
func (ph *peerHandler) startIfDisconnected() {
ph.muHandler.Lock()
defer ph.muHandler.Unlock()
if ph.reconnectTimer == nil && ph.host.Network().Connectedness(ph.peer) != network.Connected {
// reset backoff
ph.backoffStrat.Reset()
delay := ph.nextBackoff()
ph.logger.Debug("disconnected from peer, waiting for reconnection", logutil.PrivateStringer("peer", ph.peer), zap.Duration("delay", delay))
// Always start with a short timeout so we can stagger things a bit.
ph.reconnectTimer = time.AfterFunc(delay, ph.reconnect)
}
}
================================================
FILE: pkg/ipfsutil/pubsub_adaptater.go
================================================
package ipfsutil
import (
coreiface "github.com/ipfs/kubo/core/coreiface"
)
type pubsubCoreAPIAdapter struct {
coreiface.PubSubAPI
coreiface.CoreAPI
}
func (ps *pubsubCoreAPIAdapter) PubSub() coreiface.PubSubAPI {
return ps.PubSubAPI
}
func InjectPubSubAPI(api coreiface.CoreAPI, ps coreiface.PubSubAPI) coreiface.CoreAPI {
return &pubsubCoreAPIAdapter{
PubSubAPI: ps,
CoreAPI: api,
}
}
type pubsubExtendedCoreAPIAdapter struct {
coreiface.PubSubAPI
ExtendedCoreAPI
}
func (ps *pubsubExtendedCoreAPIAdapter) PubSub() coreiface.PubSubAPI {
return ps.PubSubAPI
}
func InjectPubSubCoreAPIExtendedAdapter(exapi ExtendedCoreAPI, ps coreiface.PubSubAPI) ExtendedCoreAPI {
return &pubsubExtendedCoreAPIAdapter{
PubSubAPI: ps,
ExtendedCoreAPI: exapi,
}
}
================================================
FILE: pkg/ipfsutil/pubsub_api.go
================================================
package ipfsutil
import (
"context"
"sync"
coreiface "github.com/ipfs/kubo/core/coreiface"
coreiface_options "github.com/ipfs/kubo/core/coreiface/options"
p2p_pubsub "github.com/libp2p/go-libp2p-pubsub"
p2p_peer "github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
type PubSubAPI struct {
*p2p_pubsub.PubSub
logger *zap.Logger
muTopics sync.RWMutex
topics map[string]*p2p_pubsub.Topic
}
func NewPubSubAPI(_ context.Context, logger *zap.Logger, ps *p2p_pubsub.PubSub) coreiface.PubSubAPI {
return &PubSubAPI{
PubSub: ps,
logger: logger,
topics: make(map[string]*p2p_pubsub.Topic),
}
}
func (ps *PubSubAPI) topicJoin(topic string, opts ...p2p_pubsub.TopicOpt) (*p2p_pubsub.Topic, error) {
ps.muTopics.Lock()
defer ps.muTopics.Unlock()
var err error
t, ok := ps.topics[topic]
if ok {
return t, nil
}
if t, err = ps.PubSub.Join(topic, opts...); err != nil {
return nil, err
}
if _, err = t.Relay(); err != nil {
t.Close()
return nil, err
}
ps.topics[topic] = t
return t, nil
}
// func (ps *PubSubAPI) topicLeave(topic string) (err error) {
// ps.muTopics.Lock()
// if t, ok := ps.topics[topic]; ok {
// err = t.Close()
// delete(ps.topics, topic)
// }
// ps.muTopics.Unlock()
// return
// }
// Ls lists subscribed topics by name
func (ps *PubSubAPI) Ls(context.Context) ([]string, error) {
return ps.PubSub.GetTopics(), nil
}
// Peers list peers we are currently pubsubbing with
func (ps *PubSubAPI) Peers(_ context.Context, opts ...coreiface_options.PubSubPeersOption) ([]p2p_peer.ID, error) {
s, err := coreiface_options.PubSubPeersOptions(opts...)
if err != nil {
return nil, err
}
return ps.PubSub.ListPeers(s.Topic), nil
}
var minTopicSize = p2p_pubsub.WithReadiness(p2p_pubsub.MinTopicSize(1))
// Publish a message to a given pubsub topic
func (ps *PubSubAPI) Publish(ctx context.Context, topic string, msg []byte) error {
t, err := ps.topicJoin(topic)
if err != nil {
return err
}
return t.Publish(ctx, msg, minTopicSize)
}
// Subscribe to messages on a given topic
func (ps *PubSubAPI) Subscribe(_ context.Context, topic string, _ ...coreiface_options.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
t, err := ps.topicJoin(topic)
if err != nil {
return nil, err
}
ps.logger.Debug("subscribing", logutil.PrivateString("topic", topic))
sub, err := t.Subscribe()
if err != nil {
return nil, err
}
return &pubsubSubscriptionAPI{ps.logger, sub}, nil
}
// PubSubSubscription is an active PubSub subscription
type pubsubSubscriptionAPI struct {
logger *zap.Logger
*p2p_pubsub.Subscription
}
// io.Closer
func (pss *pubsubSubscriptionAPI) Close() (_ error) {
pss.Subscription.Cancel()
return
}
// Next return the next incoming message
func (pss *pubsubSubscriptionAPI) Next(ctx context.Context) (coreiface.PubSubMessage, error) {
m, err := pss.Subscription.Next(ctx)
if err != nil {
return nil, err
}
return &pubsubMessageAPI{m}, nil
}
// PubSubMessage is a single PubSub message
type pubsubMessageAPI struct {
*p2p_pubsub.Message
}
// From returns id of a peer from which the message has arrived
func (psm *pubsubMessageAPI) From() p2p_peer.ID {
return psm.Message.GetFrom()
}
// Data returns the message body
func (psm *pubsubMessageAPI) Data() []byte {
return psm.Message.GetData()
}
// Seq returns message identifier
func (psm *pubsubMessageAPI) Seq() []byte {
return psm.Message.GetSeqno()
}
// // Topics returns list of topics this message was set to
func (psm *pubsubMessageAPI) Topics() []string {
if psm.Message.Topic == nil {
return nil
}
return []string{*psm.Message.Topic}
}
================================================
FILE: pkg/ipfsutil/pubsub_monitor.go
================================================
package ipfsutil
import (
"sync"
ps "github.com/libp2p/go-libp2p-pubsub"
ps_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/event"
host "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
// PubsubMonitor is an EventTracer
var _ ps.EventTracer = (*PubsubMonitor)(nil)
type EventMonitor int
const (
TypeEventMonitorPeerUnknown EventMonitor = iota
TypeEventMonitorPeerJoined
TypeEventMonitorPeerLeft
)
type EventTracer interface {
EventTracerOption() ps.Option
}
type EvtPubSubTopic struct {
EventType EventMonitor
Topic string
PeerID peer.ID
}
type PubsubMonitor struct {
logger *zap.Logger
h host.Host
ps *ps.PubSub
emitter event.Emitter
muPeersTopics sync.Mutex
peersTopics map[peer.ID][]string
}
func NewPubsubMonitor(l *zap.Logger, h host.Host) (EventTracer, error) {
emitter, err := h.EventBus().Emitter(new(EvtPubSubTopic))
if err != nil {
return nil, err
}
return &PubsubMonitor{
h: h,
logger: l,
emitter: emitter,
peersTopics: make(map[peer.ID][]string),
}, nil
}
func (pt *PubsubMonitor) EventTracerOption() ps.Option {
return func(p *ps.PubSub) error {
pt.ps = p
return ps.WithEventTracer(pt)(p)
}
}
func (pt *PubsubMonitor) Trace(e *ps_pb.TraceEvent) {
switch e.GetType() {
case ps_pb.TraceEvent_JOIN:
topic := e.GetJoin().GetTopic()
peer := pt.h.ID()
pt.Emit(&EvtPubSubTopic{
EventType: TypeEventMonitorPeerJoined,
Topic: topic,
PeerID: peer,
})
case ps_pb.TraceEvent_LEAVE:
topic := e.GetLeave().GetTopic()
peer := pt.h.ID()
pt.Emit(&EvtPubSubTopic{
EventType: TypeEventMonitorPeerLeft,
Topic: topic,
PeerID: peer,
})
case ps_pb.TraceEvent_REMOVE_PEER:
peerid, err := peer.IDFromBytes(e.GetRemovePeer().GetPeerID())
if err != nil {
pt.logger.Warn("unable to parse peerid",
zap.String("type", e.GetType().String()),
logutil.PrivateString("topic", e.GetGraft().GetTopic()))
return
}
topics := pt.popTopicFromPeer(peerid)
for _, topic := range topics {
pt.Emit(&EvtPubSubTopic{
EventType: TypeEventMonitorPeerLeft,
Topic: topic,
PeerID: peerid,
})
}
case ps_pb.TraceEvent_GRAFT:
topic := e.GetGraft().GetTopic()
peerid, err := peer.IDFromBytes(e.GetGraft().GetPeerID())
if err != nil {
pt.logger.Warn("unable to parse peerid",
zap.String("type", e.GetType().String()),
logutil.PrivateString("topic", e.GetGraft().GetTopic()))
return
}
pt.addTopicToPeer(peerid, topic)
pt.Emit(&EvtPubSubTopic{
EventType: TypeEventMonitorPeerJoined,
Topic: topic,
PeerID: peerid,
})
case ps_pb.TraceEvent_PRUNE:
// @FIXME(gfanton): send this info as well
}
}
func (pt *PubsubMonitor) Emit(e *EvtPubSubTopic) {
if err := pt.emitter.Emit(*e); err != nil {
pt.logger.Warn("unable to emit pubsub event")
}
}
func (pt *PubsubMonitor) popTopicFromPeer(p peer.ID) []string {
pt.muPeersTopics.Lock()
defer pt.muPeersTopics.Unlock()
if topics, ok := pt.peersTopics[p]; ok {
delete(pt.peersTopics, p)
return topics
}
return []string{}
}
func (pt *PubsubMonitor) addTopicToPeer(p peer.ID, ns string) {
pt.muPeersTopics.Lock()
topics, ok := pt.peersTopics[p]
if !ok {
topics = make([]string, 0)
}
pt.peersTopics[p] = append(topics, ns)
pt.muPeersTopics.Unlock()
}
================================================
FILE: pkg/ipfsutil/repo.go
================================================
package ipfsutil
import (
crand "crypto/rand"
"encoding/base64"
"fmt"
"path/filepath"
"time"
ipfs_ds "github.com/ipfs/go-datastore"
ipfs_cfg "github.com/ipfs/kubo/config"
ipfs_loader "github.com/ipfs/kubo/plugin/loader"
ipfs_repo "github.com/ipfs/kubo/repo"
ipfs_fsrepo "github.com/ipfs/kubo/repo/fsrepo"
p2p_ci "github.com/libp2p/go-libp2p/core/crypto"
p2p_peer "github.com/libp2p/go-libp2p/core/peer"
"github.com/pkg/errors"
"berty.tech/weshnet/v2/pkg/errcode"
)
// defaultConnMgrHighWater is the default value for the connection managers
// 'high water' mark
const defaultConnMgrHighWater = 200
// defaultConnMgrLowWater is the default value for the connection managers 'low
// water' mark
const defaultConnMgrLowWater = 150
// defaultConnMgrGracePeriod is the default value for the connection managers
// grace period
const defaultConnMgrGracePeriod = time.Second * 20
// @NOTE(gfanton): this will be removed with gomobile-ipfs
var plugins *ipfs_loader.PluginLoader
func CreateMockedRepo(dstore ipfs_ds.Batching) (ipfs_repo.Repo, error) {
c, err := CreateBaseConfig()
if err != nil {
return nil, err
}
return &ipfs_repo.Mock{
D: dstore,
C: *c,
}, nil
}
func CreateOrLoadMockedRepo(dstore ipfs_ds.Batching) (ipfs_repo.Repo, error) {
c, err := CreateBaseConfig()
if err != nil {
return nil, err
}
return &ipfs_repo.Mock{
D: dstore,
C: *c,
}, nil
}
func LoadRepoFromPath(path string) (ipfs_repo.Repo, error) {
dir, _ := filepath.Split(path)
if _, err := LoadPlugins(dir); err != nil {
return nil, errors.Wrap(err, "failed to load plugins")
}
if !ipfs_fsrepo.IsInitialized(path) {
cfg, err := CreateBaseConfig()
if err != nil {
return nil, fmt.Errorf("failed to create base config: %w", err)
}
ucfg, err := upgradeToPersistentConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "failed to upgrade repo")
}
if err := ipfs_fsrepo.Init(path, ucfg); err != nil {
return nil, fmt.Errorf("failed to init ipfs repo: %w", err)
}
}
return ipfs_fsrepo.Open(path)
}
var DefaultSwarmListeners = []string{
"/ip4/0.0.0.0/udp/0/quic-v1",
"/ip6/::/udp/0/quic-v1",
// "/ip4/0.0.0.0/tcp/0",
// "/ip6/::/tcp/0",
}
func CreateBaseConfig() (*ipfs_cfg.Config, error) {
c := ipfs_cfg.Config{}
// set default bootstrap
c.Bootstrap = ipfs_cfg.DefaultBootstrapAddresses
c.Peering.Peers = []p2p_peer.AddrInfo{}
// Identity
if err := ResetRepoIdentity(&c); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
// Discovery
c.Discovery.MDNS.Enabled = true
// swarm listeners
c.Addresses.Swarm = DefaultSwarmListeners
// Swarm
c.Swarm.RelayClient.Enabled = ipfs_cfg.True
c.Swarm.ConnMgr = ipfs_cfg.ConnMgr{
LowWater: ipfs_cfg.NewOptionalInteger(defaultConnMgrLowWater),
HighWater: ipfs_cfg.NewOptionalInteger(defaultConnMgrHighWater),
GracePeriod: ipfs_cfg.NewOptionalDuration(defaultConnMgrGracePeriod),
Type: ipfs_cfg.NewOptionalString("basic"),
}
c.Routing = ipfs_cfg.Routing{
Type: ipfs_cfg.NewOptionalString("dhtclient"),
}
return &c, nil
}
func ResetRepoIdentity(c *ipfs_cfg.Config) error {
priv, pub, err := p2p_ci.GenerateKeyPairWithReader(p2p_ci.Ed25519, 2048, crand.Reader) // nolint:staticcheck
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
pid, err := p2p_peer.IDFromPublicKey(pub) // nolint:staticcheck
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
privkeyb, err := p2p_ci.MarshalPrivateKey(priv)
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
// Identity
c.Identity.PeerID = pid.String()
c.Identity.PrivKey = base64.StdEncoding.EncodeToString(privkeyb)
return nil
}
func upgradeToPersistentConfig(cfg *ipfs_cfg.Config) (*ipfs_cfg.Config, error) {
cfgCopy, err := cfg.Clone()
if err != nil {
return nil, err
}
// setup the node mount points.
cfgCopy.Mounts = ipfs_cfg.Mounts{
IPFS: "/ipfs",
IPNS: "/ipns",
}
cfgCopy.Ipns = ipfs_cfg.Ipns{
ResolveCacheSize: 128,
}
cfgCopy.Reprovider = ipfs_cfg.Reprovider{
Interval: ipfs_cfg.NewOptionalDuration(time.Hour * 12),
Strategy: ipfs_cfg.NewOptionalString("all"),
}
cfgCopy.Datastore = ipfs_cfg.Datastore{
StorageMax: "10GB",
StorageGCWatermark: 90, // 90%
GCPeriod: "1h",
BloomFilterSize: 0,
Spec: map[string]any{
"type": "mount",
"mounts": []any{
map[string]any{
"mountpoint": "/blocks",
"type": "measure",
"prefix": "flatfs.datastore",
"child": map[string]any{
"type": "flatfs",
"path": "blocks",
"sync": true,
"shardFunc": "/repo/flatfs/shard/v1/next-to-last/2",
},
},
map[string]any{
"mountpoint": "/",
"type": "measure",
"prefix": "leveldb.datastore",
"child": map[string]any{
"type": "levelds",
"path": "datastore",
"compression": "none",
},
},
},
},
}
return cfgCopy, nil
}
func ResetExistingRepoIdentity(repo ipfs_repo.Repo) (ipfs_repo.Repo, error) {
cfg, err := repo.Config()
if err != nil {
_ = repo.Close()
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
if err := ResetRepoIdentity(cfg); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
updatedCfg, err := upgradeToPersistentConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "failed to upgrade repo")
}
err = repo.SetConfig(updatedCfg)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return repo, nil
}
func LoadPlugins(repoPath string) (*ipfs_loader.PluginLoader, error) { // nolint:unparam
if plugins != nil {
return plugins, nil
}
pluginpath := filepath.Join(repoPath, "plugins")
lp, err := ipfs_loader.NewPluginLoader(pluginpath)
if err != nil {
return nil, err
}
if err = lp.Initialize(); err != nil {
return nil, err
}
if err = lp.Inject(); err != nil {
return nil, err
}
plugins = lp
return lp, nil
}
================================================
FILE: pkg/ipfsutil/testing.go
================================================
package ipfsutil
import (
"context"
crand "crypto/rand"
"encoding/base64"
"fmt"
"net"
"testing"
rendezvous "github.com/berty/go-libp2p-rendezvous"
p2p_rpdb "github.com/berty/go-libp2p-rendezvous/db/sqlcipher"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
ipfs_cfg "github.com/ipfs/kubo/config"
ipfs_core "github.com/ipfs/kubo/core"
ipfs_p2p "github.com/ipfs/kubo/core/node/libp2p"
ipfs_repo "github.com/ipfs/kubo/repo"
"github.com/libp2p/go-libp2p"
pubsub "github.com/libp2p/go-libp2p-pubsub"
p2p_ci "github.com/libp2p/go-libp2p/core/crypto"
host "github.com/libp2p/go-libp2p/core/host"
p2pnetwork "github.com/libp2p/go-libp2p/core/network"
p2p_peer "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/protocol"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
ipfs_mobile "berty.tech/weshnet/v2/pkg/ipfsutil/mobile"
tinder "berty.tech/weshnet/v2/pkg/tinder"
)
// CoreAPIMock implements ipfs.CoreAPI and adds some debugging helpers
type CoreAPIMock interface {
API() ExtendedCoreAPI
PubSub() *pubsub.PubSub
Tinder() *tinder.Service
MockNetwork() mocknet.Mocknet
MockNode() *ipfs_core.IpfsNode
Close()
}
func getOrCreatePrivateKeyFromDatastore(t testing.TB, ctx context.Context, datastore ds.Datastore) p2p_ci.PrivKey {
const datastoreKeyForPrivateKey = "p2p_private_key"
privkeyb, err := datastore.Get(ctx, ds.NewKey("private_key"))
if err == ds.ErrNotFound {
priv, _, err := p2p_ci.GenerateKeyPairWithReader(p2p_ci.RSA, 2048, crand.Reader)
if err != nil {
t.Fatalf("failed to generate pair key: %v", err)
}
privkeyb, err := p2p_ci.MarshalPrivateKey(priv)
if err != nil {
t.Fatalf("failed to get raw priv key: %v", err)
}
if err := datastore.Put(ctx, ds.NewKey(datastoreKeyForPrivateKey), privkeyb); err != nil {
t.Fatalf("failed to save priv key: %v", err)
}
return priv
} else if err != nil {
t.Fatalf("failed to get value from datastore: %v", err)
}
priv, err := p2p_ci.UnmarshalPrivateKey(privkeyb)
if err != nil {
t.Fatalf("failed to unmarshal priv key: %v", err)
}
return priv
}
func TestingRepo(t testing.TB, ctx context.Context, datastore ds.Datastore) ipfs_repo.Repo {
t.Helper()
c := ipfs_cfg.Config{}
priv := getOrCreatePrivateKeyFromDatastore(t, ctx, datastore)
pid, err := p2p_peer.IDFromPublicKey(priv.GetPublic())
if err != nil {
t.Fatalf("failed to get pid from pub key: %v", err)
}
privkeyb, err := p2p_ci.MarshalPrivateKey(priv)
if err != nil {
t.Fatalf("failed to get raw priv key: %v", err)
}
c.Bootstrap = []string{}
c.Addresses.Swarm = []string{"/ip6/::/tcp/0"}
c.Identity.PeerID = pid.String()
c.Identity.PrivKey = base64.StdEncoding.EncodeToString(privkeyb)
c.Swarm.ResourceMgr.Enabled = ipfs_cfg.False
if datastore == nil {
datastore = ds.NewMapDatastore()
}
dstore := dsync.MutexWrap(datastore)
return &ipfs_repo.Mock{
D: dstore,
C: c,
}
}
type TestingAPIOpts struct {
Logger *zap.Logger
Mocknet mocknet.Mocknet
Datastore ds.Batching
DiscoveryServer *tinder.MockDriverServer
}
// TestingCoreAPIUsingMockNet returns a fully initialized mocked Core API with the given mocknet
func TestingCoreAPIUsingMockNet(ctx context.Context, t testing.TB, opts *TestingAPIOpts) CoreAPIMock {
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
msrv := opts.DiscoveryServer
if msrv == nil {
t.Log("warning: no discovery available")
msrv = tinder.NewMockDriverServer()
}
datastore := opts.Datastore
if datastore == nil {
datastore = dsync.MutexWrap(ds.NewMapDatastore())
}
repo := TestingRepo(t, ctx, datastore)
mrepo := ipfs_mobile.NewRepoMobile("", repo)
t.Cleanup(func() { mrepo.Close() })
mnode, err := NewIPFSMobile(ctx, mrepo, &MobileOptions{
HostOption: MockHostOption(opts.Mocknet),
RoutingOption: ipfs_p2p.NilRouterOption,
ExtraOpts: map[string]bool{
"pubsub": false,
},
P2PStaticRelays: []string{},
PeerStorePeers: []string{},
})
t.Cleanup(func() { mnode.Close() })
h := mnode.PeerHost()
mockDriver := msrv.Client(h)
// enable discovery monitor
stinder, err := tinder.NewService(h, opts.Logger, mockDriver)
require.NoError(t, err)
discAdaptater := tinder.NewDiscoveryAdaptater(opts.Logger, stinder)
t.Cleanup(func() { discAdaptater.Close() })
ps, err := pubsub.NewGossipSub(ctx, h, pubsub.WithDiscovery(discAdaptater))
require.NoError(t, err)
require.NoError(t, err, "failed to initialize IPFS node mock")
require.NotNil(t, ps, "pubsub should not be nil")
require.NotNil(t, stinder, "discovery should not be nil")
exapi, err := NewExtendedCoreAPIFromNode(mnode.IpfsNode)
require.NoError(t, err, "unable to extend core api from node")
psapi := NewPubSubAPI(ctx, opts.Logger, ps)
exapi = InjectPubSubCoreAPIExtendedAdapter(exapi, psapi)
EnableConnLogger(ctx, opts.Logger, mnode.PeerHost())
api := &coreAPIMock{
coreapi: exapi,
mocknet: opts.Mocknet,
pubsub: ps,
node: mnode.IpfsNode,
tinder: stinder,
}
return api
}
// TestingCoreAPI returns a fully initialized mocked Core API.
// If you want to do some tests involving multiple peers you should use
// `TestingCoreAPIUsingMockNet` with the same mocknet instead.
func TestingCoreAPI(ctx context.Context, t testing.TB) CoreAPIMock {
t.Helper()
m := mocknet.New()
t.Cleanup(func() { m.Close() })
api := TestingCoreAPIUsingMockNet(ctx, t, &TestingAPIOpts{
Mocknet: m,
DiscoveryServer: tinder.NewMockDriverServer(),
})
return api
}
func TestingRDVP(ctx context.Context, t testing.TB, h host.Host) (*rendezvous.RendezvousService, func()) {
db, err := p2p_rpdb.OpenDB(ctx, ":memory:")
require.NoError(t, err)
provider, err := rendezvous.NewSyncInMemProvider(h)
require.NoError(t, err)
svc := rendezvous.NewRendezvousService(h, db, provider)
cleanup := func() {
_ = db.Close() // dont use me for now as db is open in_memory
}
return svc, cleanup
}
type coreAPIMock struct {
coreapi ExtendedCoreAPI
pubsub *pubsub.PubSub
mocknet mocknet.Mocknet
node *ipfs_core.IpfsNode
tinder *tinder.Service
}
func (m *coreAPIMock) ConnMgr() ConnMgr {
return m.node.PeerHost.ConnManager()
}
func (m *coreAPIMock) NewStream(ctx context.Context, p p2p_peer.ID, pids ...protocol.ID) (p2pnetwork.Stream, error) {
return m.node.PeerHost.NewStream(ctx, p, pids...)
}
func (m *coreAPIMock) SetStreamHandler(pid protocol.ID, handler p2pnetwork.StreamHandler) {
m.node.PeerHost.SetStreamHandler(pid, handler)
}
func (m *coreAPIMock) RemoveStreamHandler(pid protocol.ID) {
m.node.PeerHost.RemoveStreamHandler(pid)
}
func (m *coreAPIMock) API() ExtendedCoreAPI {
return m.coreapi
}
func (m *coreAPIMock) MockNetwork() mocknet.Mocknet {
return m.mocknet
}
func (m *coreAPIMock) MockNode() *ipfs_core.IpfsNode {
return m.node
}
func (m *coreAPIMock) PubSub() *pubsub.PubSub {
return m.pubsub
}
func (m *coreAPIMock) Tinder() *tinder.Service {
return m.tinder
}
func (m *coreAPIMock) Close() {
m.node.Close()
}
func MockHostOption(mn mocknet.Mocknet) ipfs_p2p.HostOption {
return func(id p2p_peer.ID, ps peerstore.Peerstore, _ ...libp2p.Option) (host.Host, error) {
blackholeIP6 := net.ParseIP("100::")
pkey := ps.PrivKey(id)
if pkey == nil {
return nil, fmt.Errorf("missing private key for node ID: %s", id)
}
suffix := id
if len(id) > 8 {
suffix = id[len(id)-8:]
}
ip := append(net.IP{}, blackholeIP6...)
copy(ip[net.IPv6len-len(suffix):], suffix)
a, err := ma.NewMultiaddr(fmt.Sprintf("/ip6/%s/tcp/4242", ip))
if err != nil {
return nil, fmt.Errorf("failed to create test multiaddr: %s", err)
}
ps.AddAddr(id, a, peerstore.PermanentAddrTTL)
err = ps.AddPrivKey(id, pkey)
if err != nil {
return nil, err
}
err = ps.AddPubKey(id, pkey.GetPublic())
if err != nil {
return nil, err
}
return mn.AddPeerWithPeerstore(id, ps)
}
}
================================================
FILE: pkg/ipfsutil/util.go
================================================
package ipfsutil
import (
"bytes"
"fmt"
"net"
"sort"
ma "github.com/multiformats/go-multiaddr"
"go.uber.org/multierr"
)
type Multiaddrs []ma.Multiaddr
func NewMultiaddrs(m []ma.Multiaddr) Multiaddrs {
ms := Multiaddrs(m)
sort.Sort(ms)
return ms
}
// Len is the number of elements in the collection.
func (ms Multiaddrs) Len() int { return len(ms) }
// Less reports whether the element with
// index i should sort before the element with index j.
func (ms Multiaddrs) Less(i, j int) bool { return bytes.Compare(ms[i].Bytes(), ms[j].Bytes()) < 0 }
// Swap swaps the elements with indexes i and j.
func (ms Multiaddrs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
// MultiaddrIsEqual return true if both slice are equal
func MultiaddrIsEqual(a Multiaddrs, b Multiaddrs) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if !a[i].Equal(b[i]) {
return false
}
}
return true
}
func ParseAddr(addr string) (ma.Multiaddr, error) {
maddr, err := ma.NewMultiaddr(addr)
if err == nil {
return maddr, nil
}
// try to get a tcp multiaddr from host:port
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
if host == "" {
host = "127.0.0.1"
}
addr = fmt.Sprintf("/ip4/%s/tcp/%s/", host, port)
return ma.NewMultiaddr(addr)
}
func ParseAddrs(addrs ...string) ([]ma.Multiaddr, error) {
maddrs := make([]ma.Multiaddr, len(addrs))
var err error
for i, addr := range addrs {
var thisErr error
maddrs[i], thisErr = ParseAddr(addr)
err = multierr.Append(err, thisErr)
}
return maddrs, err
}
================================================
FILE: pkg/lifecycle/example_test.go
================================================
package lifecycle_test
================================================
FILE: pkg/lifecycle/manager.go
================================================
package lifecycle
import (
"context"
"sync"
"berty.tech/weshnet/v2/internal/notify"
)
type State int
const (
StateActive State = iota
StateInactive
)
type Manager struct {
currentState State
locker *sync.RWMutex
notify *notify.Notify
groupWaiter sync.WaitGroup
}
func NewManager(initialState State) *Manager {
var locker sync.RWMutex
return &Manager{
currentState: initialState,
locker: &locker,
notify: notify.New(&locker),
}
}
// UpdateState update the current state of the Manager
func (m *Manager) UpdateState(state State) {
m.locker.Lock()
if m.currentState != state {
m.currentState = state
m.notify.Broadcast()
}
m.locker.Unlock()
}
// WaitForStateChange waits until the currentState changes from sourceState or ctx expires. A true value is returned in former case and false in latter.
func (m *Manager) WaitForStateChange(ctx context.Context, sourceState State) bool {
m.locker.Lock()
ok := true
for sourceState == m.currentState && ok {
// wait until state has been changed or context has been cancel
ok = m.notify.Wait(ctx)
}
m.locker.Unlock()
return ok
}
// GetCurrentState return the current state of the Manager
func (m *Manager) GetCurrentState() (state State) {
m.locker.RLock()
state = m.currentState
m.locker.RUnlock()
return
}
// TaskWaitForStateChange is the same as `WaitForStateChange` but also return a
// task that can be mark as done by the upper caller to notify he is done
// handling the new state, done should always be called to avoid deadlock.
// use `WaitForTasks` to wait for task to complete
func (m *Manager) TaskWaitForStateChange(ctx context.Context, sourceState State) (Task, bool) {
m.locker.Lock()
defer m.locker.Unlock()
for sourceState == m.currentState {
// wait until state has been changed or context has been cancel
if ok := m.notify.Wait(ctx); !ok {
return nil, false
}
}
m.groupWaiter.Add(1)
return &task{t: &m.groupWaiter}, true
}
// WaitForTasks wait until all tasks returned by `TaskWaitForStateChange` are done
func (m *Manager) WaitForTasks() {
m.locker.RLock()
m.groupWaiter.Wait() // wait for all tasks to be done
m.locker.RUnlock()
}
================================================
FILE: pkg/lifecycle/task.go
================================================
package lifecycle
import "sync"
type Task interface {
Done()
}
type task struct {
t Task
o sync.Once
}
func (t *task) Done() {
t.o.Do(t.t.Done)
}
================================================
FILE: pkg/logutil/crypto_utils.go
================================================
package logutil
import (
"encoding/base64"
"github.com/libp2p/go-libp2p/core/crypto"
)
func CryptoKeyToBytes(key crypto.Key) []byte {
keyBytes, err := key.Raw()
if err != nil {
return []byte{0}
}
return keyBytes
}
func CryptoKeyToBase64(key crypto.Key) string {
bytes := CryptoKeyToBytes(key)
return base64.StdEncoding.EncodeToString(bytes)
}
================================================
FILE: pkg/logutil/encoders.go
================================================
package logutil
import (
"fmt"
"go.uber.org/zap/zapcore"
)
const (
Black uint8 = iota + 30
Red
Green
Yellow
Blue
Magenta
Cyan
White
)
func stableWidthNameEncoder(loggerName string, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(fmt.Sprintf("%-18s", loggerName))
}
func stableWidthCapitalLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(fmt.Sprintf("%-5s", l.CapitalString()))
}
func stableWidthCapitalColorLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
switch l {
case zapcore.DebugLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Magenta, "DEBUG"))
case zapcore.InfoLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Blue, "INFO"))
case zapcore.WarnLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Yellow, "WARN"))
case zapcore.ErrorLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Red, "ERROR"))
case zapcore.DPanicLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Red, "DPANIC"))
case zapcore.PanicLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Red, "PANIC"))
case zapcore.FatalLevel:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Red, "FATAL"))
default:
enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", Red, l.CapitalString()))
}
}
================================================
FILE: pkg/logutil/example_test.go
================================================
package logutil_test
import (
"berty.tech/weshnet/v2/pkg/logutil"
)
func Example_logall() {
logger, cleanup, err := logutil.NewLogger(logutil.NewStdStream("*", "light-console", "stdout"))
if err != nil {
panic(err)
}
defer cleanup()
logger.Debug("top debug")
logger.Info("top info")
logger.Warn("top warn")
logger.Error("top error")
logger.Named("foo").Debug("foo debug")
logger.Named("foo").Info("foo info")
logger.Named("foo").Warn("foo warn")
logger.Named("foo").Error("foo error")
// Output:
// DEBUG bty logutil/example_test.go:14 top debug
// INFO bty logutil/example_test.go:15 top info
// WARN bty logutil/example_test.go:16 top warn
// ERROR bty logutil/example_test.go:17 top error
// DEBUG bty.foo logutil/example_test.go:19 foo debug
// INFO bty.foo logutil/example_test.go:20 foo info
// WARN bty.foo logutil/example_test.go:21 foo warn
// ERROR bty.foo logutil/example_test.go:22 foo error
}
func Example_logerrors() {
logger, cleanup, err := logutil.NewLogger(logutil.NewStdStream("error:*,-*.bar warn:*.bar", "light-console", "stdout"))
if err != nil {
panic(err)
}
defer cleanup()
logger.Debug("top debug")
logger.Info("top info")
logger.Warn("top warn")
logger.Error("top error")
logger.Named("foo").Debug("foo debug")
logger.Named("foo").Info("foo info")
logger.Named("foo").Warn("foo warn")
logger.Named("foo").Error("foo error")
logger.Named("foo").Named("bar").Debug("foo.bar debug")
logger.Named("foo").Named("bar").Info("foo.bar info")
logger.Named("foo").Named("bar").Warn("foo.bar warn")
logger.Named("foo").Named("bar").Error("foo.bar error")
// Output:
// ERROR bty logutil/example_test.go:45 top error
// ERROR bty.foo logutil/example_test.go:50 foo error
// WARN bty.foo.bar logutil/example_test.go:54 foo.bar warn
}
================================================
FILE: pkg/logutil/file.go
================================================
package logutil
import (
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
"go.uber.org/multierr"
"moul.io/u"
"berty.tech/weshnet/v2/pkg/errcode"
)
func newFileWriteCloser(target, kind string) (io.WriteCloser, error) {
var filename string
switch {
case strings.HasSuffix(target, ".log"): // use the indicated 'path' as filename
filename = target
default: // automatically create a new file in the 'path' directory following a pattern
startTime := time.Now().Format(filePatternDateLayout)
filename = filepath.Join(
target,
fmt.Sprintf("%s-%s.log", kind, startTime),
)
// run gc
{
err := LogfileGC(target, 20)
if err != nil {
return nil, err
}
}
}
if dir := filepath.Dir(filename); !u.DirExists(dir) {
err := os.MkdirAll(dir, 0o711)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
}
var writer io.WriteCloser
if u.FileExists(filename) {
var err error
writer, err = os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
} else {
var err error
writer, err = os.Create(filename)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
}
return writer, nil
}
type Logfile struct {
Dir string
Name string
Size int64
Kind string
Time time.Time
Latest bool
Errs error `json:"Errs,omitempty"`
}
func (l Logfile) Path() string {
return filepath.Join(l.Dir, l.Name)
}
const filePatternDateLayout = "2006-01-02T15-04-05.000"
var filePatternRegex = regexp.MustCompile(`(?m)^(.*)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}.\d{3}).log$`)
func LogfileList(logDir string) ([]*Logfile, error) {
files, err := os.ReadDir(logDir)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
infos := make([]fs.FileInfo, 0, len(files))
for _, entry := range files {
info, err := entry.Info()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
infos = append(infos, info)
}
logfiles := []*Logfile{}
for _, info := range infos {
sub := filePatternRegex.FindStringSubmatch(info.Name())
if sub == nil {
continue
}
t, err := time.Parse(filePatternDateLayout, sub[2])
var errs error
if err != nil {
errs = multierr.Append(errs, err)
}
// use os.Stat to get the file size (updated than fs.FileInfo.Size()
filepath := filepath.Join(logDir, info.Name())
fi, err := os.Stat(filepath)
if err != nil {
errs = multierr.Append(errs, err)
}
logfiles = append(logfiles, &Logfile{
Dir: logDir,
Name: info.Name(),
Size: fi.Size(),
Kind: sub[1],
Time: t,
Errs: errs,
})
}
// compute latest
if len(logfiles) > 0 {
var maxTime time.Time
for _, file := range logfiles {
if file.Time.After(maxTime) {
maxTime = file.Time
}
}
for _, file := range logfiles {
if file.Time == maxTime {
file.Latest = true
}
}
}
return logfiles, nil
}
func CurrentLogfilePath(target string) (string, error) {
filename := ""
switch {
case strings.HasSuffix(target, ".log"): // use the indicated 'path' as filename
filename = target
default: // find the latest log file in the 'path' directory following a pattern
logfileList, err := LogfileList(target)
if err != nil {
return "", err
}
for _, logfile := range logfileList {
if logfile.Latest {
filename = logfile.Path()
break
}
}
}
return filename, nil
}
func LogfileGC(logDir string, max int) error {
if !u.DirExists(logDir) {
return nil
}
files, err := LogfileList(logDir)
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
if len(files) < max {
return nil
}
sort.Slice(files, func(i, j int) bool {
return files[i].Time.Before(files[j].Time)
})
var errs error
for i := 0; i < len(files)-max; i++ {
err := os.Remove(files[i].Path())
if err != nil {
errs = multierr.Append(errs, err)
}
}
return errs
}
================================================
FILE: pkg/logutil/file_test.go
================================================
package logutil
import (
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/require"
"moul.io/u"
)
func TestLogfile(t *testing.T) {
// setup volatile directory for the test
tempdir, err := os.MkdirTemp("", "logutil-file")
require.NoError(t, err)
defer os.RemoveAll(tempdir)
// check loading log files from an invalid directory
{
files, err := LogfileList(filepath.Join(tempdir, "doesnotexist"))
require.Error(t, err)
require.Nil(t, files)
}
// check loading files from empty valid directory
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Empty(t, files)
}
// create dummy files
{
dummyNames := []string{
"2021-05-25T21-12-02.650.log",
"cli.info-2021-05-25T21-12-02.aaa.log",
"blah.log",
}
for _, name := range dummyNames {
f, err := os.Create(filepath.Join(tempdir, name))
require.NoError(t, err)
err = f.Close()
require.NoError(t, err)
}
}
// check loading files from valid directory with only dummy files
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Empty(t, files)
}
// create a first logger of kind-1
{
writer, err := newFileWriteCloser(tempdir, "kind-1")
require.NoError(t, err)
require.NotNil(t, writer)
_, err = writer.Write([]byte("blah\n"))
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
}
// check loading files from the directory, should have one now
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, files[0].Dir, tempdir)
require.NotEmpty(t, files[0].Name)
require.Equal(t, files[0].Path(), filepath.Join(tempdir, files[0].Name))
require.True(t, u.FileExists(files[0].Path()))
require.True(t, files[0].Latest)
require.Equal(t, files[0].Kind, "kind-1")
}
// create a second logger of kind-1
{
time.Sleep(time.Second)
writer, err := newFileWriteCloser(tempdir, "kind-1")
require.NoError(t, err)
require.NotNil(t, writer)
_, err = writer.Write([]byte("blah blah\n"))
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
}
// check loading files from the directory, should have two now
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 2)
for _, file := range files {
require.Equal(t, file.Dir, tempdir)
require.NotEmpty(t, file.Name)
require.Equal(t, file.Path(), filepath.Join(tempdir, file.Name))
require.True(t, u.FileExists(file.Path()))
}
}
// try to gc with fewer files than the limit
{
err := LogfileGC(tempdir, 10)
require.NoError(t, err)
}
// create 10 new files
{
for i := 0; i < 10; i++ {
writer, err := newFileWriteCloser(tempdir, fmt.Sprintf("hello-%d", i))
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
}
}
// check loading files from the directory, should have twelve now
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 12)
for _, file := range files {
require.Equal(t, file.Dir, tempdir)
require.NotEmpty(t, file.Name)
require.Equal(t, file.Path(), filepath.Join(tempdir, file.Name))
require.True(t, u.FileExists(file.Path()))
}
}
// try to gc with fewer files than the limit
{
err := LogfileGC(tempdir, 10)
require.NoError(t, err)
}
// check loading files from the directory, should have ten now
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 10)
}
// try to gc with the current amount of files
{
err := LogfileGC(tempdir, 10)
require.NoError(t, err)
}
// check loading files from the directory, should still have ten
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 10)
}
// try to gc with only one
{
err := LogfileGC(tempdir, 1)
require.NoError(t, err)
}
// check loading files from the directory, should now have only one
{
files, err := LogfileList(tempdir)
require.NoError(t, err)
require.Len(t, files, 1)
}
}
================================================
FILE: pkg/logutil/grpc_logger.go
================================================
package logutil
import (
"sync"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
"go.uber.org/zap"
)
var (
// grpc logger should be set only once.
// without this singleton, we can raise race conditions in unit tests => https://github.com/grpc/grpc-go/issues/1084
grpcLoggerConfigured bool
muGRPCLoggerConfigured sync.Mutex
)
func ReplaceGRPCLogger(l *zap.Logger) {
muGRPCLoggerConfigured.Lock()
if !grpcLoggerConfigured {
grpc_zap.ReplaceGrpcLoggerV2(l)
grpcLoggerConfigured = true
}
muGRPCLoggerConfigured.Unlock()
}
================================================
FILE: pkg/logutil/logger_native.go
================================================
package logutil
import (
"fmt"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type nativeCore struct {
subsystem string
enc zapcore.Encoder
}
func NewNativeDriverCore(subsystem string, enc zapcore.Encoder) zapcore.Core {
return &nativeCore{subsystem: subsystem, enc: enc}
}
func (nc *nativeCore) Enabled(zapcore.Level) bool {
return true
}
func (nc *nativeCore) With([]zapcore.Field) zapcore.Core {
return &nativeCore{enc: nc.enc}
}
func (nc *nativeCore) Check(entry zapcore.Entry, checked *zapcore.CheckedEntry) *zapcore.CheckedEntry {
return checked.AddCore(entry, nc)
}
func (nc *nativeCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
buff, err := nc.enc.EncodeEntry(entry, fields)
if err != nil {
return err
}
NativeLog(
entry.Level,
fmt.Sprintf("%s.%s", nc.subsystem, entry.LoggerName),
buff.String(),
)
return nil
}
func (nc *nativeCore) Sync() error {
return nil
}
func NewNativeLogger(subsystem string) *zap.Logger {
// native logger
nativeEncoderConfig := zap.NewDevelopmentEncoderConfig()
nativeEncoderConfig.LevelKey = ""
nativeEncoderConfig.TimeKey = ""
nativeEncoderConfig.NameKey = ""
nativeEncoderConfig.CallerKey = ""
nativeEncoder := zapcore.NewConsoleEncoder(nativeEncoderConfig)
core := NewNativeDriverCore(subsystem, nativeEncoder)
// create logger
logger := zap.New(core)
return logger
}
================================================
FILE: pkg/logutil/logger_native_android.go
================================================
//go:build android
package logutil
/*
#cgo LDFLAGS: -llog
#include
*/
import "C"
import (
"fmt"
"go.uber.org/zap/zapcore"
)
func NativeLog(logLevel zapcore.Level, namespace string, message string) {
var level C.int = C.ANDROID_LOG_INFO
switch logLevel {
case zapcore.DebugLevel:
level = C.ANDROID_LOG_DEBUG
case zapcore.InfoLevel:
level = C.ANDROID_LOG_INFO
case zapcore.WarnLevel:
level = C.ANDROID_LOG_WARN
case zapcore.ErrorLevel:
level = C.ANDROID_LOG_ERROR
}
C.__android_log_write(level, C.CString(namespace), C.CString(fmt.Sprintf("[%s] %s", logLevel.CapitalString(), message)))
}
================================================
FILE: pkg/logutil/logger_native_darwin.go
================================================
//go:build darwin
// +build darwin
package logutil
/*
#import
const int DEBUG = 0;
const int INFO = 1;
const int WARN = 2;
const int ERROR = 3;
void os_log_wrapper(int level, os_log_t log, char *s) {
switch (level) {
case DEBUG:
os_log_debug(log, "%{public}s", s);
break ;
case WARN:
os_log_error(log, "%{public}s", s);
break ;
case ERROR:
os_log_fault(log, "%{public}s", s);
break ;
default:
os_log_info(log, "%{public}s", s);
}
}
*/
import "C"
import (
"fmt"
"go.uber.org/zap/zapcore"
)
func NativeLog(logLevel zapcore.Level, namespace string, message string) {
var level C.int = C.INFO
switch logLevel {
case zapcore.DebugLevel:
level = C.DEBUG
case zapcore.WarnLevel:
level = C.WARN
case zapcore.ErrorLevel:
level = C.ERROR
default:
level = C.INFO
}
log := C.os_log_create(C.CString(namespace), C.CString(namespace))
C.os_log_wrapper(level, log, C.CString(fmt.Sprintf("[%s] %s", logLevel.CapitalString(), message)))
}
================================================
FILE: pkg/logutil/logger_native_other.go
================================================
//go:build !darwin && !android
package logutil
import (
"fmt"
"os"
"go.uber.org/zap/zapcore"
)
func NativeLog(logLevel zapcore.Level, namespace string, message string) {
fmt.Fprintf(os.Stderr, "[%s] [%s] %s\n", logLevel.CapitalString(), namespace, message)
}
================================================
FILE: pkg/logutil/logutil.go
================================================
package logutil
import (
"fmt"
"strings"
ipfs_log "github.com/ipfs/go-log/v2"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"moul.io/u"
"moul.io/zapfilter"
"berty.tech/weshnet/v2/pkg/errcode"
)
const (
consoleEncoding = "console"
jsonEncoding = "json"
)
func NewLogger(streams ...Stream) (*zap.Logger, func(), error) {
cores := []zapcore.Core{}
cleanup := func() {}
withIPFS := false
withIPFSDebug := false
for _, opts := range streams {
if opts.filters == "" {
continue
}
var core zapcore.Core
// configure zap
var config zap.Config
switch strings.ToLower(opts.format) {
case "":
config = zap.NewProductionConfig()
case "json":
config = zap.NewProductionConfig()
config.Development = true
config.Encoding = jsonEncoding
case "light-json":
config = zap.NewProductionConfig()
config.Encoding = jsonEncoding
config.EncoderConfig.TimeKey = ""
config.EncoderConfig.EncodeLevel = stableWidthCapitalLevelEncoder
config.Development = false
config.DisableStacktrace = true
config.Sampling = &zap.SamplingConfig{Initial: 100, Thereafter: 100}
case "light-console":
config = zap.NewDevelopmentConfig()
config.Encoding = consoleEncoding
config.EncoderConfig.TimeKey = ""
config.EncoderConfig.EncodeLevel = stableWidthCapitalLevelEncoder
config.DisableStacktrace = true
config.EncoderConfig.EncodeName = stableWidthNameEncoder
config.Development = false
config.Sampling = &zap.SamplingConfig{Initial: 100, Thereafter: 100}
case "light-color":
config = zap.NewDevelopmentConfig()
config.Encoding = consoleEncoding
config.EncoderConfig.TimeKey = ""
config.EncoderConfig.EncodeLevel = stableWidthCapitalColorLevelEncoder
config.DisableStacktrace = true
config.EncoderConfig.EncodeName = stableWidthNameEncoder
config.Development = false
config.Sampling = &zap.SamplingConfig{Initial: 100, Thereafter: 100}
case "console":
config = zap.NewDevelopmentConfig()
config.Encoding = consoleEncoding
config.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder
config.EncoderConfig.EncodeLevel = stableWidthCapitalLevelEncoder
config.DisableStacktrace = true
config.EncoderConfig.EncodeName = stableWidthNameEncoder
config.Development = true
case "color":
config = zap.NewDevelopmentConfig()
config.Encoding = consoleEncoding
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
config.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
config.EncoderConfig.EncodeLevel = stableWidthCapitalColorLevelEncoder
config.DisableStacktrace = true
config.EncoderConfig.EncodeName = stableWidthNameEncoder
config.Development = true
default:
return nil, nil, fmt.Errorf("unknown log format: %q", opts.format)
}
config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
var enc zapcore.Encoder
switch config.Encoding {
case consoleEncoding:
enc = zapcore.NewConsoleEncoder(config.EncoderConfig)
case jsonEncoding:
enc = zapcore.NewJSONEncoder(config.EncoderConfig)
}
switch opts.kind {
case typeStd:
switch opts.path {
case "":
case "stdout", "stderr":
config.OutputPaths = []string{opts.path}
default:
config.OutputPaths = []string{opts.path}
}
logger, err := config.Build()
if err != nil {
return nil, nil, err
}
core = logger.Core()
case typeRing:
ring := opts.ring.SetEncoder(enc)
core = ring
case typeFile:
writer, err := newFileWriteCloser(opts.path, opts.sessionKind)
if err != nil {
return nil, nil, errcode.ErrCode_TODO.Wrap(err)
}
w := zapcore.AddSync(writer)
core = zapcore.NewCore(enc, w, config.Level)
cleanup = u.CombineFuncs(cleanup, func() { _ = writer.Close() })
case typeCustom:
core = opts.baseLogger.Core()
default:
return nil, nil, fmt.Errorf("unknown logger type: %q", opts.kind)
}
filter, err := zapfilter.ParseRules(opts.filters)
if err != nil {
return nil, nil, err
}
filtered := zapfilter.NewFilteringCore(core, filter)
if !withIPFS && zapfilter.CheckAnyLevel(zap.New(filtered).Named("ipfs")) {
withIPFS = true
if zapfilter.CheckLevel(zap.New(filtered).Named("ipfs"), zap.DebugLevel) {
withIPFSDebug = true
}
}
cores = append(cores, filtered)
}
if len(cores) == 0 {
return zap.NewNop(), cleanup, nil
}
// combine cores
tee := zap.New(
zapcore.NewTee(cores...),
zap.AddCaller(),
)
if withIPFS {
if withIPFSDebug {
ipfs_log.SetDebugLogging()
}
ipfs_log.SetPrimaryCore(tee.Core())
} else {
ipfs_log.SetPrimaryCore(zapcore.NewNopCore())
}
cleanup = u.CombineFuncs(cleanup, func() { _ = tee.Sync() })
return tee.Named("bty"), cleanup, nil
}
================================================
FILE: pkg/logutil/logutil_test.go
================================================
package logutil_test
import (
"bufio"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/stretchr/testify/require"
"moul.io/u"
"moul.io/zapring"
"berty.tech/weshnet/v2/pkg/logutil"
)
func TestTypeStd(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
closer, err := u.CaptureStdoutAndStderr()
require.NoError(t, err)
logger, cleanup, err := logutil.NewLogger(
logutil.NewStdStream("*", "light-console", "stdout"),
)
require.NoError(t, err)
defer cleanup()
logger.Info("hello world!")
logger.Warn("hello world!")
logger.Sync()
lines := strings.Split(strings.TrimSpace(closer()), "\n")
require.Equal(t, 2, len(lines))
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:33\thello world!", lines[0])
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:34\thello world!", lines[1])
}
func TestTypeRing(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
closer, err := u.CaptureStdoutAndStderr()
require.NoError(t, err)
ring := zapring.New(10 * 1024 * 1024) // 10MB ring-buffer
defer ring.Close()
logger, cleanup, err := logutil.NewLogger(
logutil.NewRingStream("*", "light-console", ring),
)
defer cleanup()
require.NoError(t, err)
logger.Info("hello world!")
logger.Warn("hello world!")
logger.Sync()
require.Empty(t, closer())
r, w := io.Pipe()
go func() {
_, err := ring.WriteTo(w)
require.True(t, err == nil || err == io.EOF)
w.Close()
}()
scanner := bufio.NewScanner(r)
scanner.Scan()
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:59\thello world!", scanner.Text())
scanner.Scan()
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:60\thello world!", scanner.Text())
}
func TestTypeFile(t *testing.T) {
t.Run("fullpath", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
tempdir, err := os.MkdirTemp("", "logutil-file")
require.NoError(t, err)
filename := filepath.Join(tempdir, "test.log")
closer, err := u.CaptureStdoutAndStderr()
require.NoError(t, err)
logger, cleanup, err := logutil.NewLogger(
logutil.NewFileStream("*", "light-console", filename, ""),
)
require.NoError(t, err)
defer cleanup()
logger.Info("hello world!")
logger.Warn("hello world!")
logger.Sync()
require.Empty(t, closer())
content, err := os.ReadFile(filename)
require.NoError(t, err)
lines := strings.Split(string(content), "\n")
require.Equal(t, 3, len(lines))
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:98\thello world!", lines[0])
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:99\thello world!", lines[1])
require.Equal(t, "", lines[2])
})
t.Run("pattern", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
tempdir, err := os.MkdirTemp("", "logutil-file")
require.NoError(t, err)
closer, err := u.CaptureStdoutAndStderr()
require.NoError(t, err)
logger, cleanup, err := logutil.NewLogger(
logutil.NewFileStream("*", "light-console", tempdir, "just.a.test"),
)
require.NoError(t, err)
defer cleanup()
logger.Info("hello world!")
logger.Warn("hello world!")
logger.Sync()
require.Empty(t, closer())
files, err := os.ReadDir(tempdir)
require.NoError(t, err)
require.Len(t, files, 1)
content, err := os.ReadFile(filepath.Join(tempdir, files[0].Name()))
require.NoError(t, err)
lines := strings.Split(string(content), "\n")
require.Equal(t, 3, len(lines))
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:130\thello world!", lines[0])
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:131\thello world!", lines[1])
require.Equal(t, "", lines[2])
})
}
func TestMultiple(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
tempdir, err := os.MkdirTemp("", "logutil-file")
require.NoError(t, err)
defer os.RemoveAll(tempdir)
// ring
ring := zapring.New(10 * 1024 * 1024) // 10MB ring-buffer
defer ring.Close()
closer, err := u.CaptureStdoutAndStderr()
require.NoError(t, err)
logger, cleanup, err := logutil.NewLogger(
logutil.NewFileStream("*", "light-console", filepath.Join(tempdir, "test.log"), ""),
logutil.NewRingStream("*", "light-console", ring),
logutil.NewStdStream("*", "light-console", "stdout"),
)
require.NoError(t, err)
defer cleanup()
logger.Info("hello world!")
logger.Warn("hello world!")
logger.Sync()
// std
{
lines := strings.Split(strings.TrimSpace(closer()), "\n")
require.Equal(t, 2, len(lines))
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:174\thello world!", lines[0])
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:175\thello world!", lines[1])
}
// file
{
content, err := os.ReadFile(filepath.Join(tempdir, "test.log"))
require.NoError(t, err)
lines := strings.Split(string(content), "\n")
require.Equal(t, 3, len(lines))
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:174\thello world!", lines[0])
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:175\thello world!", lines[1])
require.Equal(t, "", lines[2])
}
// ring
{
r, w := io.Pipe()
go func() {
_, err := ring.WriteTo(w)
require.True(t, err == nil || err == io.EOF)
w.Close()
}()
scanner := bufio.NewScanner(r)
scanner.Scan()
require.Equal(t, "INFO \tbty \tlogutil/logutil_test.go:174\thello world!", scanner.Text())
scanner.Scan()
require.Equal(t, "WARN \tbty \tlogutil/logutil_test.go:175\thello world!", scanner.Text())
}
// FIXME: test that each logger can have its own format and filters
}
// FIXME: add unit test for NewCustomStream
================================================
FILE: pkg/logutil/private_field.go
================================================
package logutil
import (
crand "crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"sync"
"go.uber.org/zap"
)
var (
global *PrivateField
mu sync.RWMutex
)
type PrivateField struct {
Namespace []byte
Enabled bool
}
func (p *PrivateField) hash(value string) string {
hash := sha256.New()
if _, err := hash.Write(p.Namespace); err != nil {
return "unrepresentable"
}
if _, err := hash.Write([]byte(value)); err != nil {
return "unrepresentable"
}
hashed := hash.Sum(nil)
return hex.EncodeToString(hashed)
}
func (p *PrivateField) PrivateString(key string, value string) zap.Field {
if p.Enabled {
return zap.String(key, p.hash(value))
}
return zap.String(key, value)
}
func (p *PrivateField) PrivateStringer(key string, value fmt.Stringer) zap.Field {
if p.Enabled {
return zap.String(key, p.hash(value.String()))
}
return zap.Stringer(key, value)
}
func (p *PrivateField) PrivateStrings(key string, values []string) zap.Field {
if p.Enabled {
strings := make([]string, len(values))
for i := range values {
strings[i] = p.hash(values[i])
}
return zap.Strings(key, strings)
}
return zap.Strings(key, values)
}
func (p *PrivateField) PrivateAny(key string, value any) zap.Field {
if p.Enabled {
return zap.String(key, p.hash(fmt.Sprintf("%+v", value)))
}
return zap.Any(key, value)
}
func (p *PrivateField) PrivateBinary(key string, value []byte) zap.Field {
if p.Enabled {
return zap.String(key, p.hash(hex.EncodeToString(value)))
}
return zap.Binary(key, value)
}
func PrivateStrings(key string, value []string) zap.Field {
mu.RLock()
g := global
mu.RUnlock()
return g.PrivateStrings(key, value)
}
func PrivateString(key string, value string) zap.Field {
mu.RLock()
g := global
mu.RUnlock()
return g.PrivateString(key, value)
}
func PrivateStringer(key string, value fmt.Stringer) zap.Field {
mu.RLock()
g := global
mu.RUnlock()
return g.PrivateStringer(key, value)
}
func PrivateAny(key string, value any) zap.Field {
mu.RLock()
g := global
mu.RUnlock()
return g.PrivateAny(key, value)
}
func PrivateBinary(key string, value []byte) zap.Field {
mu.RLock()
g := global
mu.RUnlock()
return g.PrivateBinary(key, value)
}
func SetGlobal(namespace []byte, enabled bool) {
mu.Lock()
global = &PrivateField{
Enabled: enabled,
Namespace: namespace,
}
mu.Unlock()
}
func DisablePrivateFields() {
SetGlobal(nil, false)
}
func init() { // nolint:gochecknoinits
namespace := make([]byte, 32)
_, err := crand.Reader.Read(namespace)
if err != nil {
panic(err)
}
SetGlobal(namespace, true)
}
================================================
FILE: pkg/logutil/stream.go
================================================
package logutil
import (
"go.uber.org/zap"
"moul.io/zapring"
)
const (
typeStd = "std"
typeRing = "ring"
typeFile = "file"
typeCustom = "custom"
)
type Stream struct {
kind string
filters string
format string
path string
ring *zapring.Core
sessionKind string
baseLogger *zap.Logger
}
func NewStdStream(filters, format, path string) Stream {
return Stream{
kind: typeStd,
filters: filters,
format: format,
path: path,
}
}
func NewRingStream(filters, format string, ring *zapring.Core) Stream {
return Stream{
kind: typeRing,
filters: filters,
format: format,
ring: ring,
}
}
// NewFileStream creates a new file stream backed by Lumberjack with sane default values.
//
// Usually, Lumberjack is used as a rolling log file and is intended to be reused from a session to another,
// In Berty, we want one file per session named with the start time instead of the rotation time.
//
// If the provided path is a directory, it will create files in that directory with the following pattern:
// `/-.log`.
//
// If the provided path is a path finishing with ".log", then, the path will be taken as it,
// instead of creating a new file, it will append new lines to the existing one;
// this can be particularly useful to keep a `tail -f` running.
func NewFileStream(filters, format, path, sessionKind string) Stream {
return Stream{
kind: typeFile,
filters: filters,
format: format,
path: path,
sessionKind: sessionKind,
}
}
func NewCustomStream(filters string, logger *zap.Logger) Stream {
return Stream{
kind: typeCustom,
filters: filters,
baseLogger: logger,
}
}
================================================
FILE: pkg/multipeer-connectivity-driver/bridge_darwin.go
================================================
//go:build darwin && cgo && !catalyst && !noproximitytransport
package mc
import (
"go.uber.org/zap"
native "berty.tech/weshnet/v2/pkg/multipeer-connectivity-driver/driver"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
const Supported = true
type Driver struct {
protocolCode int
protocolName string
defaultAddr string
}
// Driver is a proximity.ProximityDriver
var _ proximity.ProximityDriver = (*Driver)(nil)
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
if logger == nil {
logger = zap.NewNop()
} else {
logger = logger.Named("MC")
logger.Debug("NewDriver()")
native.MCUseExternalLogger()
}
native.Logger = logger
native.ProtocolName = ProtocolName
return &Driver{
protocolCode: ProtocolCode,
protocolName: ProtocolName,
defaultAddr: DefaultAddr,
}
}
func (d *Driver) Start(localPID string) {
native.Start(localPID)
}
func (d *Driver) Stop() {
native.Stop()
}
func (d *Driver) DialPeer(remotePID string) bool {
return native.DialPeer(remotePID)
}
func (d *Driver) SendToPeer(remotePID string, payload []byte) bool {
return native.SendToPeer(remotePID, payload)
}
func (d *Driver) CloseConnWithPeer(remotePID string) {
native.CloseConnWithPeer(remotePID)
}
func (d *Driver) ProtocolCode() int {
return d.protocolCode
}
func (d *Driver) ProtocolName() string {
return d.protocolName
}
func (d *Driver) DefaultAddr() string {
return d.defaultAddr
}
================================================
FILE: pkg/multipeer-connectivity-driver/bridge_unsupported.go
================================================
//go:build !darwin || (darwin && !cgo) || catalyst || noproximitytransport
package mc
import (
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
const Supported = false
// Noop implementation for platform that are not Darwin
func NewDriver(logger *zap.Logger) proximity.ProximityDriver {
logger = logger.Named("MC")
logger.Info("NewDriver(): incompatible system")
return proximity.NewNoopProximityDriver(ProtocolCode, ProtocolName, DefaultAddr)
}
================================================
FILE: pkg/multipeer-connectivity-driver/const.go
================================================
package mc
const (
DefaultAddr = "/mc/Qmeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
ProtocolCode = 0x0043
ProtocolName = "mc"
)
================================================
FILE: pkg/multipeer-connectivity-driver/driver/Logger.h
================================================
//
// Logger.h
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 08/12/2021.
//
#import
#import
NS_ASSUME_NONNULL_BEGIN
#define SENSITIVE_MASK @"####"
// Log levels
typedef NS_ENUM(uint8_t, level) {
Debug,
Info,
Warn,
Error,
};
@interface MC_Logger : NSObject
@property (nonatomic, strong, nonnull) os_log_t logger;
@property (readwrite) BOOL showSensitiveData;
@property (readwrite) BOOL useExternalLogger;
- (instancetype __nonnull)initLocalLoggerWithSubSystem:(const char *)subSystem andCategorie:(const char*)categorie showSensitiveData:(BOOL)showSensitiveData;
- (instancetype __nonnull)initWithExternalLoggerAndShowSensitiveData:(BOOL)showSensitiveData;
- (void)log:(enum level)level withFormat:(NSString *__nonnull)format withArgs:(va_list)args;
- (void)d:(NSString *__nonnull)format, ...;
- (void)i:(NSString *__nonnull)format, ...;
- (void)e:(NSString *__nonnull)format, ...;
- (BOOL)showSensitiveData;
- (BOOL)useExternalLogger;
- (NSString *__nonnull)SensitiveNSObject:(id __nonnull)data;
- (NSString *__nonnull)SensitiveString:(const char *)data;
@end
@compatibility_alias Logger MC_Logger;
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/multipeer-connectivity-driver/driver/Logger.m
================================================
// +build darwin,!noproximitytransport
//
// Logger.m
// BertyBridgeDemo
//
// Created by Rémi BARBERO on 08/12/2021.
//
#import
#import "Logger.h"
#import "mc-driver.h"
@implementation Logger
- (instancetype __nonnull)initLocalLoggerWithSubSystem:(const char *)subSystem andCategorie:(const char*)categorie showSensitiveData:(BOOL)showSensitiveData {
self = [super init];
if (self) {
_logger = os_log_create(subSystem, categorie);
_useExternalLogger = FALSE;
_showSensitiveData = showSensitiveData;
}
return self;
}
- (instancetype __nonnull)initWithExternalLoggerAndShowSensitiveData:(BOOL)showSensitiveData {
self = [super init];
if (self) {
_logger = nil;
_useExternalLogger = TRUE;
_showSensitiveData = showSensitiveData;
}
return self;
}
- (void)log:(enum level)level withFormat:(NSString *__nonnull)format withArgs:(va_list)args {
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
if (self.useExternalLogger) {
MCBridgeLog(level, message);
} else {
if (self.logger == nil) {
NSLog(@"log error: logger is not set");
} else {
uint8_t osLevel;
switch (level) {
case Debug:
osLevel = OS_LOG_TYPE_DEBUG;
break ;
case Info:
osLevel = OS_LOG_TYPE_INFO;
break ;
case Error:
osLevel = OS_LOG_TYPE_ERROR;
break ;
default:
osLevel = OS_LOG_TYPE_DEFAULT;
break ;
}
os_log_with_type(self.logger, osLevel, "%@", message);
}
}
[message release];
}
- (void)d:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Debug withFormat:format withArgs:args];
va_end(args);
}
- (void)i:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Info withFormat:format withArgs:args];
va_end(args);
}
- (void)e:(NSString *__nonnull)format, ... {
va_list args;
va_start(args, format);
[self log:Error withFormat:format withArgs:args];
va_end(args);
}
- (NSString *__nonnull)SensitiveNSObject:(id __nonnull)data {
if (self.showSensitiveData) {
return [NSString stringWithFormat:@"%@", data];
} else {
return SENSITIVE_MASK;
}
}
- (NSString *__nonnull)SensitiveString:(const char *)data {
if (data == nil) {
return @"";
}
if (self.showSensitiveData) {
return [NSString stringWithFormat:@"%s", data];
} else {
return SENSITIVE_MASK;
}
}
@end
================================================
FILE: pkg/multipeer-connectivity-driver/driver/MCManager.h
================================================
//
// MCManager.h
// driver
//
// Created by Rémi BARBERO on 31/03/2020.
// Copyright © 2020 Rémi BARBERO. All rights reserved.
//
#import
#import
#import "Logger.h"
NS_ASSUME_NONNULL_BEGIN
@interface MCManager : NSObject
@property (nonatomic, strong) MCSession *mSession;
@property (nonatomic, strong, nullable) MCNearbyServiceAdvertiser *mServiceAdvertiser;
@property (nonatomic, strong, nullable) MCNearbyServiceBrowser *mServiceBrowser;
@property (nonatomic, strong) MCPeerID *mPeerID;
@property (nonatomic, strong, nullable) Logger *logger;
- (MCPeerID *)getMCPeerID:(NSString *)peerID;
- (id)init:(NSString *)peerID useExternalLogger:(BOOL)useExternalLogger;
- (int)startServiceAdvertiser;
- (int)startServiceBrowser;
- (void)stopServiceAdvertiser;
- (void)stopServiceBrowser;
- (void)closeSessions;
- (int)sendToPeer:(NSString *)peerID data:(NSData *)data;
- (MCPeerID *)getPeer:(NSString *)peerID;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: pkg/multipeer-connectivity-driver/driver/MCManager.m
================================================
// +build darwin,!noproximitytransport
#import
#import "MCManager.h"
#import "mc-driver.h"
NSString *BERTY_DRIVER_MC = @"berty-mc";
@implementation MCManager
// MCPeerID must be unique and stable over time so we need to archive it after
// the first time it's created.
// https://developer.apple.com/documentation/multipeerconnectivity/mcpeerid
- (MCPeerID *)getMCPeerID:(NSString *)appPID {
NSString *kAppPID = @"berty-peerID";
NSString *kPIDData = @"berty-PIDData";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *oldAppPID = [defaults stringForKey:kAppPID];
MCPeerID *peerID;
NSData *peerIDData;
NSError *error;
if ([oldAppPID isEqualToString:appPID]) {
peerIDData = [defaults dataForKey:kPIDData];
if ((peerID = [NSKeyedUnarchiver unarchivedObjectOfClass:[MCPeerID class] fromData:peerIDData error:&error])) {
return (peerID);
}
[self.logger d:@"getMCPeerID unarchive error: %@", error];
}
peerID = [[MCPeerID alloc] initWithDisplayName:appPID];
if ((peerIDData = [NSKeyedArchiver archivedDataWithRootObject:peerID requiringSecureCoding:true error:&error])) {
[defaults setObject:peerIDData forKey:kPIDData];
[defaults setObject:appPID forKey:kAppPID];
[defaults synchronize];
} else {
[self.logger d:@"getMCPeerID archive error: %@", error];
}
return (peerID);
}
- (id)init:(NSString *)peerID useExternalLogger:(BOOL)useExternalLogger {
if (self = [super init]) {
_mPeerID = [[MCPeerID alloc] initWithDisplayName:peerID];
BOOL showSensitiveData = FALSE;
if (useExternalLogger) {
_logger = [[Logger alloc] initWithExternalLoggerAndShowSensitiveData:showSensitiveData];
} else {
_logger = [[Logger alloc] initLocalLoggerWithSubSystem:"tech.berty.bty" andCategorie:"MC" showSensitiveData:showSensitiveData];
}
if (!(self.mSession = [[MCSession alloc] initWithPeer:self.mPeerID securityIdentity:nil encryptionPreference:MCEncryptionRequired])) {
[self.logger d:@"MCSession init failed"];
return (self = nil);
}
self.mSession.delegate = self;
}
return (self);
}
- (int)startServiceAdvertiser {
if (!(self.mServiceAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.mPeerID discoveryInfo:nil serviceType:BERTY_DRIVER_MC])) {
[self.logger d:@"MCNearbyServiceAdvertiser init failed"];
return (0);
}
self.mServiceAdvertiser.delegate = self;
[self.mServiceAdvertiser startAdvertisingPeer];
return (1);
}
- (int)startServiceBrowser {
if (!(self.mServiceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.mPeerID serviceType:BERTY_DRIVER_MC])) {
[self.logger d:@"MCNearbyServiceBrowser init failed"];
return (0);
}
self.mServiceBrowser.delegate = self;
[self.mServiceBrowser startBrowsingForPeers];
return (1);
}
- (void)stopServiceAdvertiser {
[self.mServiceAdvertiser stopAdvertisingPeer];
self.mServiceAdvertiser = nil;
}
- (void)stopServiceBrowser {
[self.mServiceBrowser stopBrowsingForPeers];
self.mServiceBrowser = nil;
}
- (void)closeSessions {
[self.mSession disconnect];
}
- (int)sendToPeer: (NSString *)peerID data:(NSData *)data {
NSError *error = nil;
MCPeerID *peer;
if ((peer = [self getPeer:peerID])) {
NSArray *array = @[peer];
if ([self.mSession sendData:data toPeers:array withMode:MCSessionSendDataReliable error:&error]) {
return (1);
}
NSString *description = [error localizedDescription];
NSString *reason = [error localizedFailureReason] ?
[error localizedFailureReason] :
NSLocalizedString(@"Unknown reason", nil);
[self.logger d:@"sendToPeer error: %@: %@", description, reason];
}
return (0);
}
- (MCPeerID *)getPeer:(NSString *)peerID {
NSArray *peers = [self.mSession connectedPeers];
for (MCPeerID *peer in peers) {
if ([[peer displayName] isEqualToString:peerID]) {
return (peer);
}
}
return (nil);
}
/*
MCSessionDelegate
*/
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
switch (state) {
case MCSessionStateConnecting:
[self.logger d:@"Connecting: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
break;
case MCSessionStateConnected:
[self.logger i:@"Connected: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
BridgeHandleFoundPeer([peerID displayName]);
break;
case MCSessionStateNotConnected:
[self.logger i:@"Not connected: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
BridgeHandleLostPeer([peerID displayName]);
break;
}
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
BridgeReceiveFromPeer([peerID displayName], data);
}
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress{
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error{
}
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID{
}
/*
MCNearbyServiceAdvertiserDelegate
*/
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error {
[self.logger d:@"didNotStartAdvertisingPeer: %@", error];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession * _Nullable))invitationHandler {
[self.logger d:@"didReceiveInvationFromPeer: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
invitationHandler(true, self.mSession);
}
/*
MCNearbyServiceBrowserDelegate
*/
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
[self.logger d:@"lostPeer: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error {
[self.logger d:@"didNotStartBrowsingForPeers: %@", error];
}
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {
[self.logger d:@"foundPeer: %@", [self.logger SensitiveNSObject:[peerID displayName]]];
[browser invitePeer:peerID toSession:self.mSession withContext:nil timeout:10];
}
@end
================================================
FILE: pkg/multipeer-connectivity-driver/driver/cgo_bridge.go
================================================
//go:build darwin && cgo && !catalyst && !noproximitytransport
// +build darwin,cgo,!catalyst,!noproximitytransport
package driver
/*
#cgo CFLAGS: -x objective-c
#cgo darwin LDFLAGS: -framework Foundation -framework MultipeerConnectivity
#include
#include "mc-driver.h"
*/
import "C"
import (
"fmt"
"os"
"unsafe"
"go.uber.org/zap"
proximity "berty.tech/weshnet/v2/pkg/proximitytransport"
)
var (
Logger *zap.Logger
ProtocolName string
)
//export MCHandleFoundPeer
func MCHandleFoundPeer(remotePID *C.char) int {
goPID := C.GoString(remotePID)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return 0
}
if t.HandleFoundPeer(goPID) {
return 1
}
return 0
}
//export MCHandleLostPeer
func MCHandleLostPeer(remotePID *C.char) {
goPID := C.GoString(remotePID)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return
}
t.HandleLostPeer(goPID)
}
//export MCReceiveFromPeer
func MCReceiveFromPeer(remotePID *C.char, payload unsafe.Pointer, length C.int) {
goPID := C.GoString(remotePID)
goPayload := C.GoBytes(payload, length)
proximity.TransportMapMutex.RLock()
t, ok := proximity.TransportMap[ProtocolName]
proximity.TransportMapMutex.RUnlock()
if !ok {
return
}
t.ReceiveFromPeer(goPID, goPayload)
}
//export MCLog
func MCLog(level C.enum_level, message *C.char) { //nolint:golint
if Logger == nil {
fmt.Fprintf(os.Stderr, "logger not found\n")
return
}
goMessage := C.GoString(message)
switch level {
case C.Debug:
Logger.Debug(goMessage)
case C.Info:
Logger.Info(goMessage)
case C.Warn:
Logger.Warn(goMessage)
case C.Error:
Logger.Error(goMessage)
}
}
func Start(localPID string) {
cPID := C.CString(localPID)
defer C.free(unsafe.Pointer(cPID))
C.StartMCDriver(cPID)
}
func Stop() {
C.StopMCDriver()
}
func DialPeer(remotePID string) bool {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
return C.DialPeer(cPID) == 1
}
func SendToPeer(remotePID string, payload []byte) bool {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
cPayload := C.CBytes(payload)
defer C.free(cPayload)
return C.SendToPeer(cPID, cPayload, C.int(len(payload))) == 1
}
func CloseConnWithPeer(remotePID string) {
cPID := C.CString(remotePID)
defer C.free(unsafe.Pointer(cPID))
C.CloseConnWithPeer(cPID)
}
func MCUseExternalLogger() {
C.MCUseExternalLogger()
}
================================================
FILE: pkg/multipeer-connectivity-driver/driver/mc-driver.h
================================================
//
// mc-driver.h
// driver
//
// Created by Rémi BARBERO on 30/03/2020.
// Copyright © 2020 Rémi BARBERO. All rights reserved.
//
#import
#import
#import "Logger.h"
void StartMCDriver(char *localPId);
void StopMCDriver(void);
int SendToPeer(char *remotePID, void *payload, int length);
int DialPeer(char *remotePID);
void CloseConnWithPeer(char *remotePID);
int BridgeHandleFoundPeer(NSString *remotePID);
void BridgeHandleLostPeer(NSString *remotePID);
void BridgeReceiveFromPeer(NSString *remotePID, NSData *payload);
void MCBridgeLog(enum level level, NSString *message);
void MCUseExternalLogger(void);
================================================
FILE: pkg/multipeer-connectivity-driver/driver/mc-driver.m
================================================
// +build darwin,!noproximitytransport
#import
#import "mc-driver.h"
#import "MCManager.h"
// This functions are Go functions so they aren't defined here
extern int MCHandleFoundPeer(char *);
extern void MCHandleLostPeer(char *);
extern void MCReceiveFromPeer(char *, void *, unsigned long);
extern void MCLog(enum level level, const char *message);
int driverStarted = 0;
BOOL gMCUseExternalLogger = FALSE;
// MCManager must be unique
static MCManager *gMCManager = nil;
MCManager* getMCManager(NSString *peerID) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"init MCManager");
gMCManager = [[MCManager alloc] init:peerID useExternalLogger:gMCUseExternalLogger];
});
return gMCManager;
}
void StartMCDriver(char *localPID) {
if (!driverStarted) {
NSLog(@"StartMCDriver()");
NSString *cPID = [[NSString alloc] initWithUTF8String:localPID];
if (!getMCManager(cPID)) {
NSLog(@"StartMCDriver failed");
return ;
}
[gMCManager startServiceAdvertiser];
[gMCManager startServiceBrowser];
driverStarted = 1;
}
}
void StopMCDriver() {
if (driverStarted) {
NSLog(@"StopMCDriver()");
[gMCManager stopServiceAdvertiser];
[gMCManager stopServiceBrowser];
[gMCManager closeSessions];
driverStarted = 0;
}
}
int SendToPeer(char *remotePID, void *payload, int length) {
if (driverStarted) {
NSString *cPID = [[NSString alloc] initWithUTF8String:remotePID];
NSData *cPayload = [[NSData alloc] initWithBytes:payload length:length];
return ([gMCManager sendToPeer:cPID data:cPayload]);
}
return (0);
}
int DialPeer(char *remotePID) {
NSString *cPID = [[NSString alloc] initWithUTF8String:remotePID];
if (!driverStarted || ![gMCManager getPeer:cPID]) {
return (0);
}
return (1);
}
// nothing to do because API doesn't provide any functions
void CloseConnWithPeer(char *peerID) {
}
// Use MCBridgeLog to write logs to the external logger
void MCUseExternalLogger(void) {
gMCUseExternalLogger = TRUE;
}
int BridgeHandleFoundPeer(NSString *remotePID) {
char *cPID = (char *)[remotePID UTF8String];
if (MCHandleFoundPeer(cPID)) {
return (1);
}
return (0);
}
void BridgeHandleLostPeer(NSString *remotePID) {
char *cPID = (char *)[remotePID UTF8String];
MCHandleLostPeer(cPID);
}
void BridgeReceiveFromPeer(NSString *remotePID, NSData *payload) {
char *cPID = (char *)[remotePID UTF8String];
char *cPayload = (char *)[payload bytes];
int length = (int)[payload length];
MCReceiveFromPeer(cPID, cPayload, length);
}
// Write logs to the external logger
void MCBridgeLog(enum level level, NSString *message) {
char *cMessage = (char *)[message UTF8String];
MCLog(level, cMessage);
}
================================================
FILE: pkg/multipeer-connectivity-driver/example_test.go
================================================
package mc_test
================================================
FILE: pkg/multipeer-connectivity-driver/init.go
================================================
package mc
import (
ma "github.com/multiformats/go-multiaddr"
)
// Add MC to the list of libp2p's multiaddr protocols
// FIXME: remove this init
func init() { // nolint:gochecknoinits
err := ma.AddProtocol(newProtocol())
if err != nil {
panic(err)
}
}
================================================
FILE: pkg/multipeer-connectivity-driver/multiaddr.go
================================================
package mc
import (
peer "github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
func newProtocol() ma.Protocol {
transcoderMC := ma.NewTranscoderFromFunctions(mcStB, mcBtS, mcVal)
return ma.Protocol{
Name: ProtocolName,
Code: ProtocolCode,
VCode: ma.CodeToVarint(ProtocolCode),
Size: -1,
Path: false,
Transcoder: transcoderMC,
}
}
func mcStB(s string) ([]byte, error) {
_, err := peer.Decode(s)
if err != nil {
return nil, err
}
return []byte(s), nil
}
func mcBtS(b []byte) (string, error) {
_, err := peer.Decode(string(b))
if err != nil {
return "", err
}
return string(b), nil
}
func mcVal(b []byte) error {
_, err := peer.Decode(string(b))
return err
}
================================================
FILE: pkg/netmanager/connectivity.go
================================================
package netmanager
import (
"fmt"
"strings"
)
type ConnectivityState int
const (
ConnectivityStateUnknown ConnectivityState = iota
ConnectivityStateOff
ConnectivityStateOn
)
func (cs ConnectivityState) String() string {
switch cs {
case ConnectivityStateUnknown:
return "unknown"
case ConnectivityStateOff:
return "off"
case ConnectivityStateOn:
return "on"
default:
return "error"
}
}
func ParseConnectivityState(s string) (ConnectivityState, error) {
switch strings.ToLower(s) {
case "unknown":
return ConnectivityStateUnknown, nil
case "off":
return ConnectivityStateOff, nil
case "on":
return ConnectivityStateOn, nil
default:
return ConnectivityStateUnknown, fmt.Errorf("invalid connectivity state (unknown/off/on): %q", s)
}
}
type ConnectivityNetType int
const (
ConnectivityNetUnknown ConnectivityNetType = iota
ConnectivityNetNone
ConnectivityNetWifi
ConnectivityNetEthernet
ConnectivityNetCellular
)
func (cnt ConnectivityNetType) String() string {
switch cnt {
case ConnectivityNetUnknown:
return "unknown"
case ConnectivityNetNone:
return "none"
case ConnectivityNetWifi:
return "wifi"
case ConnectivityNetEthernet:
return "ethernet"
case ConnectivityNetCellular:
return "cellular"
default:
return "error"
}
}
func ParseConnectivityNetType(s string) (ConnectivityNetType, error) {
switch strings.ToLower(s) {
case "unknown":
return ConnectivityNetUnknown, nil
case "none":
return ConnectivityNetNone, nil
case "wifi":
return ConnectivityNetWifi, nil
case "ethernet":
return ConnectivityNetEthernet, nil
case "cellular":
return ConnectivityNetCellular, nil
default:
return ConnectivityNetUnknown, fmt.Errorf("invalid connectivity net type (unknown/none/wifi/ethernet/cellular): %q", s)
}
}
type ConnectivityCellularType int
const (
ConnectivityCellularUnknown ConnectivityCellularType = iota
ConnectivityCellularNone
ConnectivityCellular2G
ConnectivityCellular3G
ConnectivityCellular4G
ConnectivityCellular5G
)
func (cct ConnectivityCellularType) String() string {
switch cct {
case ConnectivityCellularUnknown:
return "unknown"
case ConnectivityCellularNone:
return "none"
case ConnectivityCellular2G:
return "2G"
case ConnectivityCellular3G:
return "3G"
case ConnectivityCellular4G:
return "4G"
case ConnectivityCellular5G:
return "5G"
default:
return "error"
}
}
func ParseConnectivityCellularType(s string) (ConnectivityCellularType, error) {
switch strings.ToLower(s) {
case "unknown":
return ConnectivityCellularUnknown, nil
case "none":
return ConnectivityCellularNone, nil
case "2g":
return ConnectivityCellular2G, nil
case "3g":
return ConnectivityCellular3G, nil
case "4g":
return ConnectivityCellular4G, nil
case "5g":
return ConnectivityCellular5G, nil
default:
return ConnectivityCellularUnknown, fmt.Errorf("invalid connectivity cellular type (unknown/none/2g/3g/4g/5g): %q", s)
}
}
type ConnectivityInfo struct {
// False when the device is not connected to a network.
State ConnectivityState
// True when the device is connected to a metered network.
Metering ConnectivityState
// True when the device is connected to a bluetooth network.
Bluetooth ConnectivityState
// The type of the network the device is connected to: wifi/ethernet/cellular.
NetType ConnectivityNetType
// If the device is connected to a cellular network:
// The type of the cellular network the device is connected to: 2G/3G/4G/5G.
CellularType ConnectivityCellularType
}
func (ci ConnectivityInfo) String() string {
return fmt.Sprint("ConnectivityInfo{ ",
"State: ", ci.State.String(), ", ",
"Metering: ", ci.Metering.String(), ", ",
"Bluetooth: ", ci.Bluetooth.String(), ", ",
"NetType: ", ci.NetType.String(), ", ",
"CellularType: ", ci.CellularType.String(),
" }")
}
================================================
FILE: pkg/netmanager/netmanager.go
================================================
package netmanager
import (
"context"
"sync"
"berty.tech/weshnet/v2/internal/notify"
)
type NetManager struct {
currentState ConnectivityInfo
locker *sync.RWMutex
notify *notify.Notify
}
type EventType uint
const (
ConnectivityStateChanged EventType = 1 << iota
ConnectivityMeteringChanged
ConnectivityBluetoothChanged
ConnectivityNetTypeChanged
ConnectivityCellularTypeChanged
ConnectivityChanged = 0 |
ConnectivityStateChanged |
ConnectivityMeteringChanged |
ConnectivityBluetoothChanged |
ConnectivityNetTypeChanged |
ConnectivityCellularTypeChanged
)
func (t EventType) Has(other EventType) bool {
return (t & other) == other
}
func NewNetManager(initialState ConnectivityInfo) *NetManager {
var locker sync.RWMutex
return &NetManager{
currentState: initialState,
locker: &locker,
notify: notify.New(&locker),
}
}
// UpdateState update the current state of the Manager
func (m *NetManager) UpdateState(state ConnectivityInfo) {
m.locker.Lock()
if m.currentState != state {
m.currentState = state
m.notify.Broadcast()
}
m.locker.Unlock()
}
// WaitForStateChange waits until the currentState changes from sourceState or ctx expires.
// The eventType argument allow you to filter out the event you want to wait for.
// A true value is returned in former case and false in latter.
// The EventType is also returned to know which events has been triggered.
func (m *NetManager) WaitForStateChange(ctx context.Context, sourceState *ConnectivityInfo, eventType EventType) (bool, EventType) {
if ctx.Err() != nil {
return false, 0
}
m.locker.Lock()
defer m.locker.Unlock()
var currentEventType EventType
ok := true
for ok {
currentEventType = 0
if sourceState.State != m.currentState.State {
currentEventType |= ConnectivityStateChanged
}
if sourceState.Metering != m.currentState.Metering {
currentEventType |= ConnectivityMeteringChanged
}
if sourceState.Bluetooth != m.currentState.Bluetooth {
currentEventType |= ConnectivityBluetoothChanged
}
if sourceState.NetType != m.currentState.NetType {
currentEventType |= ConnectivityNetTypeChanged
}
if sourceState.CellularType != m.currentState.CellularType {
currentEventType |= ConnectivityCellularTypeChanged
}
if (eventType & currentEventType) != 0 {
break
}
// wait until state has been changed or context has been cancel
ok = m.notify.Wait(ctx)
}
return ok, currentEventType
}
// GetCurrentState return the current state of the Manager
func (m *NetManager) GetCurrentState() (state ConnectivityInfo) {
m.locker.RLock()
state = m.currentState
m.locker.RUnlock()
return
}
================================================
FILE: pkg/netmanager/netmanager_noop.go
================================================
package netmanager
func NewNoopNetManager() *NetManager {
return NewNetManager(ConnectivityInfo{
State: ConnectivityStateOn,
NetType: ConnectivityNetWifi,
})
}
================================================
FILE: pkg/netmanager/netmanager_test.go
================================================
package netmanager
import (
"context"
"testing"
"github.com/stretchr/testify/require"
)
func TestNewNetManager(t *testing.T) {
initial := ConnectivityInfo{
State: ConnectivityStateOn,
NetType: ConnectivityNetWifi,
Bluetooth: ConnectivityStateOn,
}
netmanager := NewNetManager(initial)
require.Equal(t, initial, netmanager.GetCurrentState())
initial.State = ConnectivityStateOff
require.NotEqual(t, initial, netmanager.GetCurrentState())
}
func TestNetManagerSingleUpdate(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := ConnectivityInfo{
State: ConnectivityStateOn,
}
state := ConnectivityInfo{}
netmanager := NewNetManager(state)
netmanager.UpdateState(a)
require.Equal(t, a, netmanager.GetCurrentState())
ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged)
require.Equal(t, a, netmanager.GetCurrentState())
require.True(t, ok)
require.Equal(t, ConnectivityStateChanged, eventType)
}
func TestNetManagerDoubleUpdate(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := ConnectivityInfo{
State: ConnectivityStateOn,
}
b := ConnectivityInfo{
State: ConnectivityStateOff,
}
state := ConnectivityInfo{}
netmanager := NewNetManager(state)
netmanager.UpdateState(a)
require.Equal(t, a, netmanager.GetCurrentState())
netmanager.UpdateState(b)
require.Equal(t, b, netmanager.GetCurrentState())
ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityChanged)
require.Equal(t, b, netmanager.GetCurrentState())
require.True(t, ok)
require.Equal(t, ConnectivityStateChanged, eventType)
}
func TestNetManagerFilterUpdate(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := ConnectivityInfo{
State: ConnectivityStateOff,
}
b := ConnectivityInfo{
State: ConnectivityStateOn,
NetType: ConnectivityNetCellular,
CellularType: ConnectivityCellular3G,
}
state := ConnectivityInfo{}
netmanager := NewNetManager(state)
netmanager.UpdateState(a)
require.Equal(t, a, netmanager.GetCurrentState())
netmanager.UpdateState(b)
require.Equal(t, b, netmanager.GetCurrentState())
ok, eventType := netmanager.WaitForStateChange(ctx, &state, ConnectivityCellularTypeChanged)
require.Equal(t, b, netmanager.GetCurrentState())
require.True(t, ok)
require.Equal(t, ConnectivityStateChanged|ConnectivityNetTypeChanged|ConnectivityCellularTypeChanged, eventType)
}
================================================
FILE: pkg/outofstoremessage/outofstoremessage_test.go
================================================
package outofstoremessage
import (
"context"
"testing"
"time"
"github.com/ipfs/go-cid"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
)
func Test_sealPushMessage_OutOfStoreReceive(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{}, nil)
defer cancel()
g, _, err := weshnet.NewGroupMultiMember()
require.NoError(t, err)
s := tp.Service
gPK, err := g.GetPubKey()
require.NoError(t, err)
_, err = s.MultiMemberGroupJoin(ctx, &protocoltypes.MultiMemberGroupJoin_Request{Group: g})
require.NoError(t, err)
gPKRaw, err := gPK.Raw()
require.NoError(t, err)
_, err = s.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPk: gPKRaw})
require.NoError(t, err)
gc, err := s.(weshnet.ServiceMethods).GetContextGroupForID(g.PublicKey)
require.NoError(t, err)
otherSecretStore, cancel := createVirtualOtherPeerSecrets(t, ctx, gc)
defer cancel()
testPayload := []byte("test payload")
envBytes, err := otherSecretStore.SealEnvelope(ctx, g, testPayload)
require.NoError(t, err)
env, headers, err := otherSecretStore.OpenEnvelopeHeaders(envBytes, g)
require.NoError(t, err)
oosMsgEnv, err := otherSecretStore.SealOutOfStoreMessageEnvelope(cid.Undef, env, headers, g)
require.NoError(t, err)
oosMsgEnvBytes, err := proto.Marshal(oosMsgEnv)
require.NoError(t, err)
outOfStoreMessage, group, clearPayload, alreadyDecrypted, err := gc.SecretStore().OpenOutOfStoreMessage(ctx, oosMsgEnvBytes)
require.NoError(t, err)
require.Equal(t, g.PublicKey, group.PublicKey)
require.Equal(t, g.Secret, group.Secret)
require.Equal(t, g.SecretSig, group.SecretSig)
require.Equal(t, g.GroupType, group.GroupType)
require.Equal(t, g.SignPub, group.SignPub)
require.Equal(t, g.LinkKey, group.LinkKey)
require.Equal(t, g.LinkKeySig, group.LinkKeySig)
require.Equal(t, []byte("test payload"), clearPayload)
require.False(t, alreadyDecrypted)
require.Equal(t, headers.Counter, outOfStoreMessage.Counter)
require.Equal(t, headers.DevicePk, outOfStoreMessage.DevicePk)
require.Equal(t, headers.Sig, outOfStoreMessage.Sig)
require.Equal(t, env.Message, outOfStoreMessage.EncryptedPayload)
}
func Test_OutOfStoreMessageFlow(t *testing.T) {
message := []byte("test message")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
tp, cancel := weshnet.NewTestingProtocol(ctx, t, &weshnet.TestingOpts{Logger: logger}, nil)
defer cancel()
g, _, err := weshnet.NewGroupMultiMember()
require.NoError(t, err)
s := tp.Service
gPK, err := g.GetPubKey()
require.NoError(t, err)
_, err = s.MultiMemberGroupJoin(ctx, &protocoltypes.MultiMemberGroupJoin_Request{Group: g})
require.NoError(t, err)
gPKRaw, err := gPK.Raw()
require.NoError(t, err)
_, err = s.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{GroupPk: gPKRaw})
require.NoError(t, err)
// send a message
sendReply, err := s.AppMessageSend(ctx, &protocoltypes.AppMessageSend_Request{
GroupPk: gPKRaw,
Payload: message,
})
require.NoError(t, err)
time.Sleep(100 * time.Millisecond)
// craft an out of store message
craftReply, err := s.OutOfStoreSeal(ctx, &protocoltypes.OutOfStoreSeal_Request{
Cid: sendReply.Cid,
GroupPublicKey: gPKRaw,
})
require.NoError(t, err)
// verify the out of store message
openReply, err := s.OutOfStoreReceive(ctx, &protocoltypes.OutOfStoreReceive_Request{
Payload: craftReply.Encrypted,
})
require.NoError(t, err)
encryptedMessage := &protocoltypes.EncryptedMessage{}
err = proto.Unmarshal(openReply.Cleartext, encryptedMessage)
require.NoError(t, err)
require.Equal(t, message, encryptedMessage.Plaintext)
}
func createVirtualOtherPeerSecrets(t testing.TB, ctx context.Context, gc *weshnet.GroupContext) (secretstore.SecretStore, func()) {
secretStore, err := secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
cleanup := func() {
_ = secretStore.Close()
}
// Manually adding another member to the group
otherMD, err := secretStore.GetOwnMemberDeviceForGroup(gc.Group())
require.NoError(t, err)
_, err = weshnet.MetadataStoreAddDeviceToGroup(ctx, gc.MetadataStore(), gc.Group(), otherMD)
require.NoError(t, err)
memberDevice, err := gc.SecretStore().GetOwnMemberDeviceForGroup(gc.Group())
require.NoError(t, err)
ds, err := secretStore.GetShareableChainKey(ctx, gc.Group(), memberDevice.Member())
require.NoError(t, err)
_, err = weshnet.MetadataStoreSendSecret(ctx, gc.MetadataStore(), gc.Group(), otherMD, memberDevice.Member(), ds)
require.NoError(t, err)
time.Sleep(time.Millisecond * 200)
return secretStore, cleanup
}
================================================
FILE: pkg/outofstoremessage/service_outofstoremessage.go
================================================
package outofstoremessage
import (
"context"
"fmt"
"io"
"time"
ds "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
coreiface "github.com/ipfs/kubo/core/coreiface"
"go.uber.org/zap"
"google.golang.org/grpc"
"berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/grpcutil"
"berty.tech/weshnet/v2/pkg/outofstoremessagetypes"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
type OOSMService interface {
outofstoremessagetypes.OutOfStoreMessageServiceServer
}
var _ OOSMService = (*oosmService)(nil)
type oosmService struct {
logger *zap.Logger
rootDatastore ds.Datastore
secretStore secretstore.SecretStore
outofstoremessagetypes.UnimplementedOutOfStoreMessageServiceServer
}
type OOSMServiceClient interface {
outofstoremessagetypes.OutOfStoreMessageServiceClient
io.Closer
}
type oosmServiceClient struct {
OOSMServiceClient
service OOSMService
server *grpc.Server
}
type OOSMOption func(*oosmService) error
// NewOutOfStoreMessageServiceClient creates a new Wesh protocol service and returns a gRPC
// ServiceClient which uses a direct in-memory connection. When finished, you must call Close().
// This opens or creates a Wesh account where the datastore location is specified by the path argument.
// The service will not start any network stuff, it will only use the filesystem to store or get data.
func NewOutOfStoreMessageServiceClient(opts ...OOSMOption) (OOSMServiceClient, error) {
svc, err := NewOutOfStoreMessageService(opts...)
if err != nil {
return nil, err
}
s := grpc.NewServer()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
c, err := newClientFromService(ctx, s, svc)
if err != nil {
return nil, fmt.Errorf("unable to create client from server: %w", err)
}
return &oosmServiceClient{
OOSMServiceClient: c,
server: s,
service: svc,
}, nil
}
type oosmClient struct {
outofstoremessagetypes.OutOfStoreMessageServiceClient
l *grpcutil.BufListener
cc *grpc.ClientConn
}
func (c *oosmClient) Close() error {
err := c.cc.Close()
_ = c.l.Close()
return err
}
func newClientFromService(ctx context.Context, s *grpc.Server, svc OOSMService, opts ...grpc.DialOption) (OOSMServiceClient, error) {
bl := grpcutil.NewBufListener(weshnet.ClientBufferSize)
cc, err := bl.NewClientConn(ctx, opts...)
if err != nil {
return nil, err
}
outofstoremessagetypes.RegisterOutOfStoreMessageServiceServer(s, svc)
go func() {
// we dont need to log the error
_ = s.Serve(bl)
}()
return &oosmClient{
OutOfStoreMessageServiceClient: outofstoremessagetypes.NewOutOfStoreMessageServiceClient(cc),
cc: cc,
l: bl,
}, nil
}
func NewOutOfStoreMessageService(opts ...OOSMOption) (OOSMService, error) {
svc := &oosmService{}
withDefaultOpts := make([]OOSMOption, len(opts))
copy(withDefaultOpts, opts)
withDefaultOpts = append(withDefaultOpts, WithFallbackDefaults)
for _, opt := range withDefaultOpts {
if err := opt(svc); err != nil {
return nil, err
}
}
return svc, nil
}
func (s *oosmService) Close() error {
return nil
}
func (s *oosmService) Status() (weshnet.Status, error) {
return weshnet.Status{}, nil
}
func (s *oosmService) IpfsCoreAPI() coreiface.CoreAPI {
return nil
}
func (s *oosmService) OutOfStoreReceive(ctx context.Context, request *protocoltypes.OutOfStoreReceive_Request) (*protocoltypes.OutOfStoreReceive_Reply, error) {
outOfStoreMessage, group, clearPayload, alreadyDecrypted, err := s.secretStore.OpenOutOfStoreMessage(ctx, request.Payload)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
return &protocoltypes.OutOfStoreReceive_Reply{
Message: outOfStoreMessage,
Cleartext: clearPayload,
GroupPublicKey: group.PublicKey,
AlreadyReceived: alreadyDecrypted,
}, nil
}
// FallBackOption is a structure that permit to fallback to a default option if the option is not set.
type FallBackOption struct {
fallback func(s *oosmService) bool
opt OOSMOption
}
// WithLogger set the given logger.
var WithLogger = func(l *zap.Logger) OOSMOption {
return func(s *oosmService) error {
s.logger = l
return nil
}
}
// WithDefaultLogger init a noop logger.
var WithDefaultLogger OOSMOption = func(s *oosmService) error {
s.logger = zap.NewNop()
return nil
}
var fallbackLogger = FallBackOption{
fallback: func(s *oosmService) bool { return s.logger == nil },
opt: WithDefaultLogger,
}
// WithFallbackLogger set the logger if no logger is set.
var WithFallbackLogger OOSMOption = func(s *oosmService) error {
if fallbackLogger.fallback(s) {
return fallbackLogger.opt(s)
}
return nil
}
// WithRootDatastore set the root datastore.
var WithRootDatastore = func(ds ds.Datastore) OOSMOption {
return func(s *oosmService) error {
s.rootDatastore = ds
return nil
}
}
// WithDefaultRootDatastore init a in-memory datastore.
var WithDefaultRootDatastore OOSMOption = func(s *oosmService) error {
s.rootDatastore = ds_sync.MutexWrap(ds.NewMapDatastore())
return nil
}
var fallbackRootDatastore = FallBackOption{
fallback: func(s *oosmService) bool { return s.rootDatastore == nil },
opt: WithDefaultRootDatastore,
}
// WithFallbackRootDatastore set the root datastore if no root datastore is set.
var WithFallbackRootDatastore OOSMOption = func(s *oosmService) error {
if fallbackRootDatastore.fallback(s) {
return fallbackRootDatastore.opt(s)
}
return nil
}
// WithSecretStore set the secret store.
var WithSecretStore = func(ss secretstore.SecretStore) OOSMOption {
return func(s *oosmService) error {
s.secretStore = ss
return nil
}
}
// WithDefaultSecretStore init a new secret store.
// Call WithRootDatastore before this option if you want to use your datastore.
// Call WithLogger before this option if you want to use your logger.
var WithDefaultSecretStore OOSMOption = func(s *oosmService) error {
// dependency
if err := WithFallbackRootDatastore(s); err != nil {
return err
}
if err := WithFallbackLogger(s); err != nil {
return err
}
var err error
s.secretStore, err = secretstore.NewSecretStore(s.rootDatastore, &secretstore.NewSecretStoreOptions{
Logger: s.logger,
})
return err
}
var fallbackSecretStore = FallBackOption{
fallback: func(s *oosmService) bool { return s.secretStore == nil },
opt: WithDefaultSecretStore,
}
// WithFallbackSecretStore set the secret store if no secret store is set.
// Call WithRootDatastore before this option if you want to use your datastore if a new secret store is created.
// Call WithLogger before this option if you want to use your logger if a new secret store is created.
var WithFallbackSecretStore OOSMOption = func(s *oosmService) error {
if fallbackSecretStore.fallback(s) {
return fallbackSecretStore.opt(s)
}
return nil
}
var defaults = []FallBackOption{
fallbackLogger,
fallbackRootDatastore,
fallbackSecretStore,
}
// WithFallbackDefaults set the default options if no option is set.
var WithFallbackDefaults OOSMOption = func(s *oosmService) error {
for _, def := range defaults {
if !def.fallback(s) {
continue
}
if err := def.opt(s); err != nil {
return err
}
}
return nil
}
================================================
FILE: pkg/outofstoremessagetypes/outofstoremessage.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: outofstoremessagetypes/outofstoremessage.proto
package outofstoremessagetypes
import (
protocoltypes "berty.tech/weshnet/v2/pkg/protocoltypes"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
var File_outofstoremessagetypes_outofstoremessage_proto protoreflect.FileDescriptor
var file_outofstoremessagetypes_outofstoremessage_proto_rawDesc = []byte{
0x0a, 0x2e, 0x6f, 0x75, 0x74, 0x6f, 0x66, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6f, 0x75, 0x74, 0x6f, 0x66, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x1c, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x6f, 0x66, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x13,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x32, 0x8d, 0x01, 0x0a, 0x18, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f,
0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x71, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65,
0x63, 0x65, 0x69, 0x76, 0x65, 0x12, 0x2e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x4f,
0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x2e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x4f,
0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x42, 0x32, 0x5a, 0x30, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x74, 0x65, 0x63,
0x68, 0x2f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67,
0x2f, 0x6f, 0x75, 0x74, 0x6f, 0x66, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_outofstoremessagetypes_outofstoremessage_proto_goTypes = []any{
(*protocoltypes.OutOfStoreReceive_Request)(nil), // 0: weshnet.protocol.v1.OutOfStoreReceive.Request
(*protocoltypes.OutOfStoreReceive_Reply)(nil), // 1: weshnet.protocol.v1.OutOfStoreReceive.Reply
}
var file_outofstoremessagetypes_outofstoremessage_proto_depIdxs = []int32{
0, // 0: weshnet.outofstoremessage.v1.OutOfStoreMessageService.OutOfStoreReceive:input_type -> weshnet.protocol.v1.OutOfStoreReceive.Request
1, // 1: weshnet.outofstoremessage.v1.OutOfStoreMessageService.OutOfStoreReceive:output_type -> weshnet.protocol.v1.OutOfStoreReceive.Reply
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_outofstoremessagetypes_outofstoremessage_proto_init() }
func file_outofstoremessagetypes_outofstoremessage_proto_init() {
if File_outofstoremessagetypes_outofstoremessage_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_outofstoremessagetypes_outofstoremessage_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_outofstoremessagetypes_outofstoremessage_proto_goTypes,
DependencyIndexes: file_outofstoremessagetypes_outofstoremessage_proto_depIdxs,
}.Build()
File_outofstoremessagetypes_outofstoremessage_proto = out.File
file_outofstoremessagetypes_outofstoremessage_proto_rawDesc = nil
file_outofstoremessagetypes_outofstoremessage_proto_goTypes = nil
file_outofstoremessagetypes_outofstoremessage_proto_depIdxs = nil
}
================================================
FILE: pkg/outofstoremessagetypes/outofstoremessage.pb.gw.go
================================================
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: outofstoremessagetypes/outofstoremessage.proto
/*
Package outofstoremessagetypes is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package outofstoremessagetypes
import (
"context"
"io"
"net/http"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
func request_OutOfStoreMessageService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, client OutOfStoreMessageServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq protocoltypes.OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.OutOfStoreReceive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_OutOfStoreMessageService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, server OutOfStoreMessageServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq protocoltypes.OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.OutOfStoreReceive(ctx, &protoReq)
return msg, metadata, err
}
// RegisterOutOfStoreMessageServiceHandlerServer registers the http handlers for service OutOfStoreMessageService to "mux".
// UnaryRPC :call OutOfStoreMessageServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterOutOfStoreMessageServiceHandlerFromEndpoint instead.
func RegisterOutOfStoreMessageServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server OutOfStoreMessageServiceServer) error {
mux.Handle("POST", pattern_OutOfStoreMessageService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_OutOfStoreMessageService_OutOfStoreReceive_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_OutOfStoreMessageService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterOutOfStoreMessageServiceHandlerFromEndpoint is same as RegisterOutOfStoreMessageServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterOutOfStoreMessageServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterOutOfStoreMessageServiceHandler(ctx, mux, conn)
}
// RegisterOutOfStoreMessageServiceHandler registers the http handlers for service OutOfStoreMessageService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterOutOfStoreMessageServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterOutOfStoreMessageServiceHandlerClient(ctx, mux, NewOutOfStoreMessageServiceClient(conn))
}
// RegisterOutOfStoreMessageServiceHandlerClient registers the http handlers for service OutOfStoreMessageService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "OutOfStoreMessageServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "OutOfStoreMessageServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "OutOfStoreMessageServiceClient" to call the correct interceptors.
func RegisterOutOfStoreMessageServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client OutOfStoreMessageServiceClient) error {
mux.Handle("POST", pattern_OutOfStoreMessageService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_OutOfStoreMessageService_OutOfStoreReceive_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_OutOfStoreMessageService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_OutOfStoreMessageService_OutOfStoreReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.outofstoremessage.v1.OutOfStoreMessageService", "OutOfStoreReceive"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_OutOfStoreMessageService_OutOfStoreReceive_0 = runtime.ForwardResponseMessage
)
================================================
FILE: pkg/outofstoremessagetypes/outofstoremessage_grpc.pb.go
================================================
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: outofstoremessagetypes/outofstoremessage.proto
package outofstoremessagetypes
import (
protocoltypes "berty.tech/weshnet/v2/pkg/protocoltypes"
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
OutOfStoreMessageService_OutOfStoreReceive_FullMethodName = "/weshnet.outofstoremessage.v1.OutOfStoreMessageService/OutOfStoreReceive"
)
// OutOfStoreMessageServiceClient is the client API for OutOfStoreMessageService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// OutOfStoreMessageService is the service used to open out-of-store messages (e.g. push notifications)
// It is used to open messages with a lightweight protocol service for mobile backgroup processes.
type OutOfStoreMessageServiceClient interface {
// OutOfStoreReceive parses a payload received outside a synchronized store
OutOfStoreReceive(ctx context.Context, in *protocoltypes.OutOfStoreReceive_Request, opts ...grpc.CallOption) (*protocoltypes.OutOfStoreReceive_Reply, error)
}
type outOfStoreMessageServiceClient struct {
cc grpc.ClientConnInterface
}
func NewOutOfStoreMessageServiceClient(cc grpc.ClientConnInterface) OutOfStoreMessageServiceClient {
return &outOfStoreMessageServiceClient{cc}
}
func (c *outOfStoreMessageServiceClient) OutOfStoreReceive(ctx context.Context, in *protocoltypes.OutOfStoreReceive_Request, opts ...grpc.CallOption) (*protocoltypes.OutOfStoreReceive_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(protocoltypes.OutOfStoreReceive_Reply)
err := c.cc.Invoke(ctx, OutOfStoreMessageService_OutOfStoreReceive_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// OutOfStoreMessageServiceServer is the server API for OutOfStoreMessageService service.
// All implementations must embed UnimplementedOutOfStoreMessageServiceServer
// for forward compatibility.
//
// OutOfStoreMessageService is the service used to open out-of-store messages (e.g. push notifications)
// It is used to open messages with a lightweight protocol service for mobile backgroup processes.
type OutOfStoreMessageServiceServer interface {
// OutOfStoreReceive parses a payload received outside a synchronized store
OutOfStoreReceive(context.Context, *protocoltypes.OutOfStoreReceive_Request) (*protocoltypes.OutOfStoreReceive_Reply, error)
mustEmbedUnimplementedOutOfStoreMessageServiceServer()
}
// UnimplementedOutOfStoreMessageServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedOutOfStoreMessageServiceServer struct{}
func (UnimplementedOutOfStoreMessageServiceServer) OutOfStoreReceive(context.Context, *protocoltypes.OutOfStoreReceive_Request) (*protocoltypes.OutOfStoreReceive_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method OutOfStoreReceive not implemented")
}
func (UnimplementedOutOfStoreMessageServiceServer) mustEmbedUnimplementedOutOfStoreMessageServiceServer() {
}
func (UnimplementedOutOfStoreMessageServiceServer) testEmbeddedByValue() {}
// UnsafeOutOfStoreMessageServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to OutOfStoreMessageServiceServer will
// result in compilation errors.
type UnsafeOutOfStoreMessageServiceServer interface {
mustEmbedUnimplementedOutOfStoreMessageServiceServer()
}
func RegisterOutOfStoreMessageServiceServer(s grpc.ServiceRegistrar, srv OutOfStoreMessageServiceServer) {
// If the following call pancis, it indicates UnimplementedOutOfStoreMessageServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&OutOfStoreMessageService_ServiceDesc, srv)
}
func _OutOfStoreMessageService_OutOfStoreReceive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(protocoltypes.OutOfStoreReceive_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OutOfStoreMessageServiceServer).OutOfStoreReceive(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: OutOfStoreMessageService_OutOfStoreReceive_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OutOfStoreMessageServiceServer).OutOfStoreReceive(ctx, req.(*protocoltypes.OutOfStoreReceive_Request))
}
return interceptor(ctx, in, info, handler)
}
// OutOfStoreMessageService_ServiceDesc is the grpc.ServiceDesc for OutOfStoreMessageService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var OutOfStoreMessageService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "weshnet.outofstoremessage.v1.OutOfStoreMessageService",
HandlerType: (*OutOfStoreMessageServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "OutOfStoreReceive",
Handler: _OutOfStoreMessageService_OutOfStoreReceive_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "outofstoremessagetypes/outofstoremessage.proto",
}
================================================
FILE: pkg/protocoltypes/contact.go
================================================
package protocoltypes
import (
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/errcode"
)
const RendezvousSeedLength = 32
type ShareableContactOptions uint64
const (
shareableContactOptionsUndefined = iota
ShareableContactOptionsAllowMissingRDVSeed
ShareableContactOptionsAllowMissingPK
)
var _ = shareableContactOptionsUndefined
func (m *ShareableContact) CheckFormat(options ...ShareableContactOptions) error {
var (
optionMissingPKAllowed = false
optionMissingRDVSeedAllowed = false
)
for _, o := range options {
if o == ShareableContactOptionsAllowMissingPK {
optionMissingPKAllowed = true
}
if o == ShareableContactOptionsAllowMissingRDVSeed {
optionMissingRDVSeedAllowed = true
}
}
if l := len(m.PublicRendezvousSeed); l != RendezvousSeedLength {
if !(l == 0 && optionMissingRDVSeedAllowed) {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("rendezvous seed length should not be %d", l))
}
}
if l := len(m.Pk); l == 0 && !optionMissingPKAllowed {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("contact public key is missing"))
}
if l := len(m.Pk); l != 0 {
_, err := crypto.UnmarshalEd25519PublicKey(m.Pk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
}
return nil
}
func (m *ShareableContact) IsSamePK(otherPK crypto.PubKey) bool {
pk, err := m.GetPubKey()
if err != nil {
return false
}
return otherPK.Equals(pk)
}
func (m *ShareableContact) GetPubKey() (crypto.PubKey, error) {
pk, err := crypto.UnmarshalEd25519PublicKey(m.Pk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return pk, nil
}
================================================
FILE: pkg/protocoltypes/doc.go
================================================
// Package protocoltypes contains types and helpers for the Berty Protocol.
// This package is generated with Protobuf.
// See https://github.com/berty/berty/tree/master/api for more information.
package protocoltypes
================================================
FILE: pkg/protocoltypes/events_account.go
================================================
package protocoltypes
func (m *AccountGroupJoined) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountGroupLeft) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestDisabled) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestEnabled) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestReferenceReset) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestOutgoingEnqueued) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestOutgoingSent) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestIncomingReceived) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestIncomingDiscarded) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestIncomingAccepted) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactBlocked) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactUnblocked) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountContactRequestOutgoingSent) SetContactPK(pk []byte) {
m.ContactPk = pk
}
func (m *AccountContactRequestIncomingDiscarded) SetContactPK(pk []byte) {
m.ContactPk = pk
}
func (m *AccountContactRequestIncomingAccepted) SetContactPK(pk []byte) {
m.ContactPk = pk
}
func (m *AccountContactBlocked) SetContactPK(pk []byte) {
m.ContactPk = pk
}
func (m *AccountContactUnblocked) SetContactPK(pk []byte) {
m.ContactPk = pk
}
func (m *AccountGroupLeft) SetGroupPK(pk []byte) {
m.GroupPk = pk
}
func (m *ContactAliasKeyAdded) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *MultiMemberGroupAliasResolverAdded) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *MultiMemberGroupAdminRoleGranted) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *GroupMetadataPayloadSent) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *GroupReplicating) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
func (m *AccountVerifiedCredentialRegistered) SetDevicePK(pk []byte) {
m.DevicePk = pk
}
================================================
FILE: pkg/protocoltypes/example_test.go
================================================
package protocoltypes_test
================================================
FILE: pkg/protocoltypes/group.go
================================================
package protocoltypes
import (
crand "crypto/rand"
"encoding/hex"
"io"
"github.com/libp2p/go-libp2p/core/crypto"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
)
func (m *Group) GetSigningPrivKey() (crypto.PrivKey, error) {
if len(m.Secret) == 0 {
return nil, errcode.ErrCode_ErrMissingInput
}
edSK := ed25519.NewKeyFromSeed(m.Secret)
sk, _, err := crypto.KeyPairFromStdKey(&edSK)
if err != nil {
return nil, err
}
return sk, nil
}
func (m *Group) GetPubKey() (crypto.PubKey, error) {
return crypto.UnmarshalEd25519PublicKey(m.PublicKey)
}
func (m *Group) GetSigningPubKey() (crypto.PubKey, error) {
if len(m.SignPub) != 0 {
return crypto.UnmarshalEd25519PublicKey(m.SignPub)
}
sk, err := m.GetSigningPrivKey()
if err != nil {
return nil, err
}
return sk.GetPublic(), nil
}
func (m *Group) IsValid() error {
pk, err := m.GetPubKey()
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
ok, err := pk.Verify(m.Secret, m.SecretSig)
if err != nil {
return errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
if !ok {
return errcode.ErrCode_ErrCryptoSignatureVerification
}
return nil
}
// GroupIDAsString returns the group pub key as a string
func (m *Group) GroupIDAsString() string {
return hex.EncodeToString(m.PublicKey)
}
func (m *Group) Copy() *Group {
return &Group{
PublicKey: m.PublicKey,
Secret: m.Secret,
SecretSig: m.SecretSig,
GroupType: m.GroupType,
SignPub: m.SignPub,
}
}
const CurrentGroupVersion = 1
// NewGroupMultiMember creates a new Group object and an invitation to be used by
// the first member of the group
func NewGroupMultiMember() (*Group, crypto.PrivKey, error) {
priv, pub, err := crypto.GenerateEd25519Key(crand.Reader)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
pubBytes, err := pub.Raw()
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
signing, _, err := crypto.GenerateEd25519Key(crand.Reader)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(signing)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
skSig, err := priv.Sign(signingBytes)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
group := &Group{
PublicKey: pubBytes,
Secret: signingBytes,
SecretSig: skSig,
GroupType: GroupType_GroupTypeMultiMember,
}
updateKey, err := group.GetLinkKeyArray()
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
linkKeySig, err := priv.Sign(updateKey[:])
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
group.LinkKeySig = linkKeySig
return group, priv, nil
}
func ComputeLinkKey(publicKey, secret []byte) (*[cryptoutil.KeySize]byte, error) {
arr := [cryptoutil.KeySize]byte{}
kdf := hkdf.New(sha3.New256, secret, nil, publicKey)
if _, err := io.ReadFull(kdf, arr[:]); err != nil {
return nil, errcode.ErrCode_ErrStreamRead.Wrap(err)
}
return &arr, nil
}
func (m *Group) GetLinkKeyArray() (*[cryptoutil.KeySize]byte, error) {
if len(m.GetLinkKey()) == cryptoutil.KeySize {
arr := [cryptoutil.KeySize]byte{}
for i, c := range m.GetLinkKey() {
arr[i] = c
}
return &arr, nil
}
return ComputeLinkKey(m.GetPublicKey(), m.GetSecret())
}
func (m *Group) GetSharedSecret() *[cryptoutil.KeySize]byte {
sharedSecret := [cryptoutil.KeySize]byte{}
copy(sharedSecret[:], m.GetSecret())
return &sharedSecret
}
================================================
FILE: pkg/protocoltypes/protocoltypes.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: protocoltypes.proto
package protocoltypes
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GroupType int32
const (
// GroupTypeUndefined indicates that the value has not been set. For example, happens if group is replicated.
GroupType_GroupTypeUndefined GroupType = 0
// GroupTypeAccount is the group managing an account, available to all its devices.
GroupType_GroupTypeAccount GroupType = 1
// GroupTypeContact is the group created between two accounts, available to all their devices.
GroupType_GroupTypeContact GroupType = 2
// GroupTypeMultiMember is a group containing an undefined number of members.
GroupType_GroupTypeMultiMember GroupType = 3
)
// Enum value maps for GroupType.
var (
GroupType_name = map[int32]string{
0: "GroupTypeUndefined",
1: "GroupTypeAccount",
2: "GroupTypeContact",
3: "GroupTypeMultiMember",
}
GroupType_value = map[string]int32{
"GroupTypeUndefined": 0,
"GroupTypeAccount": 1,
"GroupTypeContact": 2,
"GroupTypeMultiMember": 3,
}
)
func (x GroupType) Enum() *GroupType {
p := new(GroupType)
*p = x
return p
}
func (x GroupType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (GroupType) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[0].Descriptor()
}
func (GroupType) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[0]
}
func (x GroupType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use GroupType.Descriptor instead.
func (GroupType) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{0}
}
type EventType int32
const (
// EventTypeUndefined indicates that the value has not been set. Should not happen.
EventType_EventTypeUndefined EventType = 0
// EventTypeGroupMemberDeviceAdded indicates the payload includes that a member has added their device to the group
EventType_EventTypeGroupMemberDeviceAdded EventType = 1
// EventTypeGroupDeviceChainKeyAdded indicates the payload includes that a member has sent their device chain key to another member
EventType_EventTypeGroupDeviceChainKeyAdded EventType = 2
// EventTypeAccountGroupJoined indicates the payload includes that the account has joined a group
EventType_EventTypeAccountGroupJoined EventType = 101
// EventTypeAccountGroupLeft indicates the payload includes that the account has left a group
EventType_EventTypeAccountGroupLeft EventType = 102
// EventTypeAccountContactRequestDisabled indicates the payload includes that the account has disabled incoming contact requests
EventType_EventTypeAccountContactRequestDisabled EventType = 103
// EventTypeAccountContactRequestEnabled indicates the payload includes that the account has enabled incoming contact requests
EventType_EventTypeAccountContactRequestEnabled EventType = 104
// EventTypeAccountContactRequestReferenceReset indicates the payload includes that the account has a new contact request rendezvous seed
EventType_EventTypeAccountContactRequestReferenceReset EventType = 105
// EventTypeAccountContactRequestOutgoingEnqueued indicates the payload includes that the account will attempt to send a new contact request
EventType_EventTypeAccountContactRequestOutgoingEnqueued EventType = 106
// EventTypeAccountContactRequestOutgoingSent indicates the payload includes that the account has sent a contact request
EventType_EventTypeAccountContactRequestOutgoingSent EventType = 107
// EventTypeAccountContactRequestIncomingReceived indicates the payload includes that the account has received a contact request
EventType_EventTypeAccountContactRequestIncomingReceived EventType = 108
// EventTypeAccountContactRequestIncomingDiscarded indicates the payload includes that the account has ignored a contact request
EventType_EventTypeAccountContactRequestIncomingDiscarded EventType = 109
// EventTypeAccountContactRequestIncomingAccepted indicates the payload includes that the account has accepted a contact request
EventType_EventTypeAccountContactRequestIncomingAccepted EventType = 110
// EventTypeAccountContactBlocked indicates the payload includes that the account has blocked a contact
EventType_EventTypeAccountContactBlocked EventType = 111
// EventTypeAccountContactUnblocked indicates the payload includes that the account has unblocked a contact
EventType_EventTypeAccountContactUnblocked EventType = 112
// EventTypeContactAliasKeyAdded indicates the payload includes that the contact group has received an alias key
EventType_EventTypeContactAliasKeyAdded EventType = 201
// EventTypeMultiMemberGroupAliasResolverAdded indicates the payload includes that a member of the group sent their alias proof
EventType_EventTypeMultiMemberGroupAliasResolverAdded EventType = 301
// EventTypeMultiMemberGroupInitialMemberAnnounced indicates the payload includes that a member has authenticated themselves as the group owner
EventType_EventTypeMultiMemberGroupInitialMemberAnnounced EventType = 302
// EventTypeMultiMemberGroupAdminRoleGranted indicates the payload includes that an admin of the group granted another member as an admin
EventType_EventTypeMultiMemberGroupAdminRoleGranted EventType = 303
// EventTypeGroupReplicating indicates that the group has been registered for replication on a server
EventType_EventTypeGroupReplicating EventType = 403
// EventTypeAccountVerifiedCredentialRegistered
EventType_EventTypeAccountVerifiedCredentialRegistered EventType = 500
// EventTypeGroupMetadataPayloadSent indicates the payload includes an app specific event, unlike messages stored on the message store it is encrypted using a static key
EventType_EventTypeGroupMetadataPayloadSent EventType = 1001
)
// Enum value maps for EventType.
var (
EventType_name = map[int32]string{
0: "EventTypeUndefined",
1: "EventTypeGroupMemberDeviceAdded",
2: "EventTypeGroupDeviceChainKeyAdded",
101: "EventTypeAccountGroupJoined",
102: "EventTypeAccountGroupLeft",
103: "EventTypeAccountContactRequestDisabled",
104: "EventTypeAccountContactRequestEnabled",
105: "EventTypeAccountContactRequestReferenceReset",
106: "EventTypeAccountContactRequestOutgoingEnqueued",
107: "EventTypeAccountContactRequestOutgoingSent",
108: "EventTypeAccountContactRequestIncomingReceived",
109: "EventTypeAccountContactRequestIncomingDiscarded",
110: "EventTypeAccountContactRequestIncomingAccepted",
111: "EventTypeAccountContactBlocked",
112: "EventTypeAccountContactUnblocked",
201: "EventTypeContactAliasKeyAdded",
301: "EventTypeMultiMemberGroupAliasResolverAdded",
302: "EventTypeMultiMemberGroupInitialMemberAnnounced",
303: "EventTypeMultiMemberGroupAdminRoleGranted",
403: "EventTypeGroupReplicating",
500: "EventTypeAccountVerifiedCredentialRegistered",
1001: "EventTypeGroupMetadataPayloadSent",
}
EventType_value = map[string]int32{
"EventTypeUndefined": 0,
"EventTypeGroupMemberDeviceAdded": 1,
"EventTypeGroupDeviceChainKeyAdded": 2,
"EventTypeAccountGroupJoined": 101,
"EventTypeAccountGroupLeft": 102,
"EventTypeAccountContactRequestDisabled": 103,
"EventTypeAccountContactRequestEnabled": 104,
"EventTypeAccountContactRequestReferenceReset": 105,
"EventTypeAccountContactRequestOutgoingEnqueued": 106,
"EventTypeAccountContactRequestOutgoingSent": 107,
"EventTypeAccountContactRequestIncomingReceived": 108,
"EventTypeAccountContactRequestIncomingDiscarded": 109,
"EventTypeAccountContactRequestIncomingAccepted": 110,
"EventTypeAccountContactBlocked": 111,
"EventTypeAccountContactUnblocked": 112,
"EventTypeContactAliasKeyAdded": 201,
"EventTypeMultiMemberGroupAliasResolverAdded": 301,
"EventTypeMultiMemberGroupInitialMemberAnnounced": 302,
"EventTypeMultiMemberGroupAdminRoleGranted": 303,
"EventTypeGroupReplicating": 403,
"EventTypeAccountVerifiedCredentialRegistered": 500,
"EventTypeGroupMetadataPayloadSent": 1001,
}
)
func (x EventType) Enum() *EventType {
p := new(EventType)
*p = x
return p
}
func (x EventType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (EventType) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[1].Descriptor()
}
func (EventType) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[1]
}
func (x EventType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use EventType.Descriptor instead.
func (EventType) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{1}
}
type DebugInspectGroupLogType int32
const (
DebugInspectGroupLogType_DebugInspectGroupLogTypeUndefined DebugInspectGroupLogType = 0
DebugInspectGroupLogType_DebugInspectGroupLogTypeMessage DebugInspectGroupLogType = 1
DebugInspectGroupLogType_DebugInspectGroupLogTypeMetadata DebugInspectGroupLogType = 2
)
// Enum value maps for DebugInspectGroupLogType.
var (
DebugInspectGroupLogType_name = map[int32]string{
0: "DebugInspectGroupLogTypeUndefined",
1: "DebugInspectGroupLogTypeMessage",
2: "DebugInspectGroupLogTypeMetadata",
}
DebugInspectGroupLogType_value = map[string]int32{
"DebugInspectGroupLogTypeUndefined": 0,
"DebugInspectGroupLogTypeMessage": 1,
"DebugInspectGroupLogTypeMetadata": 2,
}
)
func (x DebugInspectGroupLogType) Enum() *DebugInspectGroupLogType {
p := new(DebugInspectGroupLogType)
*p = x
return p
}
func (x DebugInspectGroupLogType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (DebugInspectGroupLogType) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[2].Descriptor()
}
func (DebugInspectGroupLogType) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[2]
}
func (x DebugInspectGroupLogType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use DebugInspectGroupLogType.Descriptor instead.
func (DebugInspectGroupLogType) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{2}
}
type ContactState int32
const (
ContactState_ContactStateUndefined ContactState = 0
ContactState_ContactStateToRequest ContactState = 1
ContactState_ContactStateReceived ContactState = 2
ContactState_ContactStateAdded ContactState = 3
ContactState_ContactStateRemoved ContactState = 4
ContactState_ContactStateDiscarded ContactState = 5
ContactState_ContactStateBlocked ContactState = 6
)
// Enum value maps for ContactState.
var (
ContactState_name = map[int32]string{
0: "ContactStateUndefined",
1: "ContactStateToRequest",
2: "ContactStateReceived",
3: "ContactStateAdded",
4: "ContactStateRemoved",
5: "ContactStateDiscarded",
6: "ContactStateBlocked",
}
ContactState_value = map[string]int32{
"ContactStateUndefined": 0,
"ContactStateToRequest": 1,
"ContactStateReceived": 2,
"ContactStateAdded": 3,
"ContactStateRemoved": 4,
"ContactStateDiscarded": 5,
"ContactStateBlocked": 6,
}
)
func (x ContactState) Enum() *ContactState {
p := new(ContactState)
*p = x
return p
}
func (x ContactState) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ContactState) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[3].Descriptor()
}
func (ContactState) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[3]
}
func (x ContactState) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ContactState.Descriptor instead.
func (ContactState) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{3}
}
type Direction int32
const (
Direction_UnknownDir Direction = 0
Direction_InboundDir Direction = 1
Direction_OutboundDir Direction = 2
Direction_BiDir Direction = 3
)
// Enum value maps for Direction.
var (
Direction_name = map[int32]string{
0: "UnknownDir",
1: "InboundDir",
2: "OutboundDir",
3: "BiDir",
}
Direction_value = map[string]int32{
"UnknownDir": 0,
"InboundDir": 1,
"OutboundDir": 2,
"BiDir": 3,
}
)
func (x Direction) Enum() *Direction {
p := new(Direction)
*p = x
return p
}
func (x Direction) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Direction) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[4].Descriptor()
}
func (Direction) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[4]
}
func (x Direction) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Direction.Descriptor instead.
func (Direction) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{4}
}
type ServiceGetConfiguration_SettingState int32
const (
ServiceGetConfiguration_Unknown ServiceGetConfiguration_SettingState = 0
ServiceGetConfiguration_Enabled ServiceGetConfiguration_SettingState = 1
ServiceGetConfiguration_Disabled ServiceGetConfiguration_SettingState = 2
ServiceGetConfiguration_Unavailable ServiceGetConfiguration_SettingState = 3
)
// Enum value maps for ServiceGetConfiguration_SettingState.
var (
ServiceGetConfiguration_SettingState_name = map[int32]string{
0: "Unknown",
1: "Enabled",
2: "Disabled",
3: "Unavailable",
}
ServiceGetConfiguration_SettingState_value = map[string]int32{
"Unknown": 0,
"Enabled": 1,
"Disabled": 2,
"Unavailable": 3,
}
)
func (x ServiceGetConfiguration_SettingState) Enum() *ServiceGetConfiguration_SettingState {
p := new(ServiceGetConfiguration_SettingState)
*p = x
return p
}
func (x ServiceGetConfiguration_SettingState) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ServiceGetConfiguration_SettingState) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[5].Descriptor()
}
func (ServiceGetConfiguration_SettingState) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[5]
}
func (x ServiceGetConfiguration_SettingState) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ServiceGetConfiguration_SettingState.Descriptor instead.
func (ServiceGetConfiguration_SettingState) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{34, 0}
}
type GroupDeviceStatus_Type int32
const (
GroupDeviceStatus_TypeUnknown GroupDeviceStatus_Type = 0
GroupDeviceStatus_TypePeerDisconnected GroupDeviceStatus_Type = 1
GroupDeviceStatus_TypePeerConnected GroupDeviceStatus_Type = 2
GroupDeviceStatus_TypePeerReconnecting GroupDeviceStatus_Type = 3
)
// Enum value maps for GroupDeviceStatus_Type.
var (
GroupDeviceStatus_Type_name = map[int32]string{
0: "TypeUnknown",
1: "TypePeerDisconnected",
2: "TypePeerConnected",
3: "TypePeerReconnecting",
}
GroupDeviceStatus_Type_value = map[string]int32{
"TypeUnknown": 0,
"TypePeerDisconnected": 1,
"TypePeerConnected": 2,
"TypePeerReconnecting": 3,
}
)
func (x GroupDeviceStatus_Type) Enum() *GroupDeviceStatus_Type {
p := new(GroupDeviceStatus_Type)
*p = x
return p
}
func (x GroupDeviceStatus_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (GroupDeviceStatus_Type) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[6].Descriptor()
}
func (GroupDeviceStatus_Type) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[6]
}
func (x GroupDeviceStatus_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use GroupDeviceStatus_Type.Descriptor instead.
func (GroupDeviceStatus_Type) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 0}
}
type GroupDeviceStatus_Transport int32
const (
GroupDeviceStatus_TptUnknown GroupDeviceStatus_Transport = 0
GroupDeviceStatus_TptLAN GroupDeviceStatus_Transport = 1
GroupDeviceStatus_TptWAN GroupDeviceStatus_Transport = 2
GroupDeviceStatus_TptProximity GroupDeviceStatus_Transport = 3
)
// Enum value maps for GroupDeviceStatus_Transport.
var (
GroupDeviceStatus_Transport_name = map[int32]string{
0: "TptUnknown",
1: "TptLAN",
2: "TptWAN",
3: "TptProximity",
}
GroupDeviceStatus_Transport_value = map[string]int32{
"TptUnknown": 0,
"TptLAN": 1,
"TptWAN": 2,
"TptProximity": 3,
}
)
func (x GroupDeviceStatus_Transport) Enum() *GroupDeviceStatus_Transport {
p := new(GroupDeviceStatus_Transport)
*p = x
return p
}
func (x GroupDeviceStatus_Transport) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (GroupDeviceStatus_Transport) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[7].Descriptor()
}
func (GroupDeviceStatus_Transport) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[7]
}
func (x GroupDeviceStatus_Transport) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use GroupDeviceStatus_Transport.Descriptor instead.
func (GroupDeviceStatus_Transport) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 1}
}
type PeerList_Feature int32
const (
PeerList_UnknownFeature PeerList_Feature = 0
PeerList_WeshFeature PeerList_Feature = 1
PeerList_BLEFeature PeerList_Feature = 2
PeerList_LocalFeature PeerList_Feature = 3
PeerList_TorFeature PeerList_Feature = 4
PeerList_QuicFeature PeerList_Feature = 5
)
// Enum value maps for PeerList_Feature.
var (
PeerList_Feature_name = map[int32]string{
0: "UnknownFeature",
1: "WeshFeature",
2: "BLEFeature",
3: "LocalFeature",
4: "TorFeature",
5: "QuicFeature",
}
PeerList_Feature_value = map[string]int32{
"UnknownFeature": 0,
"WeshFeature": 1,
"BLEFeature": 2,
"LocalFeature": 3,
"TorFeature": 4,
"QuicFeature": 5,
}
)
func (x PeerList_Feature) Enum() *PeerList_Feature {
p := new(PeerList_Feature)
*p = x
return p
}
func (x PeerList_Feature) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (PeerList_Feature) Descriptor() protoreflect.EnumDescriptor {
return file_protocoltypes_proto_enumTypes[8].Descriptor()
}
func (PeerList_Feature) Type() protoreflect.EnumType {
return &file_protocoltypes_proto_enumTypes[8]
}
func (x PeerList_Feature) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use PeerList_Feature.Descriptor instead.
func (PeerList_Feature) EnumDescriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 0}
}
// Account describes all the secrets that identifies an Account
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group specifies which group is used to manage the account
Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
// account_private_key, private part is used to signs handshake, signs device, create contacts group keys via ECDH -- public part is used to have a shareable identity
AccountPrivateKey []byte `protobuf:"bytes,2,opt,name=account_private_key,json=accountPrivateKey,proto3" json:"account_private_key,omitempty"`
// alias_private_key, private part is use to derive group members private keys, signs alias proofs, public part can be shared to contacts to prove identity
AliasPrivateKey []byte `protobuf:"bytes,3,opt,name=alias_private_key,json=aliasPrivateKey,proto3" json:"alias_private_key,omitempty"`
// public_rendezvous_seed, rendezvous seed used for direct communication
PublicRendezvousSeed []byte `protobuf:"bytes,4,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
func (x *Account) GetAccountPrivateKey() []byte {
if x != nil {
return x.AccountPrivateKey
}
return nil
}
func (x *Account) GetAliasPrivateKey() []byte {
if x != nil {
return x.AliasPrivateKey
}
return nil
}
func (x *Account) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
// Group define a group and is enough to invite someone to it
type Group struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// secret is the symmetric secret of the group, which is used to encrypt the metadata
Secret []byte `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
// secret_sig is the signature of the secret used to ensure the validity of the group
SecretSig []byte `protobuf:"bytes,3,opt,name=secret_sig,json=secretSig,proto3" json:"secret_sig,omitempty"`
// group_type specifies the type of the group, used to determine how device chain key is generated
GroupType GroupType `protobuf:"varint,4,opt,name=group_type,json=groupType,proto3,enum=weshnet.protocol.v1.GroupType" json:"group_type,omitempty"`
// sign_pub is the signature public key used to verify entries, not required when secret and secret_sig are provided
SignPub []byte `protobuf:"bytes,5,opt,name=sign_pub,json=signPub,proto3" json:"sign_pub,omitempty"`
// link_key is the secret key used to exchange group updates and links to attachments, useful for replication services
LinkKey []byte `protobuf:"bytes,6,opt,name=link_key,json=linkKey,proto3" json:"link_key,omitempty"`
// link_key_sig is the signature of the link_key using the group private key
LinkKeySig []byte `protobuf:"bytes,7,opt,name=link_key_sig,json=linkKeySig,proto3" json:"link_key_sig,omitempty"`
}
func (x *Group) Reset() {
*x = Group{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Group) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Group) ProtoMessage() {}
func (x *Group) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Group.ProtoReflect.Descriptor instead.
func (*Group) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{1}
}
func (x *Group) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *Group) GetSecret() []byte {
if x != nil {
return x.Secret
}
return nil
}
func (x *Group) GetSecretSig() []byte {
if x != nil {
return x.SecretSig
}
return nil
}
func (x *Group) GetGroupType() GroupType {
if x != nil {
return x.GroupType
}
return GroupType_GroupTypeUndefined
}
func (x *Group) GetSignPub() []byte {
if x != nil {
return x.SignPub
}
return nil
}
func (x *Group) GetLinkKey() []byte {
if x != nil {
return x.LinkKey
}
return nil
}
func (x *Group) GetLinkKeySig() []byte {
if x != nil {
return x.LinkKeySig
}
return nil
}
type GroupHeadsExport struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_key is the identifier of the group, it signs the group secret and the initial member of a multi-member group
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// sign_pub is the signature public key used to verify entries
SignPub []byte `protobuf:"bytes,2,opt,name=sign_pub,json=signPub,proto3" json:"sign_pub,omitempty"`
// metadata_heads_cids are the heads of the metadata store that should be restored from an export
MetadataHeadsCids [][]byte `protobuf:"bytes,3,rep,name=metadata_heads_cids,json=metadataHeadsCids,proto3" json:"metadata_heads_cids,omitempty"`
// messages_heads_cids are the heads of the metadata store that should be restored from an export
MessagesHeadsCids [][]byte `protobuf:"bytes,4,rep,name=messages_heads_cids,json=messagesHeadsCids,proto3" json:"messages_heads_cids,omitempty"`
// link_key
LinkKey []byte `protobuf:"bytes,5,opt,name=link_key,json=linkKey,proto3" json:"link_key,omitempty"`
}
func (x *GroupHeadsExport) Reset() {
*x = GroupHeadsExport{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupHeadsExport) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupHeadsExport) ProtoMessage() {}
func (x *GroupHeadsExport) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupHeadsExport.ProtoReflect.Descriptor instead.
func (*GroupHeadsExport) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{2}
}
func (x *GroupHeadsExport) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *GroupHeadsExport) GetSignPub() []byte {
if x != nil {
return x.SignPub
}
return nil
}
func (x *GroupHeadsExport) GetMetadataHeadsCids() [][]byte {
if x != nil {
return x.MetadataHeadsCids
}
return nil
}
func (x *GroupHeadsExport) GetMessagesHeadsCids() [][]byte {
if x != nil {
return x.MessagesHeadsCids
}
return nil
}
func (x *GroupHeadsExport) GetLinkKey() []byte {
if x != nil {
return x.LinkKey
}
return nil
}
// GroupMetadata is used in GroupEnvelope and only readable by invited group members
type GroupMetadata struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// event_type defines which event type is used
EventType EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=weshnet.protocol.v1.EventType" json:"event_type,omitempty"`
// the serialization depends on event_type, event is symmetrically encrypted
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// sig is the signature of the payload, it depends on the event_type for the used key
Sig []byte `protobuf:"bytes,3,opt,name=sig,proto3" json:"sig,omitempty"`
// protocol_metadata is protocol layer data
ProtocolMetadata *ProtocolMetadata `protobuf:"bytes,4,opt,name=protocol_metadata,json=protocolMetadata,proto3" json:"protocol_metadata,omitempty"`
}
func (x *GroupMetadata) Reset() {
*x = GroupMetadata{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMetadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMetadata) ProtoMessage() {}
func (x *GroupMetadata) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMetadata.ProtoReflect.Descriptor instead.
func (*GroupMetadata) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{3}
}
func (x *GroupMetadata) GetEventType() EventType {
if x != nil {
return x.EventType
}
return EventType_EventTypeUndefined
}
func (x *GroupMetadata) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
func (x *GroupMetadata) GetSig() []byte {
if x != nil {
return x.Sig
}
return nil
}
func (x *GroupMetadata) GetProtocolMetadata() *ProtocolMetadata {
if x != nil {
return x.ProtocolMetadata
}
return nil
}
// GroupEnvelope is a publicly exposed structure containing a group metadata event
type GroupEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// nonce is used to encrypt the message
Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
// event is encrypted using a symmetric key shared among group members
Event []byte `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"`
}
func (x *GroupEnvelope) Reset() {
*x = GroupEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupEnvelope) ProtoMessage() {}
func (x *GroupEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupEnvelope.ProtoReflect.Descriptor instead.
func (*GroupEnvelope) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{4}
}
func (x *GroupEnvelope) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
func (x *GroupEnvelope) GetEvent() []byte {
if x != nil {
return x.Event
}
return nil
}
// MessageHeaders is used in MessageEnvelope and only readable by invited group members
type MessageHeaders struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// counter is the current counter value for the specified device
Counter uint64 `protobuf:"varint,1,opt,name=counter,proto3" json:"counter,omitempty"`
// device_pk is the public key of the device sending the message
DevicePk []byte `protobuf:"bytes,2,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// sig is the signature of the encrypted message using the device's private key
Sig []byte `protobuf:"bytes,3,opt,name=sig,proto3" json:"sig,omitempty"`
// metadata allow to pass custom informations
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *MessageHeaders) Reset() {
*x = MessageHeaders{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MessageHeaders) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MessageHeaders) ProtoMessage() {}
func (x *MessageHeaders) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MessageHeaders.ProtoReflect.Descriptor instead.
func (*MessageHeaders) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{5}
}
func (x *MessageHeaders) GetCounter() uint64 {
if x != nil {
return x.Counter
}
return 0
}
func (x *MessageHeaders) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *MessageHeaders) GetSig() []byte {
if x != nil {
return x.Sig
}
return nil
}
func (x *MessageHeaders) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
type ProtocolMetadata struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ProtocolMetadata) Reset() {
*x = ProtocolMetadata{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProtocolMetadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtocolMetadata) ProtoMessage() {}
func (x *ProtocolMetadata) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtocolMetadata.ProtoReflect.Descriptor instead.
func (*ProtocolMetadata) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{6}
}
// EncryptedMessage is used in MessageEnvelope and only readable by groups members that joined before the message was sent
type EncryptedMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// plaintext is the app layer data
Plaintext []byte `protobuf:"bytes,1,opt,name=plaintext,proto3" json:"plaintext,omitempty"`
// protocol_metadata is protocol layer data
ProtocolMetadata *ProtocolMetadata `protobuf:"bytes,2,opt,name=protocol_metadata,json=protocolMetadata,proto3" json:"protocol_metadata,omitempty"`
}
func (x *EncryptedMessage) Reset() {
*x = EncryptedMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EncryptedMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EncryptedMessage) ProtoMessage() {}
func (x *EncryptedMessage) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EncryptedMessage.ProtoReflect.Descriptor instead.
func (*EncryptedMessage) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{7}
}
func (x *EncryptedMessage) GetPlaintext() []byte {
if x != nil {
return x.Plaintext
}
return nil
}
func (x *EncryptedMessage) GetProtocolMetadata() *ProtocolMetadata {
if x != nil {
return x.ProtocolMetadata
}
return nil
}
// MessageEnvelope is a publicly exposed structure containing a group secure message
type MessageEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// message_headers is an encrypted serialization using a symmetric key of a MessageHeaders message
MessageHeaders []byte `protobuf:"bytes,1,opt,name=message_headers,json=messageHeaders,proto3" json:"message_headers,omitempty"`
// message is an encrypted message, only readable by group members who previously received the appropriate chain key
Message []byte `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
// nonce is a nonce for message headers
Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"`
}
func (x *MessageEnvelope) Reset() {
*x = MessageEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MessageEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MessageEnvelope) ProtoMessage() {}
func (x *MessageEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MessageEnvelope.ProtoReflect.Descriptor instead.
func (*MessageEnvelope) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{8}
}
func (x *MessageEnvelope) GetMessageHeaders() []byte {
if x != nil {
return x.MessageHeaders
}
return nil
}
func (x *MessageEnvelope) GetMessage() []byte {
if x != nil {
return x.Message
}
return nil
}
func (x *MessageEnvelope) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
// EventContext adds context (its id, its parents and its attachments) to an event
type EventContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// id is the CID of the underlying OrbitDB event
Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// id are the the CIDs of the underlying parents of the OrbitDB event
ParentIds [][]byte `protobuf:"bytes,2,rep,name=parent_ids,json=parentIds,proto3" json:"parent_ids,omitempty"`
// group_pk receiving the event
GroupPk []byte `protobuf:"bytes,3,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *EventContext) Reset() {
*x = EventContext{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EventContext) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EventContext) ProtoMessage() {}
func (x *EventContext) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EventContext.ProtoReflect.Descriptor instead.
func (*EventContext) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{9}
}
func (x *EventContext) GetId() []byte {
if x != nil {
return x.Id
}
return nil
}
func (x *EventContext) GetParentIds() [][]byte {
if x != nil {
return x.ParentIds
}
return nil
}
func (x *EventContext) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
// GroupMetadataPayloadSent is an app defined message, accessible to future group members
type GroupMetadataPayloadSent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// message is the payload
Message []byte `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *GroupMetadataPayloadSent) Reset() {
*x = GroupMetadataPayloadSent{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMetadataPayloadSent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMetadataPayloadSent) ProtoMessage() {}
func (x *GroupMetadataPayloadSent) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMetadataPayloadSent.ProtoReflect.Descriptor instead.
func (*GroupMetadataPayloadSent) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{10}
}
func (x *GroupMetadataPayloadSent) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupMetadataPayloadSent) GetMessage() []byte {
if x != nil {
return x.Message
}
return nil
}
// ContactAliasKeyAdded is an event type where ones shares their alias public key
type ContactAliasKeyAdded struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// alias_pk is the alias key which will be used to verify a contact identity
AliasPk []byte `protobuf:"bytes,2,opt,name=alias_pk,json=aliasPk,proto3" json:"alias_pk,omitempty"`
}
func (x *ContactAliasKeyAdded) Reset() {
*x = ContactAliasKeyAdded{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactAliasKeyAdded) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactAliasKeyAdded) ProtoMessage() {}
func (x *ContactAliasKeyAdded) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactAliasKeyAdded.ProtoReflect.Descriptor instead.
func (*ContactAliasKeyAdded) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{11}
}
func (x *ContactAliasKeyAdded) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *ContactAliasKeyAdded) GetAliasPk() []byte {
if x != nil {
return x.AliasPk
}
return nil
}
// GroupMemberDeviceAdded is an event which indicates to a group a new device (and eventually a new member) is joining it
// When added on AccountGroup, this event should be followed by appropriate GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events
type GroupMemberDeviceAdded struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// member_pk is the member sending the event
MemberPk []byte `protobuf:"bytes,1,opt,name=member_pk,json=memberPk,proto3" json:"member_pk,omitempty"`
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,2,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// member_sig is used to prove the ownership of the member pk
MemberSig []byte `protobuf:"bytes,3,opt,name=member_sig,json=memberSig,proto3" json:"member_sig,omitempty"` // TODO: signature of what ??? ensure it can't be replayed
}
func (x *GroupMemberDeviceAdded) Reset() {
*x = GroupMemberDeviceAdded{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMemberDeviceAdded) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMemberDeviceAdded) ProtoMessage() {}
func (x *GroupMemberDeviceAdded) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMemberDeviceAdded.ProtoReflect.Descriptor instead.
func (*GroupMemberDeviceAdded) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{12}
}
func (x *GroupMemberDeviceAdded) GetMemberPk() []byte {
if x != nil {
return x.MemberPk
}
return nil
}
func (x *GroupMemberDeviceAdded) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupMemberDeviceAdded) GetMemberSig() []byte {
if x != nil {
return x.MemberSig
}
return nil
}
// DeviceChainKey is a chain key, which will be encrypted for a specific member of the group
type DeviceChainKey struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// chain_key is the current value of the chain key of the group device
ChainKey []byte `protobuf:"bytes,1,opt,name=chain_key,json=chainKey,proto3" json:"chain_key,omitempty"`
// counter is the current value of the counter of the group device
Counter uint64 `protobuf:"varint,2,opt,name=counter,proto3" json:"counter,omitempty"`
}
func (x *DeviceChainKey) Reset() {
*x = DeviceChainKey{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeviceChainKey) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeviceChainKey) ProtoMessage() {}
func (x *DeviceChainKey) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeviceChainKey.ProtoReflect.Descriptor instead.
func (*DeviceChainKey) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{13}
}
func (x *DeviceChainKey) GetChainKey() []byte {
if x != nil {
return x.ChainKey
}
return nil
}
func (x *DeviceChainKey) GetCounter() uint64 {
if x != nil {
return x.Counter
}
return 0
}
// GroupDeviceChainKeyAdded is an event which indicates to a group member a device chain key
type GroupDeviceChainKeyAdded struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// dest_member_pk is the member who should receive the secret
DestMemberPk []byte `protobuf:"bytes,2,opt,name=dest_member_pk,json=destMemberPk,proto3" json:"dest_member_pk,omitempty"`
// payload is the serialization of Payload encrypted for the specified member
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (x *GroupDeviceChainKeyAdded) Reset() {
*x = GroupDeviceChainKeyAdded{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceChainKeyAdded) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceChainKeyAdded) ProtoMessage() {}
func (x *GroupDeviceChainKeyAdded) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceChainKeyAdded.ProtoReflect.Descriptor instead.
func (*GroupDeviceChainKeyAdded) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{14}
}
func (x *GroupDeviceChainKeyAdded) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupDeviceChainKeyAdded) GetDestMemberPk() []byte {
if x != nil {
return x.DestMemberPk
}
return nil
}
func (x *GroupDeviceChainKeyAdded) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
// MultiMemberGroupAliasResolverAdded indicates that a group member want to disclose their presence in the group to their contacts
type MultiMemberGroupAliasResolverAdded struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// alias_resolver allows contact of an account to resolve the real identity behind an alias (Multi-Member Group Member)
// Generated by both contacts and account independently using: hmac(aliasPK, GroupID)
AliasResolver []byte `protobuf:"bytes,2,opt,name=alias_resolver,json=aliasResolver,proto3" json:"alias_resolver,omitempty"`
// alias_proof ensures that the associated alias_resolver has been issued by the right account
// Generated using aliasSKSig(GroupID)
AliasProof []byte `protobuf:"bytes,3,opt,name=alias_proof,json=aliasProof,proto3" json:"alias_proof,omitempty"`
}
func (x *MultiMemberGroupAliasResolverAdded) Reset() {
*x = MultiMemberGroupAliasResolverAdded{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAliasResolverAdded) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAliasResolverAdded) ProtoMessage() {}
func (x *MultiMemberGroupAliasResolverAdded) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAliasResolverAdded.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAliasResolverAdded) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{15}
}
func (x *MultiMemberGroupAliasResolverAdded) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *MultiMemberGroupAliasResolverAdded) GetAliasResolver() []byte {
if x != nil {
return x.AliasResolver
}
return nil
}
func (x *MultiMemberGroupAliasResolverAdded) GetAliasProof() []byte {
if x != nil {
return x.AliasProof
}
return nil
}
// MultiMemberGroupAdminRoleGranted indicates that a group admin allows another group member to act as an admin
type MultiMemberGroupAdminRoleGranted struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// grantee_member_pk is the member public key of the member granted of the admin role
GranteeMemberPk []byte `protobuf:"bytes,2,opt,name=grantee_member_pk,json=granteeMemberPk,proto3" json:"grantee_member_pk,omitempty"`
}
func (x *MultiMemberGroupAdminRoleGranted) Reset() {
*x = MultiMemberGroupAdminRoleGranted{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAdminRoleGranted) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAdminRoleGranted) ProtoMessage() {}
func (x *MultiMemberGroupAdminRoleGranted) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAdminRoleGranted.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAdminRoleGranted) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{16}
}
func (x *MultiMemberGroupAdminRoleGranted) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *MultiMemberGroupAdminRoleGranted) GetGranteeMemberPk() []byte {
if x != nil {
return x.GranteeMemberPk
}
return nil
}
// MultiMemberGroupInitialMemberAnnounced indicates that a member is the group creator, this event is signed using the group ID private key
type MultiMemberGroupInitialMemberAnnounced struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// member_pk is the public key of the member who is the group creator
MemberPk []byte `protobuf:"bytes,1,opt,name=member_pk,json=memberPk,proto3" json:"member_pk,omitempty"`
}
func (x *MultiMemberGroupInitialMemberAnnounced) Reset() {
*x = MultiMemberGroupInitialMemberAnnounced{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupInitialMemberAnnounced) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupInitialMemberAnnounced) ProtoMessage() {}
func (x *MultiMemberGroupInitialMemberAnnounced) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupInitialMemberAnnounced.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupInitialMemberAnnounced) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{17}
}
func (x *MultiMemberGroupInitialMemberAnnounced) GetMemberPk() []byte {
if x != nil {
return x.MemberPk
}
return nil
}
// GroupAddAdditionalRendezvousSeed indicates that an additional rendezvous point should be used for data synchronization
type GroupAddAdditionalRendezvousSeed struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// seed is the additional rendezvous point seed which should be used
Seed []byte `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"`
}
func (x *GroupAddAdditionalRendezvousSeed) Reset() {
*x = GroupAddAdditionalRendezvousSeed{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupAddAdditionalRendezvousSeed) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupAddAdditionalRendezvousSeed) ProtoMessage() {}
func (x *GroupAddAdditionalRendezvousSeed) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupAddAdditionalRendezvousSeed.ProtoReflect.Descriptor instead.
func (*GroupAddAdditionalRendezvousSeed) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{18}
}
func (x *GroupAddAdditionalRendezvousSeed) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupAddAdditionalRendezvousSeed) GetSeed() []byte {
if x != nil {
return x.Seed
}
return nil
}
// GroupRemoveAdditionalRendezvousSeed indicates that a previously added rendezvous point should be removed
type GroupRemoveAdditionalRendezvousSeed struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message, must be the device of an admin of the group
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// seed is the additional rendezvous point seed which should be removed
Seed []byte `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"`
}
func (x *GroupRemoveAdditionalRendezvousSeed) Reset() {
*x = GroupRemoveAdditionalRendezvousSeed{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupRemoveAdditionalRendezvousSeed) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupRemoveAdditionalRendezvousSeed) ProtoMessage() {}
func (x *GroupRemoveAdditionalRendezvousSeed) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupRemoveAdditionalRendezvousSeed.ProtoReflect.Descriptor instead.
func (*GroupRemoveAdditionalRendezvousSeed) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{19}
}
func (x *GroupRemoveAdditionalRendezvousSeed) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupRemoveAdditionalRendezvousSeed) GetSeed() []byte {
if x != nil {
return x.Seed
}
return nil
}
// AccountGroupJoined indicates that the account is now part of a new group
type AccountGroupJoined struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// group describe the joined group
Group *Group `protobuf:"bytes,2,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *AccountGroupJoined) Reset() {
*x = AccountGroupJoined{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountGroupJoined) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountGroupJoined) ProtoMessage() {}
func (x *AccountGroupJoined) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[20]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountGroupJoined.ProtoReflect.Descriptor instead.
func (*AccountGroupJoined) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{20}
}
func (x *AccountGroupJoined) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountGroupJoined) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
// AccountGroupLeft indicates that the account has left a group
type AccountGroupLeft struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// group_pk references the group left
GroupPk []byte `protobuf:"bytes,2,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *AccountGroupLeft) Reset() {
*x = AccountGroupLeft{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountGroupLeft) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountGroupLeft) ProtoMessage() {}
func (x *AccountGroupLeft) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[21]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountGroupLeft.ProtoReflect.Descriptor instead.
func (*AccountGroupLeft) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{21}
}
func (x *AccountGroupLeft) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountGroupLeft) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
// AccountContactRequestDisabled indicates that the account should not be advertised on a public rendezvous point
type AccountContactRequestDisabled struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
}
func (x *AccountContactRequestDisabled) Reset() {
*x = AccountContactRequestDisabled{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestDisabled) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestDisabled) ProtoMessage() {}
func (x *AccountContactRequestDisabled) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[22]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestDisabled.ProtoReflect.Descriptor instead.
func (*AccountContactRequestDisabled) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{22}
}
func (x *AccountContactRequestDisabled) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
// AccountContactRequestEnabled indicates that the account should be advertised on a public rendezvous point
type AccountContactRequestEnabled struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
}
func (x *AccountContactRequestEnabled) Reset() {
*x = AccountContactRequestEnabled{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestEnabled) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestEnabled) ProtoMessage() {}
func (x *AccountContactRequestEnabled) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[23]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestEnabled.ProtoReflect.Descriptor instead.
func (*AccountContactRequestEnabled) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{23}
}
func (x *AccountContactRequestEnabled) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
// AccountContactRequestReferenceReset indicates that the account should be advertised on different public rendezvous points
type AccountContactRequestReferenceReset struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// public_rendezvous_seed is the new rendezvous point seed
PublicRendezvousSeed []byte `protobuf:"bytes,2,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
}
func (x *AccountContactRequestReferenceReset) Reset() {
*x = AccountContactRequestReferenceReset{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestReferenceReset) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestReferenceReset) ProtoMessage() {}
func (x *AccountContactRequestReferenceReset) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[24]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestReferenceReset.ProtoReflect.Descriptor instead.
func (*AccountContactRequestReferenceReset) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{24}
}
func (x *AccountContactRequestReferenceReset) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestReferenceReset) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
// This event should be followed by an AccountGroupJoined event
// This event should be followed by a GroupMemberDeviceAdded event within the AccountGroup
// This event should be followed by a GroupDeviceChainKeyAdded event within the AccountGroup
// AccountContactRequestOutgoingEnqueued indicates that the account will attempt to send a contact request when a matching peer is discovered
type AccountContactRequestOutgoingEnqueued struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// group_pk is the 1to1 group with the requested user
GroupPk []byte `protobuf:"bytes,2,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// contact is a message describing how to connect to the other account
Contact *ShareableContact `protobuf:"bytes,3,opt,name=contact,proto3" json:"contact,omitempty"`
// own_metadata is the identifying metadata that will be shared to the other account
OwnMetadata []byte `protobuf:"bytes,4,opt,name=own_metadata,json=ownMetadata,proto3" json:"own_metadata,omitempty"`
}
func (x *AccountContactRequestOutgoingEnqueued) Reset() {
*x = AccountContactRequestOutgoingEnqueued{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestOutgoingEnqueued) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestOutgoingEnqueued) ProtoMessage() {}
func (x *AccountContactRequestOutgoingEnqueued) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[25]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestOutgoingEnqueued.ProtoReflect.Descriptor instead.
func (*AccountContactRequestOutgoingEnqueued) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{25}
}
func (x *AccountContactRequestOutgoingEnqueued) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestOutgoingEnqueued) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *AccountContactRequestOutgoingEnqueued) GetContact() *ShareableContact {
if x != nil {
return x.Contact
}
return nil
}
func (x *AccountContactRequestOutgoingEnqueued) GetOwnMetadata() []byte {
if x != nil {
return x.OwnMetadata
}
return nil
}
// AccountContactRequestOutgoingSent indicates that the account has sent a contact request
type AccountContactRequestOutgoingSent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the account event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the contacted account
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *AccountContactRequestOutgoingSent) Reset() {
*x = AccountContactRequestOutgoingSent{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestOutgoingSent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestOutgoingSent) ProtoMessage() {}
func (x *AccountContactRequestOutgoingSent) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[26]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestOutgoingSent.ProtoReflect.Descriptor instead.
func (*AccountContactRequestOutgoingSent) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{26}
}
func (x *AccountContactRequestOutgoingSent) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestOutgoingSent) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
// AccountContactRequestIncomingReceived indicates that the account has received a new contact request
type AccountContactRequestIncomingReceived struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the account event (which received the contact request), signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the account sending the request
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
// TODO: is this necessary?
// contact_rendezvous_seed is the rendezvous seed of the contact sending the request
ContactRendezvousSeed []byte `protobuf:"bytes,3,opt,name=contact_rendezvous_seed,json=contactRendezvousSeed,proto3" json:"contact_rendezvous_seed,omitempty"`
// TODO: is this necessary?
// contact_metadata is the metadata specific to the app to identify the contact for the request
ContactMetadata []byte `protobuf:"bytes,4,opt,name=contact_metadata,json=contactMetadata,proto3" json:"contact_metadata,omitempty"`
}
func (x *AccountContactRequestIncomingReceived) Reset() {
*x = AccountContactRequestIncomingReceived{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestIncomingReceived) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestIncomingReceived) ProtoMessage() {}
func (x *AccountContactRequestIncomingReceived) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[27]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestIncomingReceived.ProtoReflect.Descriptor instead.
func (*AccountContactRequestIncomingReceived) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{27}
}
func (x *AccountContactRequestIncomingReceived) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestIncomingReceived) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
func (x *AccountContactRequestIncomingReceived) GetContactRendezvousSeed() []byte {
if x != nil {
return x.ContactRendezvousSeed
}
return nil
}
func (x *AccountContactRequestIncomingReceived) GetContactMetadata() []byte {
if x != nil {
return x.ContactMetadata
}
return nil
}
// AccountContactRequestIncomingDiscarded indicates that a contact request has been refused
type AccountContactRequestIncomingDiscarded struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the contact whom request is refused
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *AccountContactRequestIncomingDiscarded) Reset() {
*x = AccountContactRequestIncomingDiscarded{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestIncomingDiscarded) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestIncomingDiscarded) ProtoMessage() {}
func (x *AccountContactRequestIncomingDiscarded) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[28]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestIncomingDiscarded.ProtoReflect.Descriptor instead.
func (*AccountContactRequestIncomingDiscarded) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{28}
}
func (x *AccountContactRequestIncomingDiscarded) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestIncomingDiscarded) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
// This event should be followed by an AccountGroupJoined event
// This event should be followed by GroupMemberDeviceAdded and GroupDeviceChainKeyAdded events within the AccountGroup
// AccountContactRequestIncomingAccepted indicates that a contact request has been accepted
type AccountContactRequestIncomingAccepted struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the contact whom request is accepted
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
// group_pk is the 1to1 group with the requester user
GroupPk []byte `protobuf:"bytes,3,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *AccountContactRequestIncomingAccepted) Reset() {
*x = AccountContactRequestIncomingAccepted{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[29]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactRequestIncomingAccepted) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactRequestIncomingAccepted) ProtoMessage() {}
func (x *AccountContactRequestIncomingAccepted) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[29]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactRequestIncomingAccepted.ProtoReflect.Descriptor instead.
func (*AccountContactRequestIncomingAccepted) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{29}
}
func (x *AccountContactRequestIncomingAccepted) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactRequestIncomingAccepted) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
func (x *AccountContactRequestIncomingAccepted) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
// AccountContactBlocked indicates that a contact is blocked
type AccountContactBlocked struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the contact blocked
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *AccountContactBlocked) Reset() {
*x = AccountContactBlocked{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[30]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactBlocked) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactBlocked) ProtoMessage() {}
func (x *AccountContactBlocked) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[30]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactBlocked.ProtoReflect.Descriptor instead.
func (*AccountContactBlocked) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{30}
}
func (x *AccountContactBlocked) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactBlocked) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
// AccountContactUnblocked indicates that a contact is unblocked
type AccountContactUnblocked struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// contact_pk is the contact unblocked
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *AccountContactUnblocked) Reset() {
*x = AccountContactUnblocked{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[31]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountContactUnblocked) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountContactUnblocked) ProtoMessage() {}
func (x *AccountContactUnblocked) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[31]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountContactUnblocked.ProtoReflect.Descriptor instead.
func (*AccountContactUnblocked) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{31}
}
func (x *AccountContactUnblocked) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountContactUnblocked) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type GroupReplicating struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the device sending the event, signs the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// authentication_url indicates which server has been used for authentication
AuthenticationUrl string `protobuf:"bytes,2,opt,name=authentication_url,json=authenticationUrl,proto3" json:"authentication_url,omitempty"`
// replication_server indicates which server will be used for replication
ReplicationServer string `protobuf:"bytes,3,opt,name=replication_server,json=replicationServer,proto3" json:"replication_server,omitempty"`
}
func (x *GroupReplicating) Reset() {
*x = GroupReplicating{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[32]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupReplicating) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupReplicating) ProtoMessage() {}
func (x *GroupReplicating) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[32]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupReplicating.ProtoReflect.Descriptor instead.
func (*GroupReplicating) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{32}
}
func (x *GroupReplicating) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupReplicating) GetAuthenticationUrl() string {
if x != nil {
return x.AuthenticationUrl
}
return ""
}
func (x *GroupReplicating) GetReplicationServer() string {
if x != nil {
return x.ReplicationServer
}
return ""
}
type ServiceExportData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ServiceExportData) Reset() {
*x = ServiceExportData{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[33]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceExportData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceExportData) ProtoMessage() {}
func (x *ServiceExportData) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[33]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceExportData.ProtoReflect.Descriptor instead.
func (*ServiceExportData) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{33}
}
type ServiceGetConfiguration struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ServiceGetConfiguration) Reset() {
*x = ServiceGetConfiguration{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[34]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceGetConfiguration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceGetConfiguration) ProtoMessage() {}
func (x *ServiceGetConfiguration) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[34]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceGetConfiguration.ProtoReflect.Descriptor instead.
func (*ServiceGetConfiguration) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{34}
}
type ContactRequestReference struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestReference) Reset() {
*x = ContactRequestReference{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[35]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestReference) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestReference) ProtoMessage() {}
func (x *ContactRequestReference) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[35]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestReference.ProtoReflect.Descriptor instead.
func (*ContactRequestReference) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{35}
}
type ContactRequestDisable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestDisable) Reset() {
*x = ContactRequestDisable{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[36]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDisable) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDisable) ProtoMessage() {}
func (x *ContactRequestDisable) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[36]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDisable.ProtoReflect.Descriptor instead.
func (*ContactRequestDisable) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{36}
}
type ContactRequestEnable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestEnable) Reset() {
*x = ContactRequestEnable{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[37]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestEnable) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestEnable) ProtoMessage() {}
func (x *ContactRequestEnable) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[37]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestEnable.ProtoReflect.Descriptor instead.
func (*ContactRequestEnable) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{37}
}
type ContactRequestResetReference struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestResetReference) Reset() {
*x = ContactRequestResetReference{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[38]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestResetReference) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestResetReference) ProtoMessage() {}
func (x *ContactRequestResetReference) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[38]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestResetReference.ProtoReflect.Descriptor instead.
func (*ContactRequestResetReference) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{38}
}
type ContactRequestSend struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestSend) Reset() {
*x = ContactRequestSend{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[39]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestSend) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestSend) ProtoMessage() {}
func (x *ContactRequestSend) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[39]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestSend.ProtoReflect.Descriptor instead.
func (*ContactRequestSend) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{39}
}
type ContactRequestAccept struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestAccept) Reset() {
*x = ContactRequestAccept{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[40]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestAccept) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestAccept) ProtoMessage() {}
func (x *ContactRequestAccept) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[40]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestAccept.ProtoReflect.Descriptor instead.
func (*ContactRequestAccept) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{40}
}
type ContactRequestDiscard struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestDiscard) Reset() {
*x = ContactRequestDiscard{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[41]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDiscard) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDiscard) ProtoMessage() {}
func (x *ContactRequestDiscard) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[41]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDiscard.ProtoReflect.Descriptor instead.
func (*ContactRequestDiscard) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{41}
}
type ShareContact struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ShareContact) Reset() {
*x = ShareContact{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[42]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ShareContact) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShareContact) ProtoMessage() {}
func (x *ShareContact) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[42]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShareContact.ProtoReflect.Descriptor instead.
func (*ShareContact) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{42}
}
type DecodeContact struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DecodeContact) Reset() {
*x = DecodeContact{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[43]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DecodeContact) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeContact) ProtoMessage() {}
func (x *DecodeContact) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[43]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeContact.ProtoReflect.Descriptor instead.
func (*DecodeContact) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{43}
}
type ContactBlock struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactBlock) Reset() {
*x = ContactBlock{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[44]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactBlock) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactBlock) ProtoMessage() {}
func (x *ContactBlock) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[44]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactBlock.ProtoReflect.Descriptor instead.
func (*ContactBlock) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{44}
}
type ContactUnblock struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactUnblock) Reset() {
*x = ContactUnblock{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[45]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactUnblock) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactUnblock) ProtoMessage() {}
func (x *ContactUnblock) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[45]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactUnblock.ProtoReflect.Descriptor instead.
func (*ContactUnblock) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{45}
}
type ContactAliasKeySend struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactAliasKeySend) Reset() {
*x = ContactAliasKeySend{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[46]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactAliasKeySend) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactAliasKeySend) ProtoMessage() {}
func (x *ContactAliasKeySend) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[46]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactAliasKeySend.ProtoReflect.Descriptor instead.
func (*ContactAliasKeySend) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{46}
}
type MultiMemberGroupCreate struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupCreate) Reset() {
*x = MultiMemberGroupCreate{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[47]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupCreate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupCreate) ProtoMessage() {}
func (x *MultiMemberGroupCreate) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[47]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupCreate.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupCreate) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{47}
}
type MultiMemberGroupJoin struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupJoin) Reset() {
*x = MultiMemberGroupJoin{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[48]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupJoin) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupJoin) ProtoMessage() {}
func (x *MultiMemberGroupJoin) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[48]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupJoin.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupJoin) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{48}
}
type MultiMemberGroupLeave struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupLeave) Reset() {
*x = MultiMemberGroupLeave{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[49]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupLeave) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupLeave) ProtoMessage() {}
func (x *MultiMemberGroupLeave) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[49]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupLeave.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupLeave) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{49}
}
type MultiMemberGroupAliasResolverDisclose struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupAliasResolverDisclose) Reset() {
*x = MultiMemberGroupAliasResolverDisclose{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[50]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAliasResolverDisclose) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAliasResolverDisclose) ProtoMessage() {}
func (x *MultiMemberGroupAliasResolverDisclose) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[50]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAliasResolverDisclose.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAliasResolverDisclose) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{50}
}
type MultiMemberGroupAdminRoleGrant struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupAdminRoleGrant) Reset() {
*x = MultiMemberGroupAdminRoleGrant{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[51]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAdminRoleGrant) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAdminRoleGrant) ProtoMessage() {}
func (x *MultiMemberGroupAdminRoleGrant) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[51]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAdminRoleGrant.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAdminRoleGrant) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{51}
}
type MultiMemberGroupInvitationCreate struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupInvitationCreate) Reset() {
*x = MultiMemberGroupInvitationCreate{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[52]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupInvitationCreate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupInvitationCreate) ProtoMessage() {}
func (x *MultiMemberGroupInvitationCreate) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[52]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupInvitationCreate.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupInvitationCreate) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{52}
}
type AppMetadataSend struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AppMetadataSend) Reset() {
*x = AppMetadataSend{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[53]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMetadataSend) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMetadataSend) ProtoMessage() {}
func (x *AppMetadataSend) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[53]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMetadataSend.ProtoReflect.Descriptor instead.
func (*AppMetadataSend) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{53}
}
type AppMessageSend struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AppMessageSend) Reset() {
*x = AppMessageSend{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[54]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMessageSend) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMessageSend) ProtoMessage() {}
func (x *AppMessageSend) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[54]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMessageSend.ProtoReflect.Descriptor instead.
func (*AppMessageSend) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{54}
}
type GroupMetadataEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// event_context contains context information about the event
EventContext *EventContext `protobuf:"bytes,1,opt,name=event_context,json=eventContext,proto3" json:"event_context,omitempty"`
// metadata contains the newly available metadata
Metadata *GroupMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
// event_clear clear bytes for the event
Event []byte `protobuf:"bytes,3,opt,name=event,proto3" json:"event,omitempty"`
}
func (x *GroupMetadataEvent) Reset() {
*x = GroupMetadataEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[55]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMetadataEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMetadataEvent) ProtoMessage() {}
func (x *GroupMetadataEvent) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[55]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMetadataEvent.ProtoReflect.Descriptor instead.
func (*GroupMetadataEvent) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{55}
}
func (x *GroupMetadataEvent) GetEventContext() *EventContext {
if x != nil {
return x.EventContext
}
return nil
}
func (x *GroupMetadataEvent) GetMetadata() *GroupMetadata {
if x != nil {
return x.Metadata
}
return nil
}
func (x *GroupMetadataEvent) GetEvent() []byte {
if x != nil {
return x.Event
}
return nil
}
type GroupMessageEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// event_context contains context information about the event
EventContext *EventContext `protobuf:"bytes,1,opt,name=event_context,json=eventContext,proto3" json:"event_context,omitempty"`
// headers contains headers of the secure message
Headers *MessageHeaders `protobuf:"bytes,2,opt,name=headers,proto3" json:"headers,omitempty"`
// message contains the secure message payload
Message []byte `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *GroupMessageEvent) Reset() {
*x = GroupMessageEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[56]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMessageEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMessageEvent) ProtoMessage() {}
func (x *GroupMessageEvent) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[56]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMessageEvent.ProtoReflect.Descriptor instead.
func (*GroupMessageEvent) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{56}
}
func (x *GroupMessageEvent) GetEventContext() *EventContext {
if x != nil {
return x.EventContext
}
return nil
}
func (x *GroupMessageEvent) GetHeaders() *MessageHeaders {
if x != nil {
return x.Headers
}
return nil
}
func (x *GroupMessageEvent) GetMessage() []byte {
if x != nil {
return x.Message
}
return nil
}
type GroupMetadataList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GroupMetadataList) Reset() {
*x = GroupMetadataList{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[57]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMetadataList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMetadataList) ProtoMessage() {}
func (x *GroupMetadataList) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[57]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMetadataList.ProtoReflect.Descriptor instead.
func (*GroupMetadataList) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{57}
}
type GroupMessageList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GroupMessageList) Reset() {
*x = GroupMessageList{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[58]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMessageList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMessageList) ProtoMessage() {}
func (x *GroupMessageList) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[58]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMessageList.ProtoReflect.Descriptor instead.
func (*GroupMessageList) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{58}
}
type GroupInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GroupInfo) Reset() {
*x = GroupInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[59]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupInfo) ProtoMessage() {}
func (x *GroupInfo) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[59]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupInfo.ProtoReflect.Descriptor instead.
func (*GroupInfo) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{59}
}
type ActivateGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ActivateGroup) Reset() {
*x = ActivateGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[60]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ActivateGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ActivateGroup) ProtoMessage() {}
func (x *ActivateGroup) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[60]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ActivateGroup.ProtoReflect.Descriptor instead.
func (*ActivateGroup) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{60}
}
type DeactivateGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DeactivateGroup) Reset() {
*x = DeactivateGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[61]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeactivateGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeactivateGroup) ProtoMessage() {}
func (x *DeactivateGroup) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[61]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeactivateGroup.ProtoReflect.Descriptor instead.
func (*DeactivateGroup) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{61}
}
type GroupDeviceStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GroupDeviceStatus) Reset() {
*x = GroupDeviceStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[62]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus) ProtoMessage() {}
func (x *GroupDeviceStatus) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[62]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62}
}
type DebugListGroups struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DebugListGroups) Reset() {
*x = DebugListGroups{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[63]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugListGroups) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugListGroups) ProtoMessage() {}
func (x *DebugListGroups) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[63]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugListGroups.ProtoReflect.Descriptor instead.
func (*DebugListGroups) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{63}
}
type DebugInspectGroupStore struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DebugInspectGroupStore) Reset() {
*x = DebugInspectGroupStore{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[64]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugInspectGroupStore) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugInspectGroupStore) ProtoMessage() {}
func (x *DebugInspectGroupStore) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[64]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugInspectGroupStore.ProtoReflect.Descriptor instead.
func (*DebugInspectGroupStore) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{64}
}
type DebugGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DebugGroup) Reset() {
*x = DebugGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[65]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugGroup) ProtoMessage() {}
func (x *DebugGroup) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[65]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugGroup.ProtoReflect.Descriptor instead.
func (*DebugGroup) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{65}
}
type ShareableContact struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// pk is the account to send a contact request to
Pk []byte `protobuf:"bytes,1,opt,name=pk,proto3" json:"pk,omitempty"`
// public_rendezvous_seed is the rendezvous seed used by the account to send a contact request to
PublicRendezvousSeed []byte `protobuf:"bytes,2,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
// metadata is the metadata specific to the app to identify the contact for the request
Metadata []byte `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
}
func (x *ShareableContact) Reset() {
*x = ShareableContact{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[66]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ShareableContact) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShareableContact) ProtoMessage() {}
func (x *ShareableContact) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[66]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShareableContact.ProtoReflect.Descriptor instead.
func (*ShareableContact) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{66}
}
func (x *ShareableContact) GetPk() []byte {
if x != nil {
return x.Pk
}
return nil
}
func (x *ShareableContact) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
func (x *ShareableContact) GetMetadata() []byte {
if x != nil {
return x.Metadata
}
return nil
}
type ServiceTokenSupportedService struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ServiceType string `protobuf:"bytes,1,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"`
ServiceEndpoint string `protobuf:"bytes,2,opt,name=service_endpoint,json=serviceEndpoint,proto3" json:"service_endpoint,omitempty"`
}
func (x *ServiceTokenSupportedService) Reset() {
*x = ServiceTokenSupportedService{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[67]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceTokenSupportedService) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceTokenSupportedService) ProtoMessage() {}
func (x *ServiceTokenSupportedService) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[67]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceTokenSupportedService.ProtoReflect.Descriptor instead.
func (*ServiceTokenSupportedService) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{67}
}
func (x *ServiceTokenSupportedService) GetServiceType() string {
if x != nil {
return x.ServiceType
}
return ""
}
func (x *ServiceTokenSupportedService) GetServiceEndpoint() string {
if x != nil {
return x.ServiceEndpoint
}
return ""
}
type ServiceToken struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
AuthenticationUrl string `protobuf:"bytes,2,opt,name=authentication_url,json=authenticationUrl,proto3" json:"authentication_url,omitempty"`
SupportedServices []*ServiceTokenSupportedService `protobuf:"bytes,3,rep,name=supported_services,json=supportedServices,proto3" json:"supported_services,omitempty"`
Expiration int64 `protobuf:"varint,4,opt,name=expiration,proto3" json:"expiration,omitempty"`
}
func (x *ServiceToken) Reset() {
*x = ServiceToken{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[68]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceToken) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceToken) ProtoMessage() {}
func (x *ServiceToken) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[68]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceToken.ProtoReflect.Descriptor instead.
func (*ServiceToken) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{68}
}
func (x *ServiceToken) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *ServiceToken) GetAuthenticationUrl() string {
if x != nil {
return x.AuthenticationUrl
}
return ""
}
func (x *ServiceToken) GetSupportedServices() []*ServiceTokenSupportedService {
if x != nil {
return x.SupportedServices
}
return nil
}
func (x *ServiceToken) GetExpiration() int64 {
if x != nil {
return x.Expiration
}
return 0
}
type CredentialVerificationServiceInitFlow struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *CredentialVerificationServiceInitFlow) Reset() {
*x = CredentialVerificationServiceInitFlow{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[69]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceInitFlow) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceInitFlow) ProtoMessage() {}
func (x *CredentialVerificationServiceInitFlow) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[69]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceInitFlow.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceInitFlow) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{69}
}
type CredentialVerificationServiceCompleteFlow struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *CredentialVerificationServiceCompleteFlow) Reset() {
*x = CredentialVerificationServiceCompleteFlow{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[70]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceCompleteFlow) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceCompleteFlow) ProtoMessage() {}
func (x *CredentialVerificationServiceCompleteFlow) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[70]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceCompleteFlow.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceCompleteFlow) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{70}
}
type VerifiedCredentialsList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *VerifiedCredentialsList) Reset() {
*x = VerifiedCredentialsList{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[71]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VerifiedCredentialsList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VerifiedCredentialsList) ProtoMessage() {}
func (x *VerifiedCredentialsList) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[71]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VerifiedCredentialsList.ProtoReflect.Descriptor instead.
func (*VerifiedCredentialsList) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{71}
}
type ReplicationServiceRegisterGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicationServiceRegisterGroup) Reset() {
*x = ReplicationServiceRegisterGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[72]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceRegisterGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceRegisterGroup) ProtoMessage() {}
func (x *ReplicationServiceRegisterGroup) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[72]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceRegisterGroup.ProtoReflect.Descriptor instead.
func (*ReplicationServiceRegisterGroup) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{72}
}
type ReplicationServiceReplicateGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicationServiceReplicateGroup) Reset() {
*x = ReplicationServiceReplicateGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[73]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[73]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{73}
}
type SystemInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *SystemInfo) Reset() {
*x = SystemInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[74]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo) ProtoMessage() {}
func (x *SystemInfo) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[74]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo.ProtoReflect.Descriptor instead.
func (*SystemInfo) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74}
}
type PeerList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *PeerList) Reset() {
*x = PeerList{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[75]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList) ProtoMessage() {}
func (x *PeerList) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[75]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList.ProtoReflect.Descriptor instead.
func (*PeerList) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75}
}
// Progress define a generic object that can be used to display a progress bar for long-running actions.
type Progress struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
State string `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
Doing string `protobuf:"bytes,2,opt,name=doing,proto3" json:"doing,omitempty"`
Progress float32 `protobuf:"fixed32,3,opt,name=progress,proto3" json:"progress,omitempty"`
Completed uint64 `protobuf:"varint,4,opt,name=completed,proto3" json:"completed,omitempty"`
Total uint64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
Delay uint64 `protobuf:"varint,6,opt,name=delay,proto3" json:"delay,omitempty"`
}
func (x *Progress) Reset() {
*x = Progress{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[76]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Progress) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Progress) ProtoMessage() {}
func (x *Progress) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[76]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Progress.ProtoReflect.Descriptor instead.
func (*Progress) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{76}
}
func (x *Progress) GetState() string {
if x != nil {
return x.State
}
return ""
}
func (x *Progress) GetDoing() string {
if x != nil {
return x.Doing
}
return ""
}
func (x *Progress) GetProgress() float32 {
if x != nil {
return x.Progress
}
return 0
}
func (x *Progress) GetCompleted() uint64 {
if x != nil {
return x.Completed
}
return 0
}
func (x *Progress) GetTotal() uint64 {
if x != nil {
return x.Total
}
return 0
}
func (x *Progress) GetDelay() uint64 {
if x != nil {
return x.Delay
}
return 0
}
type OutOfStoreMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cid []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
DevicePk []byte `protobuf:"bytes,2,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
Counter uint64 `protobuf:"fixed64,3,opt,name=counter,proto3" json:"counter,omitempty"`
Sig []byte `protobuf:"bytes,4,opt,name=sig,proto3" json:"sig,omitempty"`
Flags uint32 `protobuf:"fixed32,5,opt,name=flags,proto3" json:"flags,omitempty"`
EncryptedPayload []byte `protobuf:"bytes,6,opt,name=encrypted_payload,json=encryptedPayload,proto3" json:"encrypted_payload,omitempty"`
Nonce []byte `protobuf:"bytes,7,opt,name=nonce,proto3" json:"nonce,omitempty"`
}
func (x *OutOfStoreMessage) Reset() {
*x = OutOfStoreMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[77]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreMessage) ProtoMessage() {}
func (x *OutOfStoreMessage) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[77]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreMessage.ProtoReflect.Descriptor instead.
func (*OutOfStoreMessage) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{77}
}
func (x *OutOfStoreMessage) GetCid() []byte {
if x != nil {
return x.Cid
}
return nil
}
func (x *OutOfStoreMessage) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *OutOfStoreMessage) GetCounter() uint64 {
if x != nil {
return x.Counter
}
return 0
}
func (x *OutOfStoreMessage) GetSig() []byte {
if x != nil {
return x.Sig
}
return nil
}
func (x *OutOfStoreMessage) GetFlags() uint32 {
if x != nil {
return x.Flags
}
return 0
}
func (x *OutOfStoreMessage) GetEncryptedPayload() []byte {
if x != nil {
return x.EncryptedPayload
}
return nil
}
func (x *OutOfStoreMessage) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
type OutOfStoreMessageEnvelope struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
Box []byte `protobuf:"bytes,2,opt,name=box,proto3" json:"box,omitempty"`
GroupReference []byte `protobuf:"bytes,3,opt,name=group_reference,json=groupReference,proto3" json:"group_reference,omitempty"`
}
func (x *OutOfStoreMessageEnvelope) Reset() {
*x = OutOfStoreMessageEnvelope{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[78]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreMessageEnvelope) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreMessageEnvelope) ProtoMessage() {}
func (x *OutOfStoreMessageEnvelope) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[78]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreMessageEnvelope.ProtoReflect.Descriptor instead.
func (*OutOfStoreMessageEnvelope) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{78}
}
func (x *OutOfStoreMessageEnvelope) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
func (x *OutOfStoreMessageEnvelope) GetBox() []byte {
if x != nil {
return x.Box
}
return nil
}
func (x *OutOfStoreMessageEnvelope) GetGroupReference() []byte {
if x != nil {
return x.GroupReference
}
return nil
}
type OutOfStoreReceive struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *OutOfStoreReceive) Reset() {
*x = OutOfStoreReceive{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[79]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreReceive) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreReceive) ProtoMessage() {}
func (x *OutOfStoreReceive) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[79]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreReceive.ProtoReflect.Descriptor instead.
func (*OutOfStoreReceive) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{79}
}
type OutOfStoreSeal struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *OutOfStoreSeal) Reset() {
*x = OutOfStoreSeal{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[80]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreSeal) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreSeal) ProtoMessage() {}
func (x *OutOfStoreSeal) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[80]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreSeal.ProtoReflect.Descriptor instead.
func (*OutOfStoreSeal) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{80}
}
type AccountVerifiedCredentialRegistered struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// device_pk is the public key of the device sending the message
DevicePk []byte `protobuf:"bytes,1,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
SignedIdentityPublicKey []byte `protobuf:"bytes,2,opt,name=signed_identity_public_key,json=signedIdentityPublicKey,proto3" json:"signed_identity_public_key,omitempty"`
VerifiedCredential string `protobuf:"bytes,3,opt,name=verified_credential,json=verifiedCredential,proto3" json:"verified_credential,omitempty"`
RegistrationDate int64 `protobuf:"varint,4,opt,name=registration_date,json=registrationDate,proto3" json:"registration_date,omitempty"`
ExpirationDate int64 `protobuf:"varint,5,opt,name=expiration_date,json=expirationDate,proto3" json:"expiration_date,omitempty"`
Identifier string `protobuf:"bytes,6,opt,name=identifier,proto3" json:"identifier,omitempty"`
Issuer string `protobuf:"bytes,7,opt,name=issuer,proto3" json:"issuer,omitempty"`
}
func (x *AccountVerifiedCredentialRegistered) Reset() {
*x = AccountVerifiedCredentialRegistered{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[81]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountVerifiedCredentialRegistered) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountVerifiedCredentialRegistered) ProtoMessage() {}
func (x *AccountVerifiedCredentialRegistered) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[81]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountVerifiedCredentialRegistered.ProtoReflect.Descriptor instead.
func (*AccountVerifiedCredentialRegistered) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{81}
}
func (x *AccountVerifiedCredentialRegistered) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *AccountVerifiedCredentialRegistered) GetSignedIdentityPublicKey() []byte {
if x != nil {
return x.SignedIdentityPublicKey
}
return nil
}
func (x *AccountVerifiedCredentialRegistered) GetVerifiedCredential() string {
if x != nil {
return x.VerifiedCredential
}
return ""
}
func (x *AccountVerifiedCredentialRegistered) GetRegistrationDate() int64 {
if x != nil {
return x.RegistrationDate
}
return 0
}
func (x *AccountVerifiedCredentialRegistered) GetExpirationDate() int64 {
if x != nil {
return x.ExpirationDate
}
return 0
}
func (x *AccountVerifiedCredentialRegistered) GetIdentifier() string {
if x != nil {
return x.Identifier
}
return ""
}
func (x *AccountVerifiedCredentialRegistered) GetIssuer() string {
if x != nil {
return x.Issuer
}
return ""
}
type FirstLastCounters struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
First uint64 `protobuf:"varint,1,opt,name=first,proto3" json:"first,omitempty"`
Last uint64 `protobuf:"varint,2,opt,name=last,proto3" json:"last,omitempty"`
}
func (x *FirstLastCounters) Reset() {
*x = FirstLastCounters{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[82]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FirstLastCounters) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FirstLastCounters) ProtoMessage() {}
func (x *FirstLastCounters) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[82]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FirstLastCounters.ProtoReflect.Descriptor instead.
func (*FirstLastCounters) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{82}
}
func (x *FirstLastCounters) GetFirst() uint64 {
if x != nil {
return x.First
}
return 0
}
func (x *FirstLastCounters) GetLast() uint64 {
if x != nil {
return x.Last
}
return 0
}
// OrbitDBMessageHeads is the payload sent on orbitdb to share peer's heads
type OrbitDBMessageHeads struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// sealed box should contain encrypted Box
SealedBox []byte `protobuf:"bytes,2,opt,name=sealed_box,json=sealedBox,proto3" json:"sealed_box,omitempty"`
// current topic used
RawRotation []byte `protobuf:"bytes,3,opt,name=raw_rotation,json=rawRotation,proto3" json:"raw_rotation,omitempty"`
}
func (x *OrbitDBMessageHeads) Reset() {
*x = OrbitDBMessageHeads{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[83]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OrbitDBMessageHeads) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OrbitDBMessageHeads) ProtoMessage() {}
func (x *OrbitDBMessageHeads) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[83]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OrbitDBMessageHeads.ProtoReflect.Descriptor instead.
func (*OrbitDBMessageHeads) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{83}
}
func (x *OrbitDBMessageHeads) GetSealedBox() []byte {
if x != nil {
return x.SealedBox
}
return nil
}
func (x *OrbitDBMessageHeads) GetRawRotation() []byte {
if x != nil {
return x.RawRotation
}
return nil
}
type RefreshContactRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *RefreshContactRequest) Reset() {
*x = RefreshContactRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[84]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RefreshContactRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshContactRequest) ProtoMessage() {}
func (x *RefreshContactRequest) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[84]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RefreshContactRequest.ProtoReflect.Descriptor instead.
func (*RefreshContactRequest) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{84}
}
type ServiceExportData_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ServiceExportData_Request) Reset() {
*x = ServiceExportData_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[86]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceExportData_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceExportData_Request) ProtoMessage() {}
func (x *ServiceExportData_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[86]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceExportData_Request.ProtoReflect.Descriptor instead.
func (*ServiceExportData_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{33, 0}
}
type ServiceExportData_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ExportedData []byte `protobuf:"bytes,1,opt,name=exported_data,json=exportedData,proto3" json:"exported_data,omitempty"`
}
func (x *ServiceExportData_Reply) Reset() {
*x = ServiceExportData_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[87]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceExportData_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceExportData_Reply) ProtoMessage() {}
func (x *ServiceExportData_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[87]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceExportData_Reply.ProtoReflect.Descriptor instead.
func (*ServiceExportData_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{33, 1}
}
func (x *ServiceExportData_Reply) GetExportedData() []byte {
if x != nil {
return x.ExportedData
}
return nil
}
type ServiceGetConfiguration_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ServiceGetConfiguration_Request) Reset() {
*x = ServiceGetConfiguration_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[88]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceGetConfiguration_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceGetConfiguration_Request) ProtoMessage() {}
func (x *ServiceGetConfiguration_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[88]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceGetConfiguration_Request.ProtoReflect.Descriptor instead.
func (*ServiceGetConfiguration_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{34, 0}
}
type ServiceGetConfiguration_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// account_pk is the public key of the current account
AccountPk []byte `protobuf:"bytes,1,opt,name=account_pk,json=accountPk,proto3" json:"account_pk,omitempty"`
// device_pk is the public key of the current device
DevicePk []byte `protobuf:"bytes,2,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// account_group_pk is the public key of the account group
AccountGroupPk []byte `protobuf:"bytes,3,opt,name=account_group_pk,json=accountGroupPk,proto3" json:"account_group_pk,omitempty"`
// peer_id is the peer ID of the current IPFS node
PeerId string `protobuf:"bytes,4,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
// listeners is the list of swarm listening addresses of the current IPFS node
Listeners []string `protobuf:"bytes,5,rep,name=listeners,proto3" json:"listeners,omitempty"`
BleEnabled ServiceGetConfiguration_SettingState `protobuf:"varint,6,opt,name=ble_enabled,json=bleEnabled,proto3,enum=weshnet.protocol.v1.ServiceGetConfiguration_SettingState" json:"ble_enabled,omitempty"`
WifiP2PEnabled ServiceGetConfiguration_SettingState `protobuf:"varint,7,opt,name=wifi_p2p_enabled,json=wifiP2pEnabled,proto3,enum=weshnet.protocol.v1.ServiceGetConfiguration_SettingState" json:"wifi_p2p_enabled,omitempty"` // MultiPeerConnectivity for Darwin and Nearby for Android
MdnsEnabled ServiceGetConfiguration_SettingState `protobuf:"varint,8,opt,name=mdns_enabled,json=mdnsEnabled,proto3,enum=weshnet.protocol.v1.ServiceGetConfiguration_SettingState" json:"mdns_enabled,omitempty"`
RelayEnabled ServiceGetConfiguration_SettingState `protobuf:"varint,9,opt,name=relay_enabled,json=relayEnabled,proto3,enum=weshnet.protocol.v1.ServiceGetConfiguration_SettingState" json:"relay_enabled,omitempty"`
}
func (x *ServiceGetConfiguration_Reply) Reset() {
*x = ServiceGetConfiguration_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[89]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServiceGetConfiguration_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServiceGetConfiguration_Reply) ProtoMessage() {}
func (x *ServiceGetConfiguration_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[89]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServiceGetConfiguration_Reply.ProtoReflect.Descriptor instead.
func (*ServiceGetConfiguration_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{34, 1}
}
func (x *ServiceGetConfiguration_Reply) GetAccountPk() []byte {
if x != nil {
return x.AccountPk
}
return nil
}
func (x *ServiceGetConfiguration_Reply) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *ServiceGetConfiguration_Reply) GetAccountGroupPk() []byte {
if x != nil {
return x.AccountGroupPk
}
return nil
}
func (x *ServiceGetConfiguration_Reply) GetPeerId() string {
if x != nil {
return x.PeerId
}
return ""
}
func (x *ServiceGetConfiguration_Reply) GetListeners() []string {
if x != nil {
return x.Listeners
}
return nil
}
func (x *ServiceGetConfiguration_Reply) GetBleEnabled() ServiceGetConfiguration_SettingState {
if x != nil {
return x.BleEnabled
}
return ServiceGetConfiguration_Unknown
}
func (x *ServiceGetConfiguration_Reply) GetWifiP2PEnabled() ServiceGetConfiguration_SettingState {
if x != nil {
return x.WifiP2PEnabled
}
return ServiceGetConfiguration_Unknown
}
func (x *ServiceGetConfiguration_Reply) GetMdnsEnabled() ServiceGetConfiguration_SettingState {
if x != nil {
return x.MdnsEnabled
}
return ServiceGetConfiguration_Unknown
}
func (x *ServiceGetConfiguration_Reply) GetRelayEnabled() ServiceGetConfiguration_SettingState {
if x != nil {
return x.RelayEnabled
}
return ServiceGetConfiguration_Unknown
}
type ContactRequestReference_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestReference_Request) Reset() {
*x = ContactRequestReference_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[90]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestReference_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestReference_Request) ProtoMessage() {}
func (x *ContactRequestReference_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[90]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestReference_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestReference_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{35, 0}
}
type ContactRequestReference_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_rendezvous_seed is the rendezvous seed used by the current account
PublicRendezvousSeed []byte `protobuf:"bytes,1,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
// enabled indicates if incoming contact requests are enabled
Enabled bool `protobuf:"varint,2,opt,name=enabled,proto3" json:"enabled,omitempty"`
}
func (x *ContactRequestReference_Reply) Reset() {
*x = ContactRequestReference_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[91]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestReference_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestReference_Reply) ProtoMessage() {}
func (x *ContactRequestReference_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[91]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestReference_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestReference_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{35, 1}
}
func (x *ContactRequestReference_Reply) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
func (x *ContactRequestReference_Reply) GetEnabled() bool {
if x != nil {
return x.Enabled
}
return false
}
type ContactRequestDisable_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestDisable_Request) Reset() {
*x = ContactRequestDisable_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[92]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDisable_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDisable_Request) ProtoMessage() {}
func (x *ContactRequestDisable_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[92]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDisable_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestDisable_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{36, 0}
}
type ContactRequestDisable_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestDisable_Reply) Reset() {
*x = ContactRequestDisable_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[93]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDisable_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDisable_Reply) ProtoMessage() {}
func (x *ContactRequestDisable_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[93]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDisable_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestDisable_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{36, 1}
}
type ContactRequestEnable_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestEnable_Request) Reset() {
*x = ContactRequestEnable_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[94]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestEnable_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestEnable_Request) ProtoMessage() {}
func (x *ContactRequestEnable_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[94]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestEnable_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestEnable_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{37, 0}
}
type ContactRequestEnable_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_rendezvous_seed is the rendezvous seed used by the current account
PublicRendezvousSeed []byte `protobuf:"bytes,1,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
}
func (x *ContactRequestEnable_Reply) Reset() {
*x = ContactRequestEnable_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[95]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestEnable_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestEnable_Reply) ProtoMessage() {}
func (x *ContactRequestEnable_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[95]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestEnable_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestEnable_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{37, 1}
}
func (x *ContactRequestEnable_Reply) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
type ContactRequestResetReference_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestResetReference_Request) Reset() {
*x = ContactRequestResetReference_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[96]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestResetReference_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestResetReference_Request) ProtoMessage() {}
func (x *ContactRequestResetReference_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[96]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestResetReference_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestResetReference_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{38, 0}
}
type ContactRequestResetReference_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_rendezvous_seed is the rendezvous seed used by the current account
PublicRendezvousSeed []byte `protobuf:"bytes,1,opt,name=public_rendezvous_seed,json=publicRendezvousSeed,proto3" json:"public_rendezvous_seed,omitempty"`
}
func (x *ContactRequestResetReference_Reply) Reset() {
*x = ContactRequestResetReference_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[97]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestResetReference_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestResetReference_Reply) ProtoMessage() {}
func (x *ContactRequestResetReference_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[97]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestResetReference_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestResetReference_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{38, 1}
}
func (x *ContactRequestResetReference_Reply) GetPublicRendezvousSeed() []byte {
if x != nil {
return x.PublicRendezvousSeed
}
return nil
}
type ContactRequestSend_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact is a message describing how to connect to the other account
Contact *ShareableContact `protobuf:"bytes,1,opt,name=contact,proto3" json:"contact,omitempty"`
// own_metadata is the identifying metadata that will be shared to the other account
OwnMetadata []byte `protobuf:"bytes,2,opt,name=own_metadata,json=ownMetadata,proto3" json:"own_metadata,omitempty"`
}
func (x *ContactRequestSend_Request) Reset() {
*x = ContactRequestSend_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[98]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestSend_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestSend_Request) ProtoMessage() {}
func (x *ContactRequestSend_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[98]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestSend_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestSend_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{39, 0}
}
func (x *ContactRequestSend_Request) GetContact() *ShareableContact {
if x != nil {
return x.Contact
}
return nil
}
func (x *ContactRequestSend_Request) GetOwnMetadata() []byte {
if x != nil {
return x.OwnMetadata
}
return nil
}
type ContactRequestSend_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestSend_Reply) Reset() {
*x = ContactRequestSend_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[99]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestSend_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestSend_Reply) ProtoMessage() {}
func (x *ContactRequestSend_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[99]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestSend_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestSend_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{39, 1}
}
type ContactRequestAccept_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact_pk is the identifier of the contact to accept the request from
ContactPk []byte `protobuf:"bytes,1,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *ContactRequestAccept_Request) Reset() {
*x = ContactRequestAccept_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[100]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestAccept_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestAccept_Request) ProtoMessage() {}
func (x *ContactRequestAccept_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[100]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestAccept_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestAccept_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{40, 0}
}
func (x *ContactRequestAccept_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type ContactRequestAccept_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestAccept_Reply) Reset() {
*x = ContactRequestAccept_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[101]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestAccept_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestAccept_Reply) ProtoMessage() {}
func (x *ContactRequestAccept_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[101]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestAccept_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestAccept_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{40, 1}
}
type ContactRequestDiscard_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact_pk is the identifier of the contact to ignore the request from
ContactPk []byte `protobuf:"bytes,1,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *ContactRequestDiscard_Request) Reset() {
*x = ContactRequestDiscard_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[102]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDiscard_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDiscard_Request) ProtoMessage() {}
func (x *ContactRequestDiscard_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[102]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDiscard_Request.ProtoReflect.Descriptor instead.
func (*ContactRequestDiscard_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{41, 0}
}
func (x *ContactRequestDiscard_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type ContactRequestDiscard_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactRequestDiscard_Reply) Reset() {
*x = ContactRequestDiscard_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[103]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactRequestDiscard_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactRequestDiscard_Reply) ProtoMessage() {}
func (x *ContactRequestDiscard_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[103]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactRequestDiscard_Reply.ProtoReflect.Descriptor instead.
func (*ContactRequestDiscard_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{41, 1}
}
type ShareContact_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ShareContact_Request) Reset() {
*x = ShareContact_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[104]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ShareContact_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShareContact_Request) ProtoMessage() {}
func (x *ShareContact_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[104]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShareContact_Request.ProtoReflect.Descriptor instead.
func (*ShareContact_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{42, 0}
}
type ShareContact_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// encoded_contact is the Protobuf encoding of the ShareableContact. You can further encode the bytes for sharing, such as base58 or QR code.
EncodedContact []byte `protobuf:"bytes,1,opt,name=encoded_contact,json=encodedContact,proto3" json:"encoded_contact,omitempty"`
}
func (x *ShareContact_Reply) Reset() {
*x = ShareContact_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[105]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ShareContact_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ShareContact_Reply) ProtoMessage() {}
func (x *ShareContact_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[105]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ShareContact_Reply.ProtoReflect.Descriptor instead.
func (*ShareContact_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{42, 1}
}
func (x *ShareContact_Reply) GetEncodedContact() []byte {
if x != nil {
return x.EncodedContact
}
return nil
}
type DecodeContact_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// encoded_contact is the Protobuf encoding of the shareable contact (as returned by ShareContact).
EncodedContact []byte `protobuf:"bytes,1,opt,name=encoded_contact,json=encodedContact,proto3" json:"encoded_contact,omitempty"`
}
func (x *DecodeContact_Request) Reset() {
*x = DecodeContact_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[106]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DecodeContact_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeContact_Request) ProtoMessage() {}
func (x *DecodeContact_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[106]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeContact_Request.ProtoReflect.Descriptor instead.
func (*DecodeContact_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{43, 0}
}
func (x *DecodeContact_Request) GetEncodedContact() []byte {
if x != nil {
return x.EncodedContact
}
return nil
}
type DecodeContact_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// shareable_contact is the decoded shareable contact.
Contact *ShareableContact `protobuf:"bytes,1,opt,name=contact,proto3" json:"contact,omitempty"`
}
func (x *DecodeContact_Reply) Reset() {
*x = DecodeContact_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[107]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DecodeContact_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DecodeContact_Reply) ProtoMessage() {}
func (x *DecodeContact_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[107]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DecodeContact_Reply.ProtoReflect.Descriptor instead.
func (*DecodeContact_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{43, 1}
}
func (x *DecodeContact_Reply) GetContact() *ShareableContact {
if x != nil {
return x.Contact
}
return nil
}
type ContactBlock_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact_pk is the identifier of the contact to block
ContactPk []byte `protobuf:"bytes,1,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *ContactBlock_Request) Reset() {
*x = ContactBlock_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[108]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactBlock_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactBlock_Request) ProtoMessage() {}
func (x *ContactBlock_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[108]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactBlock_Request.ProtoReflect.Descriptor instead.
func (*ContactBlock_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{44, 0}
}
func (x *ContactBlock_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type ContactBlock_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactBlock_Reply) Reset() {
*x = ContactBlock_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[109]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactBlock_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactBlock_Reply) ProtoMessage() {}
func (x *ContactBlock_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[109]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactBlock_Reply.ProtoReflect.Descriptor instead.
func (*ContactBlock_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{44, 1}
}
type ContactUnblock_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact_pk is the identifier of the contact to unblock
ContactPk []byte `protobuf:"bytes,1,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *ContactUnblock_Request) Reset() {
*x = ContactUnblock_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[110]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactUnblock_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactUnblock_Request) ProtoMessage() {}
func (x *ContactUnblock_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[110]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactUnblock_Request.ProtoReflect.Descriptor instead.
func (*ContactUnblock_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{45, 0}
}
func (x *ContactUnblock_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type ContactUnblock_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactUnblock_Reply) Reset() {
*x = ContactUnblock_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[111]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactUnblock_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactUnblock_Reply) ProtoMessage() {}
func (x *ContactUnblock_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[111]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactUnblock_Reply.ProtoReflect.Descriptor instead.
func (*ContactUnblock_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{45, 1}
}
type ContactAliasKeySend_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// contact_pk is the identifier of the contact to send the alias public key to
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *ContactAliasKeySend_Request) Reset() {
*x = ContactAliasKeySend_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[112]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactAliasKeySend_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactAliasKeySend_Request) ProtoMessage() {}
func (x *ContactAliasKeySend_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[112]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactAliasKeySend_Request.ProtoReflect.Descriptor instead.
func (*ContactAliasKeySend_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{46, 0}
}
func (x *ContactAliasKeySend_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type ContactAliasKeySend_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ContactAliasKeySend_Reply) Reset() {
*x = ContactAliasKeySend_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[113]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ContactAliasKeySend_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ContactAliasKeySend_Reply) ProtoMessage() {}
func (x *ContactAliasKeySend_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[113]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ContactAliasKeySend_Reply.ProtoReflect.Descriptor instead.
func (*ContactAliasKeySend_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{46, 1}
}
type MultiMemberGroupCreate_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupCreate_Request) Reset() {
*x = MultiMemberGroupCreate_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[114]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupCreate_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupCreate_Request) ProtoMessage() {}
func (x *MultiMemberGroupCreate_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[114]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupCreate_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupCreate_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{47, 0}
}
type MultiMemberGroupCreate_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the newly created group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *MultiMemberGroupCreate_Reply) Reset() {
*x = MultiMemberGroupCreate_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[115]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupCreate_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupCreate_Reply) ProtoMessage() {}
func (x *MultiMemberGroupCreate_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[115]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupCreate_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupCreate_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{47, 1}
}
func (x *MultiMemberGroupCreate_Reply) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type MultiMemberGroupJoin_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group is the information of the group to join
Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *MultiMemberGroupJoin_Request) Reset() {
*x = MultiMemberGroupJoin_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[116]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupJoin_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupJoin_Request) ProtoMessage() {}
func (x *MultiMemberGroupJoin_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[116]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupJoin_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupJoin_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{48, 0}
}
func (x *MultiMemberGroupJoin_Request) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
type MultiMemberGroupJoin_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupJoin_Reply) Reset() {
*x = MultiMemberGroupJoin_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[117]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupJoin_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupJoin_Reply) ProtoMessage() {}
func (x *MultiMemberGroupJoin_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[117]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupJoin_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupJoin_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{48, 1}
}
type MultiMemberGroupLeave_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *MultiMemberGroupLeave_Request) Reset() {
*x = MultiMemberGroupLeave_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[118]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupLeave_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupLeave_Request) ProtoMessage() {}
func (x *MultiMemberGroupLeave_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[118]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupLeave_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupLeave_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{49, 0}
}
func (x *MultiMemberGroupLeave_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type MultiMemberGroupLeave_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupLeave_Reply) Reset() {
*x = MultiMemberGroupLeave_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[119]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupLeave_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupLeave_Reply) ProtoMessage() {}
func (x *MultiMemberGroupLeave_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[119]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupLeave_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupLeave_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{49, 1}
}
type MultiMemberGroupAliasResolverDisclose_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *MultiMemberGroupAliasResolverDisclose_Request) Reset() {
*x = MultiMemberGroupAliasResolverDisclose_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[120]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAliasResolverDisclose_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAliasResolverDisclose_Request) ProtoMessage() {}
func (x *MultiMemberGroupAliasResolverDisclose_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[120]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAliasResolverDisclose_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAliasResolverDisclose_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{50, 0}
}
func (x *MultiMemberGroupAliasResolverDisclose_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type MultiMemberGroupAliasResolverDisclose_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupAliasResolverDisclose_Reply) Reset() {
*x = MultiMemberGroupAliasResolverDisclose_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[121]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAliasResolverDisclose_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAliasResolverDisclose_Reply) ProtoMessage() {}
func (x *MultiMemberGroupAliasResolverDisclose_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[121]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAliasResolverDisclose_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAliasResolverDisclose_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{50, 1}
}
type MultiMemberGroupAdminRoleGrant_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// member_pk is the identifier of the member which will be granted the admin role
MemberPk []byte `protobuf:"bytes,2,opt,name=member_pk,json=memberPk,proto3" json:"member_pk,omitempty"`
}
func (x *MultiMemberGroupAdminRoleGrant_Request) Reset() {
*x = MultiMemberGroupAdminRoleGrant_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[122]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAdminRoleGrant_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAdminRoleGrant_Request) ProtoMessage() {}
func (x *MultiMemberGroupAdminRoleGrant_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[122]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAdminRoleGrant_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAdminRoleGrant_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{51, 0}
}
func (x *MultiMemberGroupAdminRoleGrant_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *MultiMemberGroupAdminRoleGrant_Request) GetMemberPk() []byte {
if x != nil {
return x.MemberPk
}
return nil
}
type MultiMemberGroupAdminRoleGrant_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *MultiMemberGroupAdminRoleGrant_Reply) Reset() {
*x = MultiMemberGroupAdminRoleGrant_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[123]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupAdminRoleGrant_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupAdminRoleGrant_Reply) ProtoMessage() {}
func (x *MultiMemberGroupAdminRoleGrant_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[123]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupAdminRoleGrant_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupAdminRoleGrant_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{51, 1}
}
type MultiMemberGroupInvitationCreate_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *MultiMemberGroupInvitationCreate_Request) Reset() {
*x = MultiMemberGroupInvitationCreate_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[124]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupInvitationCreate_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupInvitationCreate_Request) ProtoMessage() {}
func (x *MultiMemberGroupInvitationCreate_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[124]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupInvitationCreate_Request.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupInvitationCreate_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{52, 0}
}
func (x *MultiMemberGroupInvitationCreate_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type MultiMemberGroupInvitationCreate_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group is the invitation to the group
Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *MultiMemberGroupInvitationCreate_Reply) Reset() {
*x = MultiMemberGroupInvitationCreate_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[125]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MultiMemberGroupInvitationCreate_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiMemberGroupInvitationCreate_Reply) ProtoMessage() {}
func (x *MultiMemberGroupInvitationCreate_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[125]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiMemberGroupInvitationCreate_Reply.ProtoReflect.Descriptor instead.
func (*MultiMemberGroupInvitationCreate_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{52, 1}
}
func (x *MultiMemberGroupInvitationCreate_Reply) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
type AppMetadataSend_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// payload is the payload to send
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (x *AppMetadataSend_Request) Reset() {
*x = AppMetadataSend_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[126]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMetadataSend_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMetadataSend_Request) ProtoMessage() {}
func (x *AppMetadataSend_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[126]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMetadataSend_Request.ProtoReflect.Descriptor instead.
func (*AppMetadataSend_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{53, 0}
}
func (x *AppMetadataSend_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *AppMetadataSend_Request) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type AppMetadataSend_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cid []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
}
func (x *AppMetadataSend_Reply) Reset() {
*x = AppMetadataSend_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[127]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMetadataSend_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMetadataSend_Reply) ProtoMessage() {}
func (x *AppMetadataSend_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[127]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMetadataSend_Reply.ProtoReflect.Descriptor instead.
func (*AppMetadataSend_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{53, 1}
}
func (x *AppMetadataSend_Reply) GetCid() []byte {
if x != nil {
return x.Cid
}
return nil
}
type AppMessageSend_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// payload is the payload to send
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (x *AppMessageSend_Request) Reset() {
*x = AppMessageSend_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[128]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMessageSend_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMessageSend_Request) ProtoMessage() {}
func (x *AppMessageSend_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[128]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMessageSend_Request.ProtoReflect.Descriptor instead.
func (*AppMessageSend_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{54, 0}
}
func (x *AppMessageSend_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *AppMessageSend_Request) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type AppMessageSend_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cid []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
}
func (x *AppMessageSend_Reply) Reset() {
*x = AppMessageSend_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[129]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AppMessageSend_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AppMessageSend_Reply) ProtoMessage() {}
func (x *AppMessageSend_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[129]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AppMessageSend_Reply.ProtoReflect.Descriptor instead.
func (*AppMessageSend_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{54, 1}
}
func (x *AppMessageSend_Reply) GetCid() []byte {
if x != nil {
return x.Cid
}
return nil
}
type GroupMetadataList_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// since is the lower ID bound used to filter events
// if not set, will return events since the beginning
SinceId []byte `protobuf:"bytes,2,opt,name=since_id,json=sinceId,proto3" json:"since_id,omitempty"`
// since_now will list only new event to come
// since_id must not be set
SinceNow bool `protobuf:"varint,3,opt,name=since_now,json=sinceNow,proto3" json:"since_now,omitempty"`
// until is the upper ID bound used to filter events
// if not set, will subscribe to new events to come
UntilId []byte `protobuf:"bytes,4,opt,name=until_id,json=untilId,proto3" json:"until_id,omitempty"`
// until_now will not list new event to come
// until_id must not be set
UntilNow bool `protobuf:"varint,5,opt,name=until_now,json=untilNow,proto3" json:"until_now,omitempty"`
// reverse_order indicates whether the previous events should be returned in
// reverse chronological order
ReverseOrder bool `protobuf:"varint,6,opt,name=reverse_order,json=reverseOrder,proto3" json:"reverse_order,omitempty"`
}
func (x *GroupMetadataList_Request) Reset() {
*x = GroupMetadataList_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[130]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMetadataList_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMetadataList_Request) ProtoMessage() {}
func (x *GroupMetadataList_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[130]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMetadataList_Request.ProtoReflect.Descriptor instead.
func (*GroupMetadataList_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{57, 0}
}
func (x *GroupMetadataList_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *GroupMetadataList_Request) GetSinceId() []byte {
if x != nil {
return x.SinceId
}
return nil
}
func (x *GroupMetadataList_Request) GetSinceNow() bool {
if x != nil {
return x.SinceNow
}
return false
}
func (x *GroupMetadataList_Request) GetUntilId() []byte {
if x != nil {
return x.UntilId
}
return nil
}
func (x *GroupMetadataList_Request) GetUntilNow() bool {
if x != nil {
return x.UntilNow
}
return false
}
func (x *GroupMetadataList_Request) GetReverseOrder() bool {
if x != nil {
return x.ReverseOrder
}
return false
}
type GroupMessageList_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// since is the lower ID bound used to filter events
// if not set, will return events since the beginning
SinceId []byte `protobuf:"bytes,2,opt,name=since_id,json=sinceId,proto3" json:"since_id,omitempty"`
// since_now will list only new event to come
// since_id must not be set
SinceNow bool `protobuf:"varint,3,opt,name=since_now,json=sinceNow,proto3" json:"since_now,omitempty"`
// until is the upper ID bound used to filter events
// if not set, will subscribe to new events to come
UntilId []byte `protobuf:"bytes,4,opt,name=until_id,json=untilId,proto3" json:"until_id,omitempty"`
// until_now will not list new event to come
// until_id must not be set
UntilNow bool `protobuf:"varint,5,opt,name=until_now,json=untilNow,proto3" json:"until_now,omitempty"`
// reverse_order indicates whether the previous events should be returned in
// reverse chronological order
ReverseOrder bool `protobuf:"varint,6,opt,name=reverse_order,json=reverseOrder,proto3" json:"reverse_order,omitempty"`
}
func (x *GroupMessageList_Request) Reset() {
*x = GroupMessageList_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[131]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupMessageList_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupMessageList_Request) ProtoMessage() {}
func (x *GroupMessageList_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[131]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupMessageList_Request.ProtoReflect.Descriptor instead.
func (*GroupMessageList_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{58, 0}
}
func (x *GroupMessageList_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *GroupMessageList_Request) GetSinceId() []byte {
if x != nil {
return x.SinceId
}
return nil
}
func (x *GroupMessageList_Request) GetSinceNow() bool {
if x != nil {
return x.SinceNow
}
return false
}
func (x *GroupMessageList_Request) GetUntilId() []byte {
if x != nil {
return x.UntilId
}
return nil
}
func (x *GroupMessageList_Request) GetUntilNow() bool {
if x != nil {
return x.UntilNow
}
return false
}
func (x *GroupMessageList_Request) GetReverseOrder() bool {
if x != nil {
return x.ReverseOrder
}
return false
}
type GroupInfo_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// contact_pk is the identifier of the contact
ContactPk []byte `protobuf:"bytes,2,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *GroupInfo_Request) Reset() {
*x = GroupInfo_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[132]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupInfo_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupInfo_Request) ProtoMessage() {}
func (x *GroupInfo_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[132]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupInfo_Request.ProtoReflect.Descriptor instead.
func (*GroupInfo_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{59, 0}
}
func (x *GroupInfo_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *GroupInfo_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type GroupInfo_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group is the group invitation, containing the group pk and its type
Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
// member_pk is the identifier of the current member in the group
MemberPk []byte `protobuf:"bytes,2,opt,name=member_pk,json=memberPk,proto3" json:"member_pk,omitempty"`
// device_pk is the identifier of the current device in the group
DevicePk []byte `protobuf:"bytes,3,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
}
func (x *GroupInfo_Reply) Reset() {
*x = GroupInfo_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[133]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupInfo_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupInfo_Reply) ProtoMessage() {}
func (x *GroupInfo_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[133]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupInfo_Reply.ProtoReflect.Descriptor instead.
func (*GroupInfo_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{59, 1}
}
func (x *GroupInfo_Reply) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
func (x *GroupInfo_Reply) GetMemberPk() []byte {
if x != nil {
return x.MemberPk
}
return nil
}
func (x *GroupInfo_Reply) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
type ActivateGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// local_only will open the group without enabling network interactions
// with other members
LocalOnly bool `protobuf:"varint,2,opt,name=local_only,json=localOnly,proto3" json:"local_only,omitempty"`
}
func (x *ActivateGroup_Request) Reset() {
*x = ActivateGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[134]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ActivateGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ActivateGroup_Request) ProtoMessage() {}
func (x *ActivateGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[134]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ActivateGroup_Request.ProtoReflect.Descriptor instead.
func (*ActivateGroup_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{60, 0}
}
func (x *ActivateGroup_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *ActivateGroup_Request) GetLocalOnly() bool {
if x != nil {
return x.LocalOnly
}
return false
}
type ActivateGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ActivateGroup_Reply) Reset() {
*x = ActivateGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[135]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ActivateGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ActivateGroup_Reply) ProtoMessage() {}
func (x *ActivateGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[135]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ActivateGroup_Reply.ProtoReflect.Descriptor instead.
func (*ActivateGroup_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{60, 1}
}
type DeactivateGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *DeactivateGroup_Request) Reset() {
*x = DeactivateGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[136]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeactivateGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeactivateGroup_Request) ProtoMessage() {}
func (x *DeactivateGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[136]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeactivateGroup_Request.ProtoReflect.Descriptor instead.
func (*DeactivateGroup_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{61, 0}
}
func (x *DeactivateGroup_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type DeactivateGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DeactivateGroup_Reply) Reset() {
*x = DeactivateGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[137]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeactivateGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeactivateGroup_Reply) ProtoMessage() {}
func (x *DeactivateGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[137]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeactivateGroup_Reply.ProtoReflect.Descriptor instead.
func (*DeactivateGroup_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{61, 1}
}
type GroupDeviceStatus_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *GroupDeviceStatus_Request) Reset() {
*x = GroupDeviceStatus_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[138]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus_Request) ProtoMessage() {}
func (x *GroupDeviceStatus_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[138]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus_Request.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 0}
}
func (x *GroupDeviceStatus_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type GroupDeviceStatus_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type GroupDeviceStatus_Type `protobuf:"varint,1,opt,name=type,proto3,enum=weshnet.protocol.v1.GroupDeviceStatus_Type" json:"type,omitempty"`
Event []byte `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"`
}
func (x *GroupDeviceStatus_Reply) Reset() {
*x = GroupDeviceStatus_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[139]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus_Reply) ProtoMessage() {}
func (x *GroupDeviceStatus_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[139]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus_Reply.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 1}
}
func (x *GroupDeviceStatus_Reply) GetType() GroupDeviceStatus_Type {
if x != nil {
return x.Type
}
return GroupDeviceStatus_TypeUnknown
}
func (x *GroupDeviceStatus_Reply) GetEvent() []byte {
if x != nil {
return x.Event
}
return nil
}
type GroupDeviceStatus_Reply_PeerConnected struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PeerId string `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
DevicePk []byte `protobuf:"bytes,2,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
Transports []GroupDeviceStatus_Transport `protobuf:"varint,3,rep,packed,name=transports,proto3,enum=weshnet.protocol.v1.GroupDeviceStatus_Transport" json:"transports,omitempty"`
Maddrs []string `protobuf:"bytes,4,rep,name=maddrs,proto3" json:"maddrs,omitempty"`
}
func (x *GroupDeviceStatus_Reply_PeerConnected) Reset() {
*x = GroupDeviceStatus_Reply_PeerConnected{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[140]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus_Reply_PeerConnected) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus_Reply_PeerConnected) ProtoMessage() {}
func (x *GroupDeviceStatus_Reply_PeerConnected) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[140]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus_Reply_PeerConnected.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus_Reply_PeerConnected) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 1, 0}
}
func (x *GroupDeviceStatus_Reply_PeerConnected) GetPeerId() string {
if x != nil {
return x.PeerId
}
return ""
}
func (x *GroupDeviceStatus_Reply_PeerConnected) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *GroupDeviceStatus_Reply_PeerConnected) GetTransports() []GroupDeviceStatus_Transport {
if x != nil {
return x.Transports
}
return nil
}
func (x *GroupDeviceStatus_Reply_PeerConnected) GetMaddrs() []string {
if x != nil {
return x.Maddrs
}
return nil
}
type GroupDeviceStatus_Reply_PeerReconnecting struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PeerId string `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
}
func (x *GroupDeviceStatus_Reply_PeerReconnecting) Reset() {
*x = GroupDeviceStatus_Reply_PeerReconnecting{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[141]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus_Reply_PeerReconnecting) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus_Reply_PeerReconnecting) ProtoMessage() {}
func (x *GroupDeviceStatus_Reply_PeerReconnecting) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[141]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus_Reply_PeerReconnecting.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus_Reply_PeerReconnecting) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 1, 1}
}
func (x *GroupDeviceStatus_Reply_PeerReconnecting) GetPeerId() string {
if x != nil {
return x.PeerId
}
return ""
}
type GroupDeviceStatus_Reply_PeerDisconnected struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PeerId string `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
}
func (x *GroupDeviceStatus_Reply_PeerDisconnected) Reset() {
*x = GroupDeviceStatus_Reply_PeerDisconnected{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[142]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GroupDeviceStatus_Reply_PeerDisconnected) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupDeviceStatus_Reply_PeerDisconnected) ProtoMessage() {}
func (x *GroupDeviceStatus_Reply_PeerDisconnected) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[142]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupDeviceStatus_Reply_PeerDisconnected.ProtoReflect.Descriptor instead.
func (*GroupDeviceStatus_Reply_PeerDisconnected) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{62, 1, 2}
}
func (x *GroupDeviceStatus_Reply_PeerDisconnected) GetPeerId() string {
if x != nil {
return x.PeerId
}
return ""
}
type DebugListGroups_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DebugListGroups_Request) Reset() {
*x = DebugListGroups_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[143]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugListGroups_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugListGroups_Request) ProtoMessage() {}
func (x *DebugListGroups_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[143]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugListGroups_Request.ProtoReflect.Descriptor instead.
func (*DebugListGroups_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{63, 0}
}
type DebugListGroups_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the public key of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// group_type is the type of the group
GroupType GroupType `protobuf:"varint,2,opt,name=group_type,json=groupType,proto3,enum=weshnet.protocol.v1.GroupType" json:"group_type,omitempty"`
// contact_pk is the contact public key if appropriate
ContactPk []byte `protobuf:"bytes,3,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
}
func (x *DebugListGroups_Reply) Reset() {
*x = DebugListGroups_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[144]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugListGroups_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugListGroups_Reply) ProtoMessage() {}
func (x *DebugListGroups_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[144]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugListGroups_Reply.ProtoReflect.Descriptor instead.
func (*DebugListGroups_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{63, 1}
}
func (x *DebugListGroups_Reply) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *DebugListGroups_Reply) GetGroupType() GroupType {
if x != nil {
return x.GroupType
}
return GroupType_GroupTypeUndefined
}
func (x *DebugListGroups_Reply) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
type DebugInspectGroupStore_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
// log_type is the log to inspect
LogType DebugInspectGroupLogType `protobuf:"varint,2,opt,name=log_type,json=logType,proto3,enum=weshnet.protocol.v1.DebugInspectGroupLogType" json:"log_type,omitempty"`
}
func (x *DebugInspectGroupStore_Request) Reset() {
*x = DebugInspectGroupStore_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[145]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugInspectGroupStore_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugInspectGroupStore_Request) ProtoMessage() {}
func (x *DebugInspectGroupStore_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[145]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugInspectGroupStore_Request.ProtoReflect.Descriptor instead.
func (*DebugInspectGroupStore_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{64, 0}
}
func (x *DebugInspectGroupStore_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *DebugInspectGroupStore_Request) GetLogType() DebugInspectGroupLogType {
if x != nil {
return x.LogType
}
return DebugInspectGroupLogType_DebugInspectGroupLogTypeUndefined
}
type DebugInspectGroupStore_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// cid is the CID of the IPFS log entry
Cid []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
// parent_cids is the list of the parent entries
ParentCids [][]byte `protobuf:"bytes,2,rep,name=parent_cids,json=parentCids,proto3" json:"parent_cids,omitempty"`
// event_type metadata event type if subscribed to metadata events
MetadataEventType EventType `protobuf:"varint,3,opt,name=metadata_event_type,json=metadataEventType,proto3,enum=weshnet.protocol.v1.EventType" json:"metadata_event_type,omitempty"`
// device_pk is the public key of the device signing the entry
DevicePk []byte `protobuf:"bytes,4,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
// payload is the un encrypted entry payload if available
Payload []byte `protobuf:"bytes,6,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (x *DebugInspectGroupStore_Reply) Reset() {
*x = DebugInspectGroupStore_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[146]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugInspectGroupStore_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugInspectGroupStore_Reply) ProtoMessage() {}
func (x *DebugInspectGroupStore_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[146]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugInspectGroupStore_Reply.ProtoReflect.Descriptor instead.
func (*DebugInspectGroupStore_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{64, 1}
}
func (x *DebugInspectGroupStore_Reply) GetCid() []byte {
if x != nil {
return x.Cid
}
return nil
}
func (x *DebugInspectGroupStore_Reply) GetParentCids() [][]byte {
if x != nil {
return x.ParentCids
}
return nil
}
func (x *DebugInspectGroupStore_Reply) GetMetadataEventType() EventType {
if x != nil {
return x.MetadataEventType
}
return EventType_EventTypeUndefined
}
func (x *DebugInspectGroupStore_Reply) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *DebugInspectGroupStore_Reply) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type DebugGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// group_pk is the identifier of the group
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
}
func (x *DebugGroup_Request) Reset() {
*x = DebugGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[147]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugGroup_Request) ProtoMessage() {}
func (x *DebugGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[147]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugGroup_Request.ProtoReflect.Descriptor instead.
func (*DebugGroup_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{65, 0}
}
func (x *DebugGroup_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
type DebugGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// peer_ids is the list of peer ids connected to the same group
PeerIds []string `protobuf:"bytes,1,rep,name=peer_ids,json=peerIds,proto3" json:"peer_ids,omitempty"`
}
func (x *DebugGroup_Reply) Reset() {
*x = DebugGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[148]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DebugGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DebugGroup_Reply) ProtoMessage() {}
func (x *DebugGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[148]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DebugGroup_Reply.ProtoReflect.Descriptor instead.
func (*DebugGroup_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{65, 1}
}
func (x *DebugGroup_Reply) GetPeerIds() []string {
if x != nil {
return x.PeerIds
}
return nil
}
type CredentialVerificationServiceInitFlow_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ServiceUrl string `protobuf:"bytes,1,opt,name=service_url,json=serviceUrl,proto3" json:"service_url,omitempty"`
PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
Link string `protobuf:"bytes,3,opt,name=link,proto3" json:"link,omitempty"`
}
func (x *CredentialVerificationServiceInitFlow_Request) Reset() {
*x = CredentialVerificationServiceInitFlow_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[149]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceInitFlow_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceInitFlow_Request) ProtoMessage() {}
func (x *CredentialVerificationServiceInitFlow_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[149]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceInitFlow_Request.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceInitFlow_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{69, 0}
}
func (x *CredentialVerificationServiceInitFlow_Request) GetServiceUrl() string {
if x != nil {
return x.ServiceUrl
}
return ""
}
func (x *CredentialVerificationServiceInitFlow_Request) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *CredentialVerificationServiceInitFlow_Request) GetLink() string {
if x != nil {
return x.Link
}
return ""
}
type CredentialVerificationServiceInitFlow_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
SecureUrl bool `protobuf:"varint,2,opt,name=secure_url,json=secureUrl,proto3" json:"secure_url,omitempty"`
}
func (x *CredentialVerificationServiceInitFlow_Reply) Reset() {
*x = CredentialVerificationServiceInitFlow_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[150]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceInitFlow_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceInitFlow_Reply) ProtoMessage() {}
func (x *CredentialVerificationServiceInitFlow_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[150]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceInitFlow_Reply.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceInitFlow_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{69, 1}
}
func (x *CredentialVerificationServiceInitFlow_Reply) GetUrl() string {
if x != nil {
return x.Url
}
return ""
}
func (x *CredentialVerificationServiceInitFlow_Reply) GetSecureUrl() bool {
if x != nil {
return x.SecureUrl
}
return false
}
type CredentialVerificationServiceCompleteFlow_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CallbackUri string `protobuf:"bytes,1,opt,name=callback_uri,json=callbackUri,proto3" json:"callback_uri,omitempty"`
}
func (x *CredentialVerificationServiceCompleteFlow_Request) Reset() {
*x = CredentialVerificationServiceCompleteFlow_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[151]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceCompleteFlow_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceCompleteFlow_Request) ProtoMessage() {}
func (x *CredentialVerificationServiceCompleteFlow_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[151]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceCompleteFlow_Request.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceCompleteFlow_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{70, 0}
}
func (x *CredentialVerificationServiceCompleteFlow_Request) GetCallbackUri() string {
if x != nil {
return x.CallbackUri
}
return ""
}
type CredentialVerificationServiceCompleteFlow_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"`
}
func (x *CredentialVerificationServiceCompleteFlow_Reply) Reset() {
*x = CredentialVerificationServiceCompleteFlow_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[152]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CredentialVerificationServiceCompleteFlow_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CredentialVerificationServiceCompleteFlow_Reply) ProtoMessage() {}
func (x *CredentialVerificationServiceCompleteFlow_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[152]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CredentialVerificationServiceCompleteFlow_Reply.ProtoReflect.Descriptor instead.
func (*CredentialVerificationServiceCompleteFlow_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{70, 1}
}
func (x *CredentialVerificationServiceCompleteFlow_Reply) GetIdentifier() string {
if x != nil {
return x.Identifier
}
return ""
}
type VerifiedCredentialsList_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FilterIdentifier string `protobuf:"bytes,1,opt,name=filter_identifier,json=filterIdentifier,proto3" json:"filter_identifier,omitempty"`
FilterIssuer string `protobuf:"bytes,2,opt,name=filter_issuer,json=filterIssuer,proto3" json:"filter_issuer,omitempty"`
ExcludeExpired bool `protobuf:"varint,3,opt,name=exclude_expired,json=excludeExpired,proto3" json:"exclude_expired,omitempty"`
}
func (x *VerifiedCredentialsList_Request) Reset() {
*x = VerifiedCredentialsList_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[153]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VerifiedCredentialsList_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VerifiedCredentialsList_Request) ProtoMessage() {}
func (x *VerifiedCredentialsList_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[153]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VerifiedCredentialsList_Request.ProtoReflect.Descriptor instead.
func (*VerifiedCredentialsList_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{71, 0}
}
func (x *VerifiedCredentialsList_Request) GetFilterIdentifier() string {
if x != nil {
return x.FilterIdentifier
}
return ""
}
func (x *VerifiedCredentialsList_Request) GetFilterIssuer() string {
if x != nil {
return x.FilterIssuer
}
return ""
}
func (x *VerifiedCredentialsList_Request) GetExcludeExpired() bool {
if x != nil {
return x.ExcludeExpired
}
return false
}
type VerifiedCredentialsList_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Credential *AccountVerifiedCredentialRegistered `protobuf:"bytes,1,opt,name=credential,proto3" json:"credential,omitempty"`
}
func (x *VerifiedCredentialsList_Reply) Reset() {
*x = VerifiedCredentialsList_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[154]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VerifiedCredentialsList_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VerifiedCredentialsList_Reply) ProtoMessage() {}
func (x *VerifiedCredentialsList_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[154]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VerifiedCredentialsList_Reply.ProtoReflect.Descriptor instead.
func (*VerifiedCredentialsList_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{71, 1}
}
func (x *VerifiedCredentialsList_Reply) GetCredential() *AccountVerifiedCredentialRegistered {
if x != nil {
return x.Credential
}
return nil
}
type ReplicationServiceRegisterGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
GroupPk []byte `protobuf:"bytes,1,opt,name=group_pk,json=groupPk,proto3" json:"group_pk,omitempty"`
Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
AuthenticationUrl string `protobuf:"bytes,3,opt,name=authentication_url,json=authenticationUrl,proto3" json:"authentication_url,omitempty"`
ReplicationServer string `protobuf:"bytes,4,opt,name=replication_server,json=replicationServer,proto3" json:"replication_server,omitempty"`
}
func (x *ReplicationServiceRegisterGroup_Request) Reset() {
*x = ReplicationServiceRegisterGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[155]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceRegisterGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceRegisterGroup_Request) ProtoMessage() {}
func (x *ReplicationServiceRegisterGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[155]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceRegisterGroup_Request.ProtoReflect.Descriptor instead.
func (*ReplicationServiceRegisterGroup_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{72, 0}
}
func (x *ReplicationServiceRegisterGroup_Request) GetGroupPk() []byte {
if x != nil {
return x.GroupPk
}
return nil
}
func (x *ReplicationServiceRegisterGroup_Request) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *ReplicationServiceRegisterGroup_Request) GetAuthenticationUrl() string {
if x != nil {
return x.AuthenticationUrl
}
return ""
}
func (x *ReplicationServiceRegisterGroup_Request) GetReplicationServer() string {
if x != nil {
return x.ReplicationServer
}
return ""
}
type ReplicationServiceRegisterGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicationServiceRegisterGroup_Reply) Reset() {
*x = ReplicationServiceRegisterGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[156]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceRegisterGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceRegisterGroup_Reply) ProtoMessage() {}
func (x *ReplicationServiceRegisterGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[156]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceRegisterGroup_Reply.ProtoReflect.Descriptor instead.
func (*ReplicationServiceRegisterGroup_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{72, 1}
}
type ReplicationServiceReplicateGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *ReplicationServiceReplicateGroup_Request) Reset() {
*x = ReplicationServiceReplicateGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[157]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup_Request) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[157]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup_Request.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{73, 0}
}
func (x *ReplicationServiceReplicateGroup_Request) GetGroup() *Group {
if x != nil {
return x.Group
}
return nil
}
type ReplicationServiceReplicateGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
}
func (x *ReplicationServiceReplicateGroup_Reply) Reset() {
*x = ReplicationServiceReplicateGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[158]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup_Reply) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[158]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup_Reply.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{73, 1}
}
func (x *ReplicationServiceReplicateGroup_Reply) GetOk() bool {
if x != nil {
return x.Ok
}
return false
}
type SystemInfo_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *SystemInfo_Request) Reset() {
*x = SystemInfo_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[159]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_Request) ProtoMessage() {}
func (x *SystemInfo_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[159]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_Request.ProtoReflect.Descriptor instead.
func (*SystemInfo_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 0}
}
type SystemInfo_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Process *SystemInfo_Process `protobuf:"bytes,1,opt,name=process,proto3" json:"process,omitempty"`
P2P *SystemInfo_P2P `protobuf:"bytes,2,opt,name=p2p,proto3" json:"p2p,omitempty"`
Orbitdb *SystemInfo_OrbitDB `protobuf:"bytes,3,opt,name=orbitdb,proto3" json:"orbitdb,omitempty"`
Warns []string `protobuf:"bytes,4,rep,name=warns,proto3" json:"warns,omitempty"`
}
func (x *SystemInfo_Reply) Reset() {
*x = SystemInfo_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[160]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_Reply) ProtoMessage() {}
func (x *SystemInfo_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[160]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_Reply.ProtoReflect.Descriptor instead.
func (*SystemInfo_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 1}
}
func (x *SystemInfo_Reply) GetProcess() *SystemInfo_Process {
if x != nil {
return x.Process
}
return nil
}
func (x *SystemInfo_Reply) GetP2P() *SystemInfo_P2P {
if x != nil {
return x.P2P
}
return nil
}
func (x *SystemInfo_Reply) GetOrbitdb() *SystemInfo_OrbitDB {
if x != nil {
return x.Orbitdb
}
return nil
}
func (x *SystemInfo_Reply) GetWarns() []string {
if x != nil {
return x.Warns
}
return nil
}
type SystemInfo_OrbitDB struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AccountMetadata *SystemInfo_OrbitDB_ReplicationStatus `protobuf:"bytes,1,opt,name=account_metadata,json=accountMetadata,proto3" json:"account_metadata,omitempty"`
}
func (x *SystemInfo_OrbitDB) Reset() {
*x = SystemInfo_OrbitDB{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[161]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_OrbitDB) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_OrbitDB) ProtoMessage() {}
func (x *SystemInfo_OrbitDB) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[161]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_OrbitDB.ProtoReflect.Descriptor instead.
func (*SystemInfo_OrbitDB) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 2}
}
func (x *SystemInfo_OrbitDB) GetAccountMetadata() *SystemInfo_OrbitDB_ReplicationStatus {
if x != nil {
return x.AccountMetadata
}
return nil
}
type SystemInfo_P2P struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ConnectedPeers int64 `protobuf:"varint,1,opt,name=connected_peers,json=connectedPeers,proto3" json:"connected_peers,omitempty"`
}
func (x *SystemInfo_P2P) Reset() {
*x = SystemInfo_P2P{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[162]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_P2P) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_P2P) ProtoMessage() {}
func (x *SystemInfo_P2P) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[162]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_P2P.ProtoReflect.Descriptor instead.
func (*SystemInfo_P2P) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 3}
}
func (x *SystemInfo_P2P) GetConnectedPeers() int64 {
if x != nil {
return x.ConnectedPeers
}
return 0
}
type SystemInfo_Process struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
VcsRef string `protobuf:"bytes,2,opt,name=vcs_ref,json=vcsRef,proto3" json:"vcs_ref,omitempty"`
UptimeMs int64 `protobuf:"varint,3,opt,name=uptime_ms,json=uptimeMs,proto3" json:"uptime_ms,omitempty"`
UserCpuTimeMs int64 `protobuf:"varint,10,opt,name=user_cpu_time_ms,json=userCpuTimeMs,proto3" json:"user_cpu_time_ms,omitempty"`
SystemCpuTimeMs int64 `protobuf:"varint,11,opt,name=system_cpu_time_ms,json=systemCpuTimeMs,proto3" json:"system_cpu_time_ms,omitempty"`
StartedAt int64 `protobuf:"varint,12,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
RlimitCur uint64 `protobuf:"varint,13,opt,name=rlimit_cur,json=rlimitCur,proto3" json:"rlimit_cur,omitempty"`
NumGoroutine int64 `protobuf:"varint,14,opt,name=num_goroutine,json=numGoroutine,proto3" json:"num_goroutine,omitempty"`
Nofile int64 `protobuf:"varint,15,opt,name=nofile,proto3" json:"nofile,omitempty"`
TooManyOpenFiles bool `protobuf:"varint,16,opt,name=too_many_open_files,json=tooManyOpenFiles,proto3" json:"too_many_open_files,omitempty"`
NumCpu int64 `protobuf:"varint,17,opt,name=num_cpu,json=numCpu,proto3" json:"num_cpu,omitempty"`
GoVersion string `protobuf:"bytes,18,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"`
OperatingSystem string `protobuf:"bytes,19,opt,name=operating_system,json=operatingSystem,proto3" json:"operating_system,omitempty"`
HostName string `protobuf:"bytes,20,opt,name=host_name,json=hostName,proto3" json:"host_name,omitempty"`
Arch string `protobuf:"bytes,21,opt,name=arch,proto3" json:"arch,omitempty"`
RlimitMax uint64 `protobuf:"varint,22,opt,name=rlimit_max,json=rlimitMax,proto3" json:"rlimit_max,omitempty"`
Pid int64 `protobuf:"varint,23,opt,name=pid,proto3" json:"pid,omitempty"`
Ppid int64 `protobuf:"varint,24,opt,name=ppid,proto3" json:"ppid,omitempty"`
Priority int64 `protobuf:"varint,25,opt,name=priority,proto3" json:"priority,omitempty"`
Uid int64 `protobuf:"varint,26,opt,name=uid,proto3" json:"uid,omitempty"`
WorkingDir string `protobuf:"bytes,27,opt,name=working_dir,json=workingDir,proto3" json:"working_dir,omitempty"`
SystemUsername string `protobuf:"bytes,28,opt,name=system_username,json=systemUsername,proto3" json:"system_username,omitempty"`
}
func (x *SystemInfo_Process) Reset() {
*x = SystemInfo_Process{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[163]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_Process) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_Process) ProtoMessage() {}
func (x *SystemInfo_Process) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[163]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_Process.ProtoReflect.Descriptor instead.
func (*SystemInfo_Process) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 4}
}
func (x *SystemInfo_Process) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *SystemInfo_Process) GetVcsRef() string {
if x != nil {
return x.VcsRef
}
return ""
}
func (x *SystemInfo_Process) GetUptimeMs() int64 {
if x != nil {
return x.UptimeMs
}
return 0
}
func (x *SystemInfo_Process) GetUserCpuTimeMs() int64 {
if x != nil {
return x.UserCpuTimeMs
}
return 0
}
func (x *SystemInfo_Process) GetSystemCpuTimeMs() int64 {
if x != nil {
return x.SystemCpuTimeMs
}
return 0
}
func (x *SystemInfo_Process) GetStartedAt() int64 {
if x != nil {
return x.StartedAt
}
return 0
}
func (x *SystemInfo_Process) GetRlimitCur() uint64 {
if x != nil {
return x.RlimitCur
}
return 0
}
func (x *SystemInfo_Process) GetNumGoroutine() int64 {
if x != nil {
return x.NumGoroutine
}
return 0
}
func (x *SystemInfo_Process) GetNofile() int64 {
if x != nil {
return x.Nofile
}
return 0
}
func (x *SystemInfo_Process) GetTooManyOpenFiles() bool {
if x != nil {
return x.TooManyOpenFiles
}
return false
}
func (x *SystemInfo_Process) GetNumCpu() int64 {
if x != nil {
return x.NumCpu
}
return 0
}
func (x *SystemInfo_Process) GetGoVersion() string {
if x != nil {
return x.GoVersion
}
return ""
}
func (x *SystemInfo_Process) GetOperatingSystem() string {
if x != nil {
return x.OperatingSystem
}
return ""
}
func (x *SystemInfo_Process) GetHostName() string {
if x != nil {
return x.HostName
}
return ""
}
func (x *SystemInfo_Process) GetArch() string {
if x != nil {
return x.Arch
}
return ""
}
func (x *SystemInfo_Process) GetRlimitMax() uint64 {
if x != nil {
return x.RlimitMax
}
return 0
}
func (x *SystemInfo_Process) GetPid() int64 {
if x != nil {
return x.Pid
}
return 0
}
func (x *SystemInfo_Process) GetPpid() int64 {
if x != nil {
return x.Ppid
}
return 0
}
func (x *SystemInfo_Process) GetPriority() int64 {
if x != nil {
return x.Priority
}
return 0
}
func (x *SystemInfo_Process) GetUid() int64 {
if x != nil {
return x.Uid
}
return 0
}
func (x *SystemInfo_Process) GetWorkingDir() string {
if x != nil {
return x.WorkingDir
}
return ""
}
func (x *SystemInfo_Process) GetSystemUsername() string {
if x != nil {
return x.SystemUsername
}
return ""
}
type SystemInfo_OrbitDB_ReplicationStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Progress int64 `protobuf:"varint,1,opt,name=progress,proto3" json:"progress,omitempty"`
Maximum int64 `protobuf:"varint,2,opt,name=maximum,proto3" json:"maximum,omitempty"`
Buffered int64 `protobuf:"varint,3,opt,name=buffered,proto3" json:"buffered,omitempty"`
Queued int64 `protobuf:"varint,4,opt,name=queued,proto3" json:"queued,omitempty"`
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) Reset() {
*x = SystemInfo_OrbitDB_ReplicationStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[164]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemInfo_OrbitDB_ReplicationStatus) ProtoMessage() {}
func (x *SystemInfo_OrbitDB_ReplicationStatus) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[164]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemInfo_OrbitDB_ReplicationStatus.ProtoReflect.Descriptor instead.
func (*SystemInfo_OrbitDB_ReplicationStatus) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{74, 2, 0}
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) GetProgress() int64 {
if x != nil {
return x.Progress
}
return 0
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) GetMaximum() int64 {
if x != nil {
return x.Maximum
}
return 0
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) GetBuffered() int64 {
if x != nil {
return x.Buffered
}
return 0
}
func (x *SystemInfo_OrbitDB_ReplicationStatus) GetQueued() int64 {
if x != nil {
return x.Queued
}
return 0
}
type PeerList_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *PeerList_Request) Reset() {
*x = PeerList_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[165]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList_Request) ProtoMessage() {}
func (x *PeerList_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[165]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList_Request.ProtoReflect.Descriptor instead.
func (*PeerList_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 0}
}
type PeerList_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Peers []*PeerList_Peer `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"`
}
func (x *PeerList_Reply) Reset() {
*x = PeerList_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[166]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList_Reply) ProtoMessage() {}
func (x *PeerList_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[166]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList_Reply.ProtoReflect.Descriptor instead.
func (*PeerList_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 1}
}
func (x *PeerList_Reply) GetPeers() []*PeerList_Peer {
if x != nil {
return x.Peers
}
return nil
}
type PeerList_Peer struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// id is the libp2p.PeerID.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// routes are the list of active and known maddr.
Routes []*PeerList_Route `protobuf:"bytes,2,rep,name=routes,proto3" json:"routes,omitempty"`
// errors is a list of errors related to the peer.
Errors []string `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty"`
// Features is a list of available features.
Features []PeerList_Feature `protobuf:"varint,4,rep,packed,name=features,proto3,enum=weshnet.protocol.v1.PeerList_Feature" json:"features,omitempty"`
// MinLatency is the minimum latency across all the peer routes.
MinLatency int64 `protobuf:"varint,5,opt,name=min_latency,json=minLatency,proto3" json:"min_latency,omitempty"`
// IsActive is true if at least one of the route is active.
IsActive bool `protobuf:"varint,6,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
// Direction is the aggregate of all the routes's direction.
Direction Direction `protobuf:"varint,7,opt,name=direction,proto3,enum=weshnet.protocol.v1.Direction" json:"direction,omitempty"`
}
func (x *PeerList_Peer) Reset() {
*x = PeerList_Peer{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[167]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList_Peer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList_Peer) ProtoMessage() {}
func (x *PeerList_Peer) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[167]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList_Peer.ProtoReflect.Descriptor instead.
func (*PeerList_Peer) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 2}
}
func (x *PeerList_Peer) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *PeerList_Peer) GetRoutes() []*PeerList_Route {
if x != nil {
return x.Routes
}
return nil
}
func (x *PeerList_Peer) GetErrors() []string {
if x != nil {
return x.Errors
}
return nil
}
func (x *PeerList_Peer) GetFeatures() []PeerList_Feature {
if x != nil {
return x.Features
}
return nil
}
func (x *PeerList_Peer) GetMinLatency() int64 {
if x != nil {
return x.MinLatency
}
return 0
}
func (x *PeerList_Peer) GetIsActive() bool {
if x != nil {
return x.IsActive
}
return false
}
func (x *PeerList_Peer) GetDirection() Direction {
if x != nil {
return x.Direction
}
return Direction_UnknownDir
}
type PeerList_Route struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// IsActive indicates whether the address is currently used or just known.
IsActive bool `protobuf:"varint,1,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
// Address is the multiaddress via which we are connected with the peer.
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
// Direction is which way the connection was established.
Direction Direction `protobuf:"varint,3,opt,name=direction,proto3,enum=weshnet.protocol.v1.Direction" json:"direction,omitempty"`
// Latency is the last known round trip time to the peer in ms.
Latency int64 `protobuf:"varint,4,opt,name=latency,proto3" json:"latency,omitempty"`
// Streams returns list of streams established with the peer.
Streams []*PeerList_Stream `protobuf:"bytes,5,rep,name=streams,proto3" json:"streams,omitempty"`
}
func (x *PeerList_Route) Reset() {
*x = PeerList_Route{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[168]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList_Route) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList_Route) ProtoMessage() {}
func (x *PeerList_Route) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[168]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList_Route.ProtoReflect.Descriptor instead.
func (*PeerList_Route) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 3}
}
func (x *PeerList_Route) GetIsActive() bool {
if x != nil {
return x.IsActive
}
return false
}
func (x *PeerList_Route) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
func (x *PeerList_Route) GetDirection() Direction {
if x != nil {
return x.Direction
}
return Direction_UnknownDir
}
func (x *PeerList_Route) GetLatency() int64 {
if x != nil {
return x.Latency
}
return 0
}
func (x *PeerList_Route) GetStreams() []*PeerList_Stream {
if x != nil {
return x.Streams
}
return nil
}
type PeerList_Stream struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// id is an identifier used to write protocol headers in streams.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *PeerList_Stream) Reset() {
*x = PeerList_Stream{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[169]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PeerList_Stream) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PeerList_Stream) ProtoMessage() {}
func (x *PeerList_Stream) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[169]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PeerList_Stream.ProtoReflect.Descriptor instead.
func (*PeerList_Stream) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{75, 4}
}
func (x *PeerList_Stream) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type OutOfStoreReceive_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
}
func (x *OutOfStoreReceive_Request) Reset() {
*x = OutOfStoreReceive_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[170]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreReceive_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreReceive_Request) ProtoMessage() {}
func (x *OutOfStoreReceive_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[170]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreReceive_Request.ProtoReflect.Descriptor instead.
func (*OutOfStoreReceive_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{79, 0}
}
func (x *OutOfStoreReceive_Request) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
type OutOfStoreReceive_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message *OutOfStoreMessage `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Cleartext []byte `protobuf:"bytes,2,opt,name=cleartext,proto3" json:"cleartext,omitempty"`
GroupPublicKey []byte `protobuf:"bytes,3,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
AlreadyReceived bool `protobuf:"varint,4,opt,name=already_received,json=alreadyReceived,proto3" json:"already_received,omitempty"`
}
func (x *OutOfStoreReceive_Reply) Reset() {
*x = OutOfStoreReceive_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[171]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreReceive_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreReceive_Reply) ProtoMessage() {}
func (x *OutOfStoreReceive_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[171]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreReceive_Reply.ProtoReflect.Descriptor instead.
func (*OutOfStoreReceive_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{79, 1}
}
func (x *OutOfStoreReceive_Reply) GetMessage() *OutOfStoreMessage {
if x != nil {
return x.Message
}
return nil
}
func (x *OutOfStoreReceive_Reply) GetCleartext() []byte {
if x != nil {
return x.Cleartext
}
return nil
}
func (x *OutOfStoreReceive_Reply) GetGroupPublicKey() []byte {
if x != nil {
return x.GroupPublicKey
}
return nil
}
func (x *OutOfStoreReceive_Reply) GetAlreadyReceived() bool {
if x != nil {
return x.AlreadyReceived
}
return false
}
type OutOfStoreSeal_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cid []byte `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
GroupPublicKey []byte `protobuf:"bytes,2,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
}
func (x *OutOfStoreSeal_Request) Reset() {
*x = OutOfStoreSeal_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[172]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreSeal_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreSeal_Request) ProtoMessage() {}
func (x *OutOfStoreSeal_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[172]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreSeal_Request.ProtoReflect.Descriptor instead.
func (*OutOfStoreSeal_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{80, 0}
}
func (x *OutOfStoreSeal_Request) GetCid() []byte {
if x != nil {
return x.Cid
}
return nil
}
func (x *OutOfStoreSeal_Request) GetGroupPublicKey() []byte {
if x != nil {
return x.GroupPublicKey
}
return nil
}
type OutOfStoreSeal_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Encrypted []byte `protobuf:"bytes,1,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
}
func (x *OutOfStoreSeal_Reply) Reset() {
*x = OutOfStoreSeal_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[173]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutOfStoreSeal_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutOfStoreSeal_Reply) ProtoMessage() {}
func (x *OutOfStoreSeal_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[173]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OutOfStoreSeal_Reply.ProtoReflect.Descriptor instead.
func (*OutOfStoreSeal_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{80, 1}
}
func (x *OutOfStoreSeal_Reply) GetEncrypted() []byte {
if x != nil {
return x.Encrypted
}
return nil
}
type OrbitDBMessageHeads_Box struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Heads []byte `protobuf:"bytes,2,opt,name=heads,proto3" json:"heads,omitempty"`
DevicePk []byte `protobuf:"bytes,3,opt,name=device_pk,json=devicePk,proto3" json:"device_pk,omitempty"`
PeerId []byte `protobuf:"bytes,4,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
}
func (x *OrbitDBMessageHeads_Box) Reset() {
*x = OrbitDBMessageHeads_Box{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[174]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OrbitDBMessageHeads_Box) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OrbitDBMessageHeads_Box) ProtoMessage() {}
func (x *OrbitDBMessageHeads_Box) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[174]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OrbitDBMessageHeads_Box.ProtoReflect.Descriptor instead.
func (*OrbitDBMessageHeads_Box) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{83, 0}
}
func (x *OrbitDBMessageHeads_Box) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
func (x *OrbitDBMessageHeads_Box) GetHeads() []byte {
if x != nil {
return x.Heads
}
return nil
}
func (x *OrbitDBMessageHeads_Box) GetDevicePk() []byte {
if x != nil {
return x.DevicePk
}
return nil
}
func (x *OrbitDBMessageHeads_Box) GetPeerId() []byte {
if x != nil {
return x.PeerId
}
return nil
}
type RefreshContactRequest_Peer struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// id is the libp2p.PeerID.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// list of peers multiaddrs.
Addrs []string `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"`
}
func (x *RefreshContactRequest_Peer) Reset() {
*x = RefreshContactRequest_Peer{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[175]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RefreshContactRequest_Peer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshContactRequest_Peer) ProtoMessage() {}
func (x *RefreshContactRequest_Peer) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[175]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RefreshContactRequest_Peer.ProtoReflect.Descriptor instead.
func (*RefreshContactRequest_Peer) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{84, 0}
}
func (x *RefreshContactRequest_Peer) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *RefreshContactRequest_Peer) GetAddrs() []string {
if x != nil {
return x.Addrs
}
return nil
}
type RefreshContactRequest_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ContactPk []byte `protobuf:"bytes,1,opt,name=contact_pk,json=contactPk,proto3" json:"contact_pk,omitempty"`
// timeout in second
Timeout int64 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
}
func (x *RefreshContactRequest_Request) Reset() {
*x = RefreshContactRequest_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[176]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RefreshContactRequest_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshContactRequest_Request) ProtoMessage() {}
func (x *RefreshContactRequest_Request) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[176]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RefreshContactRequest_Request.ProtoReflect.Descriptor instead.
func (*RefreshContactRequest_Request) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{84, 1}
}
func (x *RefreshContactRequest_Request) GetContactPk() []byte {
if x != nil {
return x.ContactPk
}
return nil
}
func (x *RefreshContactRequest_Request) GetTimeout() int64 {
if x != nil {
return x.Timeout
}
return 0
}
type RefreshContactRequest_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// peers found and successfully connected.
PeersFound []*RefreshContactRequest_Peer `protobuf:"bytes,1,rep,name=peers_found,json=peersFound,proto3" json:"peers_found,omitempty"`
}
func (x *RefreshContactRequest_Reply) Reset() {
*x = RefreshContactRequest_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_protocoltypes_proto_msgTypes[177]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RefreshContactRequest_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshContactRequest_Reply) ProtoMessage() {}
func (x *RefreshContactRequest_Reply) ProtoReflect() protoreflect.Message {
mi := &file_protocoltypes_proto_msgTypes[177]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RefreshContactRequest_Reply.ProtoReflect.Descriptor instead.
func (*RefreshContactRequest_Reply) Descriptor() ([]byte, []int) {
return file_protocoltypes_proto_rawDescGZIP(), []int{84, 2}
}
func (x *RefreshContactRequest_Reply) GetPeersFound() []*RefreshContactRequest_Peer {
if x != nil {
return x.PeersFound
}
return nil
}
var File_protocoltypes_proto protoreflect.FileDescriptor
var file_protocoltypes_proto_rawDesc = []byte{
0x0a, 0x13, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x72,
0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x61, 0x6c, 0x69, 0x61,
0x73, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x0f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74,
0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x65, 0x64, 0x22, 0xf4, 0x01, 0x0a, 0x05, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x53, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x0a, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x67,
0x6e, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x69, 0x67,
0x6e, 0x50, 0x75, 0x62, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79,
0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x4b, 0x65, 0x79, 0x12,
0x20, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x18,
0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x4b, 0x65, 0x79, 0x53, 0x69,
0x67, 0x22, 0xc7, 0x01, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x48, 0x65, 0x61, 0x64, 0x73,
0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x70, 0x75,
0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x69, 0x67, 0x6e, 0x50, 0x75, 0x62,
0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x68, 0x65, 0x61,
0x64, 0x73, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x6d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x65, 0x61, 0x64, 0x73, 0x43, 0x69, 0x64, 0x73,
0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x68, 0x65, 0x61,
0x64, 0x73, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x48, 0x65, 0x61, 0x64, 0x73, 0x43, 0x69, 0x64, 0x73,
0x12, 0x19, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x4b, 0x65, 0x79, 0x22, 0xce, 0x01, 0x0a, 0x0d,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3d, 0x0a,
0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x1e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x41, 0x0a, 0x0d,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f,
0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22,
0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65,
0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x08, 0x6d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e,
0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65,
0x72, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x18, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x01, 0x10,
0x02, 0x22, 0x84, 0x01, 0x0a, 0x10, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74,
0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x69, 0x6e,
0x74, 0x65, 0x78, 0x74, 0x12, 0x52, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x70, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e,
0x6f, 0x6e, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x5e, 0x0a, 0x0c, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61,
0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09,
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x50, 0x6b, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x51, 0x0a, 0x18, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4e, 0x0a,
0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4b, 0x65, 0x79,
0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x70, 0x6b, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x50, 0x6b, 0x22, 0x71, 0x0a,
0x16, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65,
0x72, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x50, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70,
0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50,
0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x69, 0x67,
0x22, 0x47, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x4b,
0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x12,
0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x77, 0x0a, 0x18, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x4b, 0x65, 0x79,
0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x6b, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65,
0x72, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x22, 0x89, 0x01, 0x0a, 0x22, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x6f,
0x6c, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f,
0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d,
0x61, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x1f, 0x0a,
0x0b, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x6b,
0x0a, 0x20, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74,
0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12,
0x2a, 0x0a, 0x11, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65,
0x72, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x67, 0x72, 0x61, 0x6e,
0x74, 0x65, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6b, 0x22, 0x45, 0x0a, 0x26, 0x4d,
0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49,
0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x6e, 0x6e, 0x6f,
0x75, 0x6e, 0x63, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f,
0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72,
0x50, 0x6b, 0x22, 0x53, 0x0a, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x64, 0x64, 0x41, 0x64,
0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f,
0x75, 0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x22, 0x56, 0x0a, 0x23, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x1b,
0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x73,
0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x22,
0x63, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a,
0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x6b, 0x12, 0x30, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x22, 0x4a, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x4c, 0x65, 0x66, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70,
0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b,
0x22, 0x3c, 0x0a, 0x1d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x22, 0x3b,
0x0a, 0x1c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1b,
0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x22, 0x78, 0x0a, 0x23, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73,
0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12,
0x34, 0x0a, 0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x7a,
0x76, 0x6f, 0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75,
0x73, 0x53, 0x65, 0x65, 0x64, 0x22, 0xc3, 0x01, 0x0a, 0x25, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4f,
0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x12,
0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x19, 0x0a, 0x08,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x3f, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x68, 0x61, 0x72, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52,
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x77, 0x6e, 0x5f,
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b,
0x6f, 0x77, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x5f, 0x0a, 0x21, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x6e, 0x74,
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x1d, 0x0a,
0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b, 0x22, 0xc6, 0x01, 0x0a,
0x25, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x65,
0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70,
0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x50, 0x6b, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x72, 0x65,
0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x64, 0x0a, 0x26, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e,
0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x12,
0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x1d, 0x0a, 0x0a,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b, 0x22, 0x7e, 0x0a, 0x25, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x41, 0x63, 0x63, 0x65,
0x70, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50,
0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b,
0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x22, 0x53, 0x0a, 0x15, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50,
0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b,
0x22, 0x55, 0x0a, 0x17, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b, 0x22, 0x8d, 0x01, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x2d, 0x0a, 0x12, 0x61, 0x75, 0x74,
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x09, 0x0a, 0x07,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65,
0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x93, 0x05, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0xa3, 0x04, 0x0a,
0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x50, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x6b, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x17, 0x0a, 0x07,
0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70,
0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65,
0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e,
0x65, 0x72, 0x73, 0x12, 0x5a, 0x0a, 0x0b, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74,
0x61, 0x74, 0x65, 0x52, 0x0a, 0x62, 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
0x63, 0x0a, 0x10, 0x77, 0x69, 0x66, 0x69, 0x5f, 0x70, 0x32, 0x70, 0x5f, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53,
0x74, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x77, 0x69, 0x66, 0x69, 0x50, 0x32, 0x70, 0x45, 0x6e, 0x61,
0x62, 0x6c, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x0c, 0x6d, 0x64, 0x6e, 0x73, 0x5f, 0x65, 0x6e, 0x61,
0x62, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x6d, 0x64, 0x6e, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x12, 0x5e, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53,
0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x22, 0x47, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61,
0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12,
0x0b, 0x0a, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08,
0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e,
0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x03, 0x22, 0x7d, 0x0a, 0x17, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x66,
0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x57, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x5f,
0x73, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x65, 0x64,
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x2b, 0x0a, 0x15, 0x43, 0x6f,
0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61,
0x62, 0x6c, 0x65, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07,
0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x60, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x1a,
0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x05, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x65,
0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x6e, 0x64, 0x65,
0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x65, 0x64, 0x22, 0x68, 0x0a, 0x1c, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x65, 0x74,
0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a,
0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f,
0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75, 0x73, 0x53,
0x65, 0x65, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x1a, 0x6d, 0x0a, 0x07, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61,
0x72, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x77, 0x6e, 0x5f, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x77,
0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x22, 0x49, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x1a, 0x28, 0x0a, 0x07, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x4a, 0x0a,
0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44,
0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x1a, 0x28, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b,
0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x4b, 0x0a, 0x0c, 0x53, 0x68, 0x61,
0x72, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, 0x0a,
0x0f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x0d, 0x44, 0x65, 0x63, 0x6f, 0x64,
0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x1a, 0x32, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x65, 0x6e,
0x63, 0x6f, 0x64, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x1a, 0x48, 0x0a, 0x05,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61,
0x72, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x22, 0x41, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0x28, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b,
0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x43, 0x0a, 0x0e, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0x28, 0x0a, 0x07, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x44,
0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4b, 0x65,
0x79, 0x53, 0x65, 0x6e, 0x64, 0x1a, 0x24, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x22, 0x47, 0x0a, 0x16, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 0x09,
0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x0a, 0x05, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x22, 0x5c, 0x0a,
0x14, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x4a, 0x6f, 0x69, 0x6e, 0x1a, 0x3b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x30, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x46, 0x0a, 0x15, 0x4d,
0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c,
0x65, 0x61, 0x76, 0x65, 0x1a, 0x24, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x22, 0x56, 0x0a, 0x25, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x6f,
0x6c, 0x76, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x1a, 0x24, 0x0a, 0x07,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70,
0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x6c, 0x0a, 0x1e, 0x4d,
0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41,
0x64, 0x6d, 0x69, 0x6e, 0x52, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x1a, 0x41, 0x0a,
0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x50, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6b,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6b,
0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x83, 0x01, 0x0a, 0x20, 0x4d, 0x75,
0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e,
0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x1a, 0x24,
0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x50, 0x6b, 0x1a, 0x39, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a,
0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22,
0x72, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x65,
0x6e, 0x64, 0x1a, 0x44, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a,
0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x1a, 0x19, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03,
0x63, 0x69, 0x64, 0x22, 0x71, 0x0a, 0x0e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x53, 0x65, 0x6e, 0x64, 0x1a, 0x44, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x1a, 0x19, 0x0a, 0x05, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x03, 0x63, 0x69, 0x64, 0x22, 0xb2, 0x01, 0x0a, 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x46, 0x0a,
0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f,
0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x3e, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0xb4, 0x01, 0x0a, 0x11,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x12, 0x46, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x45,
0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x65, 0x76, 0x65,
0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x3d, 0x0a, 0x07, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52,
0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x22, 0xcf, 0x01, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12,
0x19, 0x0a, 0x08, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x07, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x69,
0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73,
0x69, 0x6e, 0x63, 0x65, 0x4e, 0x6f, 0x77, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x6e, 0x74, 0x69, 0x6c,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x6e, 0x74, 0x69, 0x6c,
0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x5f, 0x6e, 0x6f, 0x77, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x4e, 0x6f, 0x77, 0x12,
0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72,
0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4f,
0x72, 0x64, 0x65, 0x72, 0x22, 0xce, 0x01, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x07, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b,
0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73,
0x69, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08,
0x73, 0x69, 0x6e, 0x63, 0x65, 0x4e, 0x6f, 0x77, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x6e, 0x74, 0x69,
0x6c, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x6e, 0x74, 0x69,
0x6c, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x5f, 0x6e, 0x6f, 0x77,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x4e, 0x6f, 0x77,
0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65,
0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0xc5, 0x01, 0x0a, 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49,
0x6e, 0x66, 0x6f, 0x1a, 0x43, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19,
0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x50, 0x6b, 0x1a, 0x73, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c,
0x79, 0x12, 0x30, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x70, 0x6b,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x6b,
0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x22, 0x5d, 0x0a,
0x0d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x43,
0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f,
0x75, 0x70, 0x50, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x6f, 0x6e,
0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f,
0x6e, 0x6c, 0x79, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x40, 0x0a, 0x0f,
0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x1a,
0x24, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x50, 0x6b, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0xd1,
0x04, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x1a, 0x24, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x1a, 0xea, 0x02, 0x0a, 0x05, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xaf, 0x01, 0x0a, 0x0d,
0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x17, 0x0a,
0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x6b, 0x12, 0x50, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x61, 0x64, 0x64, 0x72, 0x73, 0x1a, 0x2b, 0x0a,
0x10, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e,
0x67, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x2b, 0x0a, 0x10, 0x50, 0x65,
0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x17,
0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x62, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
0x0f, 0x0a, 0x0b, 0x54, 0x79, 0x70, 0x65, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00,
0x12, 0x18, 0x0a, 0x14, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x79,
0x70, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10,
0x02, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x79, 0x70, 0x65, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x03, 0x22, 0x45, 0x0a, 0x09, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x70, 0x74, 0x55,
0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x70, 0x74, 0x4c,
0x41, 0x4e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x70, 0x74, 0x57, 0x41, 0x4e, 0x10, 0x02,
0x12, 0x10, 0x0a, 0x0c, 0x54, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x69, 0x6d, 0x69, 0x74, 0x79,
0x10, 0x03, 0x22, 0x9f, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x73, 0x74,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x80, 0x01, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x3d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f,
0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x50, 0x6b, 0x22, 0xcc, 0x02, 0x0a, 0x16, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e,
0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a,
0x6e, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x50, 0x6b, 0x12, 0x48, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
0x62, 0x75, 0x67, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c,
0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x1a,
0xc1, 0x01, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70,
0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c,
0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x64, 0x73, 0x12, 0x4e, 0x0a, 0x13,
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x11, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x22, 0x56, 0x0a, 0x0a, 0x44, 0x65, 0x62, 0x75, 0x67, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x1a, 0x24, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b, 0x1a, 0x22, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x12, 0x19, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x09, 0x52, 0x07, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0x74, 0x0a, 0x10, 0x53,
0x68, 0x61, 0x72, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12,
0x0e, 0x0a, 0x02, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x70, 0x6b, 0x12,
0x34, 0x0a, 0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x7a,
0x76, 0x6f, 0x75, 0x73, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x14, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x7a, 0x76, 0x6f, 0x75,
0x73, 0x53, 0x65, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x22, 0x6c, 0x0a, 0x1c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22,
0xd5, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x60, 0x0a, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x65, 0x78, 0x70,
0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc0, 0x01, 0x0a, 0x25, 0x43, 0x72, 0x65, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x6c, 0x6f,
0x77, 0x1a, 0x5d, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1d, 0x0a,
0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04,
0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b,
0x1a, 0x38, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
0x09, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x82, 0x01, 0x0a, 0x29, 0x43,
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70,
0x6c, 0x65, 0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x1a, 0x2c, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f,
0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x55, 0x72, 0x69, 0x1a, 0x27, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22,
0x83, 0x02, 0x0a, 0x17, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x84, 0x01, 0x0a, 0x07,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x66, 0x69, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69,
0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x6c,
0x74, 0x65, 0x72, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x63,
0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72,
0x65, 0x64, 0x1a, 0x61, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x58, 0x0a, 0x0a, 0x63,
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x38, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x56, 0x65, 0x72,
0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52,
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xc5, 0x01, 0x0a, 0x1f, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x98, 0x01, 0x0a, 0x07, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x70,
0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x6b,
0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x1a, 0x07, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x78, 0x0a,
0x20, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x1a, 0x3b, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05,
0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x77, 0x65,
0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x17,
0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, 0xc2, 0x09, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0xda, 0x01, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x41, 0x0a, 0x07, 0x70,
0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x72,
0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x35,
0x0a, 0x03, 0x70, 0x32, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x77, 0x65,
0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76,
0x31, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x32, 0x50,
0x52, 0x03, 0x70, 0x32, 0x70, 0x12, 0x41, 0x0a, 0x07, 0x6f, 0x72, 0x62, 0x69, 0x74, 0x64, 0x62,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x73,
0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x52,
0x07, 0x6f, 0x72, 0x62, 0x69, 0x74, 0x64, 0x62, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x61, 0x72, 0x6e,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x77, 0x61, 0x72, 0x6e, 0x73, 0x1a, 0xee,
0x01, 0x0a, 0x07, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x12, 0x64, 0x0a, 0x10, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
0x0f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x1a, 0x7d, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x62,
0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62,
0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x71, 0x75, 0x65, 0x75, 0x65,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x1a,
0x2e, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x74, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x73, 0x1a,
0xaa, 0x05, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x63, 0x73, 0x5f, 0x72, 0x65, 0x66,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x63, 0x73, 0x52, 0x65, 0x66, 0x12, 0x1b,
0x0a, 0x09, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x08, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x27, 0x0a, 0x10, 0x75,
0x73, 0x65, 0x72, 0x5f, 0x63, 0x70, 0x75, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x43, 0x70, 0x75, 0x54, 0x69,
0x6d, 0x65, 0x4d, 0x73, 0x12, 0x2b, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63,
0x70, 0x75, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, 0x54, 0x69, 0x6d, 0x65, 0x4d,
0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74,
0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x18, 0x0d,
0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x75, 0x72, 0x12,
0x23, 0x0a, 0x0d, 0x6e, 0x75, 0x6d, 0x5f, 0x67, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65,
0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x47, 0x6f, 0x72, 0x6f, 0x75,
0x74, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0f,
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2d, 0x0a, 0x13,
0x74, 0x6f, 0x6f, 0x5f, 0x6d, 0x61, 0x6e, 0x79, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x6f, 0x6f, 0x4d, 0x61,
0x6e, 0x79, 0x4f, 0x70, 0x65, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e,
0x75, 0x6d, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75,
0x6d, 0x43, 0x70, 0x75, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67,
0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f,
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1b,
0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61,
0x72, 0x63, 0x68, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12,
0x1d, 0x0a, 0x0a, 0x72, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x16, 0x20,
0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x78, 0x12, 0x10,
0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x70, 0x69, 0x64,
0x12, 0x12, 0x0a, 0x04, 0x70, 0x70, 0x69, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
0x70, 0x70, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79,
0x18, 0x19, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x75,
0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69,
0x72, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67,
0x44, 0x69, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x75, 0x73,
0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xeb, 0x05, 0x0a,
0x08, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x38, 0x0a,
0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72,
0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x1a, 0xaa, 0x02, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x12, 0x3b, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x23, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e,
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x16, 0x0a,
0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65,
0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x08,
0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x5f,
0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6d,
0x69, 0x6e, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f,
0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73,
0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xd6, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x1b,
0x0a, 0x09, 0x69, 0x73, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x08, 0x52, 0x08, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44,
0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04,
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x3e, 0x0a,
0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x53, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x52, 0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x1a, 0x18, 0x0a,
0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x71, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75,
0x72, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x46, 0x65, 0x61,
0x74, 0x75, 0x72, 0x65, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x57, 0x65, 0x73, 0x68, 0x46, 0x65,
0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4c, 0x45, 0x46, 0x65,
0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x6f, 0x72,
0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x51, 0x75, 0x69,
0x63, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x05, 0x22, 0x9c, 0x01, 0x0a, 0x08, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x6f,
0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12,
0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
0x28, 0x04, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a,
0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01,
0x28, 0x04, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x22, 0xc7, 0x01, 0x0a, 0x11, 0x4f, 0x75,
0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x63, 0x69,
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x18,
0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52,
0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c,
0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x07, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73,
0x12, 0x2b, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x65, 0x6e, 0x63,
0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x14, 0x0a,
0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f,
0x6e, 0x63, 0x65, 0x22, 0x6c, 0x0a, 0x19, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72,
0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x6f, 0x78, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x03, 0x62, 0x6f, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63,
0x65, 0x22, 0xf7, 0x01, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65,
0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x1a, 0x23, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0xbc, 0x01, 0x0a,
0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x40, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75,
0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x65, 0x61,
0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x65,
0x61, 0x72, 0x74, 0x65, 0x78, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,
0x12, 0x29, 0x0a, 0x10, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x5f, 0x72, 0x65, 0x63, 0x65,
0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x61, 0x6c, 0x72, 0x65,
0x61, 0x64, 0x79, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x22, 0x7e, 0x0a, 0x0e, 0x4f,
0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x65, 0x61, 0x6c, 0x1a, 0x45, 0x0a,
0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x1a, 0x25, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1c, 0x0a,
0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0xbe, 0x02, 0x0a, 0x23,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43,
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
0x72, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b,
0x12, 0x3b, 0x0a, 0x1a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x49, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a,
0x13, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x65, 0x72, 0x69,
0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x2b,
0x0a, 0x11, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64,
0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x67, 0x69, 0x73,
0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x65,
0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x44, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x66, 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x07,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x22, 0x3d, 0x0a, 0x11,
0x46, 0x69, 0x72, 0x73, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
0x52, 0x05, 0x66, 0x69, 0x72, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x73, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x6c, 0x61, 0x73, 0x74, 0x22, 0xc4, 0x01, 0x0a, 0x13,
0x4f, 0x72, 0x62, 0x69, 0x74, 0x44, 0x42, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65,
0x61, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x6f,
0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x42,
0x6f, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x52, 0x6f, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6b, 0x0a, 0x03, 0x42, 0x6f, 0x78, 0x12, 0x18, 0x0a, 0x07,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x68, 0x65, 0x61, 0x64, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x68, 0x65, 0x61, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x6b, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65,
0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72,
0x49, 0x64, 0x22, 0xe4, 0x01, 0x0a, 0x15, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f,
0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x0a, 0x04,
0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x02, 0x20,
0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x1a, 0x42, 0x0a, 0x07, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x5f, 0x70, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x50, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, 0x59,
0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x50, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x73,
0x5f, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x0a, 0x70,
0x65, 0x65, 0x72, 0x73, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x2a, 0x69, 0x0a, 0x09, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54,
0x79, 0x70, 0x65, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x14,
0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x79, 0x70,
0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x10, 0x03, 0x2a, 0xba, 0x07, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79,
0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x55,
0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62,
0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x64, 0x64, 0x65, 0x64, 0x10, 0x01, 0x12,
0x25, 0x0a, 0x21, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x47, 0x72, 0x6f, 0x75,
0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x41,
0x64, 0x64, 0x65, 0x64, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a,
0x6f, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4c, 0x65, 0x66, 0x74, 0x10, 0x66, 0x12, 0x2a, 0x0a, 0x26, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x10, 0x67, 0x12, 0x29, 0x0a, 0x25, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x10, 0x68, 0x12, 0x30, 0x0a,
0x2c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52,
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x65, 0x74, 0x10, 0x69, 0x12,
0x32, 0x0a, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x71, 0x75, 0x65, 0x75, 0x65,
0x64, 0x10, 0x6a, 0x12, 0x2e, 0x0a, 0x2a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x6e,
0x74, 0x10, 0x6b, 0x12, 0x32, 0x0a, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63,
0x65, 0x69, 0x76, 0x65, 0x64, 0x10, 0x6c, 0x12, 0x33, 0x0a, 0x2f, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e,
0x67, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x10, 0x6d, 0x12, 0x32, 0x0a, 0x2e,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e,
0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x10, 0x6e,
0x12, 0x22, 0x0a, 0x1e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x65, 0x64, 0x10, 0x6f, 0x12, 0x24, 0x0a, 0x20, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x55,
0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x10, 0x70, 0x12, 0x22, 0x0a, 0x1d, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x6c,
0x69, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x41, 0x64, 0x64, 0x65, 0x64, 0x10, 0xc9, 0x01, 0x12, 0x30,
0x0a, 0x2b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73,
0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x65, 0x64, 0x10, 0xad, 0x02,
0x12, 0x34, 0x0a, 0x2f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x75, 0x6c,
0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x69,
0x74, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e,
0x63, 0x65, 0x64, 0x10, 0xae, 0x02, 0x12, 0x2e, 0x0a, 0x29, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e,
0x74, 0x65, 0x64, 0x10, 0xaf, 0x02, 0x12, 0x1e, 0x0a, 0x19, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6e, 0x67, 0x10, 0x93, 0x03, 0x12, 0x31, 0x0a, 0x2c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69,
0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x10, 0xf4, 0x03, 0x12, 0x26, 0x0a, 0x21, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x65, 0x6e, 0x74, 0x10, 0xe9,
0x07, 0x2a, 0x8c, 0x01, 0x0a, 0x18, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x73, 0x70, 0x65,
0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25,
0x0a, 0x21, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69,
0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e,
0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70,
0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x44, 0x65,
0x62, 0x75, 0x67, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c,
0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x10, 0x02,
0x2a, 0xc2, 0x01, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74,
0x65, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74,
0x65, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x10,
0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74,
0x65, 0x41, 0x64, 0x64, 0x65, 0x64, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x10,
0x04, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74,
0x65, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x10, 0x05, 0x12, 0x17, 0x0a, 0x13,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x65, 0x64, 0x10, 0x06, 0x2a, 0x47, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x44, 0x69, 0x72,
0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x69, 0x72,
0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x44, 0x69,
0x72, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x69, 0x44, 0x69, 0x72, 0x10, 0x03, 0x32, 0xdd,
0x26, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x12, 0x73, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x78, 0x70,
0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x12, 0x83, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x83, 0x01,
0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65,
0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x32, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x7d, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x32, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x30, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x12, 0x7a, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x31, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45,
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e,
0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x92,
0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12,
0x39, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52,
0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x74, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x2f, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65,
0x6e, 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53,
0x65, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x7a, 0x0a, 0x14, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x70,
0x74, 0x12, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x7d, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x12, 0x32,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x30, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x2e, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0x62, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x12, 0x29, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65,
0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x27, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x65, 0x0a, 0x0d, 0x44, 0x65, 0x63, 0x6f,
0x64, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x2a, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x6f,
0x64, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
0x62, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12,
0x29, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x55, 0x6e,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x2b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x29, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x77, 0x0a,
0x13, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4b, 0x65, 0x79,
0x53, 0x65, 0x6e, 0x64, 0x12, 0x30, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x63, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x63, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x6e, 0x64,
0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x80, 0x01, 0x0a, 0x16, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x12, 0x33, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c,
0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x7a, 0x0a, 0x14, 0x4d, 0x75, 0x6c,
0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69,
0x6e, 0x12, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69, 0x6e, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x7d, 0x0a, 0x15, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x32,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x30, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x2e, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0xad, 0x01, 0x0a, 0x25, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65,
0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x42,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76,
0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x40, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65,
0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x2e, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0x98, 0x01, 0x0a, 0x1e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x6f,
0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, 0x3b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75,
0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x64,
0x6d, 0x69, 0x6e, 0x52, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x64, 0x6d, 0x69, 0x6e,
0x52, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
0x9e, 0x01, 0x0a, 0x20, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x4d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x12, 0x6b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53,
0x65, 0x6e, 0x64, 0x12, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x65, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x53, 0x65, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a,
0x0e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x12,
0x2b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x53, 0x65, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x6e,
0x64, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x6e, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x4c, 0x69, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x6b, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2d, 0x2e, 0x77, 0x65,
0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x69,
0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x30, 0x01, 0x12, 0x59, 0x0a, 0x09, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66,
0x6f, 0x12, 0x26, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66,
0x6f, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
0x65, 0x0a, 0x0d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x12, 0x2a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x6b, 0x0a, 0x0f, 0x44, 0x65, 0x61, 0x63, 0x74, 0x69,
0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x65, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x73, 0x0a, 0x11, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x12, 0x6d, 0x0a, 0x0f, 0x44, 0x65, 0x62, 0x75,
0x67, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2c, 0x2e, 0x77, 0x65,
0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76,
0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x77, 0x65, 0x73, 0x68,
0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x12, 0x82, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x62, 0x75,
0x67, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f,
0x72, 0x65, 0x12, 0x33, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e,
0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
0x62, 0x75, 0x67, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53,
0x74, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x12, 0x5c, 0x0a, 0x0a,
0x44, 0x65, 0x62, 0x75, 0x67, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x27, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31,
0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x5c, 0x0a, 0x0a, 0x53, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x27, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e,
0x66, 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0xad, 0x01, 0x0a, 0x25, 0x43, 0x72, 0x65,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x6c,
0x6f, 0x77, 0x12, 0x42, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x6c,
0x6f, 0x77, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0xb9, 0x01, 0x0a, 0x29, 0x43, 0x72, 0x65,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x46, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x44,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x56,
0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x2e, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x12, 0x85, 0x01, 0x0a, 0x17, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65,
0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74,
0x12, 0x34, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43,
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72,
0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73,
0x4c, 0x69, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30, 0x01, 0x12, 0x9b, 0x01, 0x0a,
0x1f, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x12, 0x3c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a,
0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x56, 0x0a, 0x08, 0x50, 0x65,
0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65,
0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x12, 0x71, 0x0a, 0x11, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65,
0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x12, 0x2e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75,
0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75,
0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x4f, 0x66, 0x53, 0x74,
0x6f, 0x72, 0x65, 0x53, 0x65, 0x61, 0x6c, 0x12, 0x2b, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75,
0x74, 0x4f, 0x66, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x65, 0x61, 0x6c, 0x2e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x75, 0x74, 0x4f, 0x66,
0x53, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x65, 0x61, 0x6c, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
0x7d, 0x0a, 0x15, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x42, 0x29,
0x5a, 0x27, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_protocoltypes_proto_rawDescOnce sync.Once
file_protocoltypes_proto_rawDescData = file_protocoltypes_proto_rawDesc
)
func file_protocoltypes_proto_rawDescGZIP() []byte {
file_protocoltypes_proto_rawDescOnce.Do(func() {
file_protocoltypes_proto_rawDescData = protoimpl.X.CompressGZIP(file_protocoltypes_proto_rawDescData)
})
return file_protocoltypes_proto_rawDescData
}
var file_protocoltypes_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
var file_protocoltypes_proto_msgTypes = make([]protoimpl.MessageInfo, 178)
var file_protocoltypes_proto_goTypes = []any{
(GroupType)(0), // 0: weshnet.protocol.v1.GroupType
(EventType)(0), // 1: weshnet.protocol.v1.EventType
(DebugInspectGroupLogType)(0), // 2: weshnet.protocol.v1.DebugInspectGroupLogType
(ContactState)(0), // 3: weshnet.protocol.v1.ContactState
(Direction)(0), // 4: weshnet.protocol.v1.Direction
(ServiceGetConfiguration_SettingState)(0), // 5: weshnet.protocol.v1.ServiceGetConfiguration.SettingState
(GroupDeviceStatus_Type)(0), // 6: weshnet.protocol.v1.GroupDeviceStatus.Type
(GroupDeviceStatus_Transport)(0), // 7: weshnet.protocol.v1.GroupDeviceStatus.Transport
(PeerList_Feature)(0), // 8: weshnet.protocol.v1.PeerList.Feature
(*Account)(nil), // 9: weshnet.protocol.v1.Account
(*Group)(nil), // 10: weshnet.protocol.v1.Group
(*GroupHeadsExport)(nil), // 11: weshnet.protocol.v1.GroupHeadsExport
(*GroupMetadata)(nil), // 12: weshnet.protocol.v1.GroupMetadata
(*GroupEnvelope)(nil), // 13: weshnet.protocol.v1.GroupEnvelope
(*MessageHeaders)(nil), // 14: weshnet.protocol.v1.MessageHeaders
(*ProtocolMetadata)(nil), // 15: weshnet.protocol.v1.ProtocolMetadata
(*EncryptedMessage)(nil), // 16: weshnet.protocol.v1.EncryptedMessage
(*MessageEnvelope)(nil), // 17: weshnet.protocol.v1.MessageEnvelope
(*EventContext)(nil), // 18: weshnet.protocol.v1.EventContext
(*GroupMetadataPayloadSent)(nil), // 19: weshnet.protocol.v1.GroupMetadataPayloadSent
(*ContactAliasKeyAdded)(nil), // 20: weshnet.protocol.v1.ContactAliasKeyAdded
(*GroupMemberDeviceAdded)(nil), // 21: weshnet.protocol.v1.GroupMemberDeviceAdded
(*DeviceChainKey)(nil), // 22: weshnet.protocol.v1.DeviceChainKey
(*GroupDeviceChainKeyAdded)(nil), // 23: weshnet.protocol.v1.GroupDeviceChainKeyAdded
(*MultiMemberGroupAliasResolverAdded)(nil), // 24: weshnet.protocol.v1.MultiMemberGroupAliasResolverAdded
(*MultiMemberGroupAdminRoleGranted)(nil), // 25: weshnet.protocol.v1.MultiMemberGroupAdminRoleGranted
(*MultiMemberGroupInitialMemberAnnounced)(nil), // 26: weshnet.protocol.v1.MultiMemberGroupInitialMemberAnnounced
(*GroupAddAdditionalRendezvousSeed)(nil), // 27: weshnet.protocol.v1.GroupAddAdditionalRendezvousSeed
(*GroupRemoveAdditionalRendezvousSeed)(nil), // 28: weshnet.protocol.v1.GroupRemoveAdditionalRendezvousSeed
(*AccountGroupJoined)(nil), // 29: weshnet.protocol.v1.AccountGroupJoined
(*AccountGroupLeft)(nil), // 30: weshnet.protocol.v1.AccountGroupLeft
(*AccountContactRequestDisabled)(nil), // 31: weshnet.protocol.v1.AccountContactRequestDisabled
(*AccountContactRequestEnabled)(nil), // 32: weshnet.protocol.v1.AccountContactRequestEnabled
(*AccountContactRequestReferenceReset)(nil), // 33: weshnet.protocol.v1.AccountContactRequestReferenceReset
(*AccountContactRequestOutgoingEnqueued)(nil), // 34: weshnet.protocol.v1.AccountContactRequestOutgoingEnqueued
(*AccountContactRequestOutgoingSent)(nil), // 35: weshnet.protocol.v1.AccountContactRequestOutgoingSent
(*AccountContactRequestIncomingReceived)(nil), // 36: weshnet.protocol.v1.AccountContactRequestIncomingReceived
(*AccountContactRequestIncomingDiscarded)(nil), // 37: weshnet.protocol.v1.AccountContactRequestIncomingDiscarded
(*AccountContactRequestIncomingAccepted)(nil), // 38: weshnet.protocol.v1.AccountContactRequestIncomingAccepted
(*AccountContactBlocked)(nil), // 39: weshnet.protocol.v1.AccountContactBlocked
(*AccountContactUnblocked)(nil), // 40: weshnet.protocol.v1.AccountContactUnblocked
(*GroupReplicating)(nil), // 41: weshnet.protocol.v1.GroupReplicating
(*ServiceExportData)(nil), // 42: weshnet.protocol.v1.ServiceExportData
(*ServiceGetConfiguration)(nil), // 43: weshnet.protocol.v1.ServiceGetConfiguration
(*ContactRequestReference)(nil), // 44: weshnet.protocol.v1.ContactRequestReference
(*ContactRequestDisable)(nil), // 45: weshnet.protocol.v1.ContactRequestDisable
(*ContactRequestEnable)(nil), // 46: weshnet.protocol.v1.ContactRequestEnable
(*ContactRequestResetReference)(nil), // 47: weshnet.protocol.v1.ContactRequestResetReference
(*ContactRequestSend)(nil), // 48: weshnet.protocol.v1.ContactRequestSend
(*ContactRequestAccept)(nil), // 49: weshnet.protocol.v1.ContactRequestAccept
(*ContactRequestDiscard)(nil), // 50: weshnet.protocol.v1.ContactRequestDiscard
(*ShareContact)(nil), // 51: weshnet.protocol.v1.ShareContact
(*DecodeContact)(nil), // 52: weshnet.protocol.v1.DecodeContact
(*ContactBlock)(nil), // 53: weshnet.protocol.v1.ContactBlock
(*ContactUnblock)(nil), // 54: weshnet.protocol.v1.ContactUnblock
(*ContactAliasKeySend)(nil), // 55: weshnet.protocol.v1.ContactAliasKeySend
(*MultiMemberGroupCreate)(nil), // 56: weshnet.protocol.v1.MultiMemberGroupCreate
(*MultiMemberGroupJoin)(nil), // 57: weshnet.protocol.v1.MultiMemberGroupJoin
(*MultiMemberGroupLeave)(nil), // 58: weshnet.protocol.v1.MultiMemberGroupLeave
(*MultiMemberGroupAliasResolverDisclose)(nil), // 59: weshnet.protocol.v1.MultiMemberGroupAliasResolverDisclose
(*MultiMemberGroupAdminRoleGrant)(nil), // 60: weshnet.protocol.v1.MultiMemberGroupAdminRoleGrant
(*MultiMemberGroupInvitationCreate)(nil), // 61: weshnet.protocol.v1.MultiMemberGroupInvitationCreate
(*AppMetadataSend)(nil), // 62: weshnet.protocol.v1.AppMetadataSend
(*AppMessageSend)(nil), // 63: weshnet.protocol.v1.AppMessageSend
(*GroupMetadataEvent)(nil), // 64: weshnet.protocol.v1.GroupMetadataEvent
(*GroupMessageEvent)(nil), // 65: weshnet.protocol.v1.GroupMessageEvent
(*GroupMetadataList)(nil), // 66: weshnet.protocol.v1.GroupMetadataList
(*GroupMessageList)(nil), // 67: weshnet.protocol.v1.GroupMessageList
(*GroupInfo)(nil), // 68: weshnet.protocol.v1.GroupInfo
(*ActivateGroup)(nil), // 69: weshnet.protocol.v1.ActivateGroup
(*DeactivateGroup)(nil), // 70: weshnet.protocol.v1.DeactivateGroup
(*GroupDeviceStatus)(nil), // 71: weshnet.protocol.v1.GroupDeviceStatus
(*DebugListGroups)(nil), // 72: weshnet.protocol.v1.DebugListGroups
(*DebugInspectGroupStore)(nil), // 73: weshnet.protocol.v1.DebugInspectGroupStore
(*DebugGroup)(nil), // 74: weshnet.protocol.v1.DebugGroup
(*ShareableContact)(nil), // 75: weshnet.protocol.v1.ShareableContact
(*ServiceTokenSupportedService)(nil), // 76: weshnet.protocol.v1.ServiceTokenSupportedService
(*ServiceToken)(nil), // 77: weshnet.protocol.v1.ServiceToken
(*CredentialVerificationServiceInitFlow)(nil), // 78: weshnet.protocol.v1.CredentialVerificationServiceInitFlow
(*CredentialVerificationServiceCompleteFlow)(nil), // 79: weshnet.protocol.v1.CredentialVerificationServiceCompleteFlow
(*VerifiedCredentialsList)(nil), // 80: weshnet.protocol.v1.VerifiedCredentialsList
(*ReplicationServiceRegisterGroup)(nil), // 81: weshnet.protocol.v1.ReplicationServiceRegisterGroup
(*ReplicationServiceReplicateGroup)(nil), // 82: weshnet.protocol.v1.ReplicationServiceReplicateGroup
(*SystemInfo)(nil), // 83: weshnet.protocol.v1.SystemInfo
(*PeerList)(nil), // 84: weshnet.protocol.v1.PeerList
(*Progress)(nil), // 85: weshnet.protocol.v1.Progress
(*OutOfStoreMessage)(nil), // 86: weshnet.protocol.v1.OutOfStoreMessage
(*OutOfStoreMessageEnvelope)(nil), // 87: weshnet.protocol.v1.OutOfStoreMessageEnvelope
(*OutOfStoreReceive)(nil), // 88: weshnet.protocol.v1.OutOfStoreReceive
(*OutOfStoreSeal)(nil), // 89: weshnet.protocol.v1.OutOfStoreSeal
(*AccountVerifiedCredentialRegistered)(nil), // 90: weshnet.protocol.v1.AccountVerifiedCredentialRegistered
(*FirstLastCounters)(nil), // 91: weshnet.protocol.v1.FirstLastCounters
(*OrbitDBMessageHeads)(nil), // 92: weshnet.protocol.v1.OrbitDBMessageHeads
(*RefreshContactRequest)(nil), // 93: weshnet.protocol.v1.RefreshContactRequest
nil, // 94: weshnet.protocol.v1.MessageHeaders.MetadataEntry
(*ServiceExportData_Request)(nil), // 95: weshnet.protocol.v1.ServiceExportData.Request
(*ServiceExportData_Reply)(nil), // 96: weshnet.protocol.v1.ServiceExportData.Reply
(*ServiceGetConfiguration_Request)(nil), // 97: weshnet.protocol.v1.ServiceGetConfiguration.Request
(*ServiceGetConfiguration_Reply)(nil), // 98: weshnet.protocol.v1.ServiceGetConfiguration.Reply
(*ContactRequestReference_Request)(nil), // 99: weshnet.protocol.v1.ContactRequestReference.Request
(*ContactRequestReference_Reply)(nil), // 100: weshnet.protocol.v1.ContactRequestReference.Reply
(*ContactRequestDisable_Request)(nil), // 101: weshnet.protocol.v1.ContactRequestDisable.Request
(*ContactRequestDisable_Reply)(nil), // 102: weshnet.protocol.v1.ContactRequestDisable.Reply
(*ContactRequestEnable_Request)(nil), // 103: weshnet.protocol.v1.ContactRequestEnable.Request
(*ContactRequestEnable_Reply)(nil), // 104: weshnet.protocol.v1.ContactRequestEnable.Reply
(*ContactRequestResetReference_Request)(nil), // 105: weshnet.protocol.v1.ContactRequestResetReference.Request
(*ContactRequestResetReference_Reply)(nil), // 106: weshnet.protocol.v1.ContactRequestResetReference.Reply
(*ContactRequestSend_Request)(nil), // 107: weshnet.protocol.v1.ContactRequestSend.Request
(*ContactRequestSend_Reply)(nil), // 108: weshnet.protocol.v1.ContactRequestSend.Reply
(*ContactRequestAccept_Request)(nil), // 109: weshnet.protocol.v1.ContactRequestAccept.Request
(*ContactRequestAccept_Reply)(nil), // 110: weshnet.protocol.v1.ContactRequestAccept.Reply
(*ContactRequestDiscard_Request)(nil), // 111: weshnet.protocol.v1.ContactRequestDiscard.Request
(*ContactRequestDiscard_Reply)(nil), // 112: weshnet.protocol.v1.ContactRequestDiscard.Reply
(*ShareContact_Request)(nil), // 113: weshnet.protocol.v1.ShareContact.Request
(*ShareContact_Reply)(nil), // 114: weshnet.protocol.v1.ShareContact.Reply
(*DecodeContact_Request)(nil), // 115: weshnet.protocol.v1.DecodeContact.Request
(*DecodeContact_Reply)(nil), // 116: weshnet.protocol.v1.DecodeContact.Reply
(*ContactBlock_Request)(nil), // 117: weshnet.protocol.v1.ContactBlock.Request
(*ContactBlock_Reply)(nil), // 118: weshnet.protocol.v1.ContactBlock.Reply
(*ContactUnblock_Request)(nil), // 119: weshnet.protocol.v1.ContactUnblock.Request
(*ContactUnblock_Reply)(nil), // 120: weshnet.protocol.v1.ContactUnblock.Reply
(*ContactAliasKeySend_Request)(nil), // 121: weshnet.protocol.v1.ContactAliasKeySend.Request
(*ContactAliasKeySend_Reply)(nil), // 122: weshnet.protocol.v1.ContactAliasKeySend.Reply
(*MultiMemberGroupCreate_Request)(nil), // 123: weshnet.protocol.v1.MultiMemberGroupCreate.Request
(*MultiMemberGroupCreate_Reply)(nil), // 124: weshnet.protocol.v1.MultiMemberGroupCreate.Reply
(*MultiMemberGroupJoin_Request)(nil), // 125: weshnet.protocol.v1.MultiMemberGroupJoin.Request
(*MultiMemberGroupJoin_Reply)(nil), // 126: weshnet.protocol.v1.MultiMemberGroupJoin.Reply
(*MultiMemberGroupLeave_Request)(nil), // 127: weshnet.protocol.v1.MultiMemberGroupLeave.Request
(*MultiMemberGroupLeave_Reply)(nil), // 128: weshnet.protocol.v1.MultiMemberGroupLeave.Reply
(*MultiMemberGroupAliasResolverDisclose_Request)(nil), // 129: weshnet.protocol.v1.MultiMemberGroupAliasResolverDisclose.Request
(*MultiMemberGroupAliasResolverDisclose_Reply)(nil), // 130: weshnet.protocol.v1.MultiMemberGroupAliasResolverDisclose.Reply
(*MultiMemberGroupAdminRoleGrant_Request)(nil), // 131: weshnet.protocol.v1.MultiMemberGroupAdminRoleGrant.Request
(*MultiMemberGroupAdminRoleGrant_Reply)(nil), // 132: weshnet.protocol.v1.MultiMemberGroupAdminRoleGrant.Reply
(*MultiMemberGroupInvitationCreate_Request)(nil), // 133: weshnet.protocol.v1.MultiMemberGroupInvitationCreate.Request
(*MultiMemberGroupInvitationCreate_Reply)(nil), // 134: weshnet.protocol.v1.MultiMemberGroupInvitationCreate.Reply
(*AppMetadataSend_Request)(nil), // 135: weshnet.protocol.v1.AppMetadataSend.Request
(*AppMetadataSend_Reply)(nil), // 136: weshnet.protocol.v1.AppMetadataSend.Reply
(*AppMessageSend_Request)(nil), // 137: weshnet.protocol.v1.AppMessageSend.Request
(*AppMessageSend_Reply)(nil), // 138: weshnet.protocol.v1.AppMessageSend.Reply
(*GroupMetadataList_Request)(nil), // 139: weshnet.protocol.v1.GroupMetadataList.Request
(*GroupMessageList_Request)(nil), // 140: weshnet.protocol.v1.GroupMessageList.Request
(*GroupInfo_Request)(nil), // 141: weshnet.protocol.v1.GroupInfo.Request
(*GroupInfo_Reply)(nil), // 142: weshnet.protocol.v1.GroupInfo.Reply
(*ActivateGroup_Request)(nil), // 143: weshnet.protocol.v1.ActivateGroup.Request
(*ActivateGroup_Reply)(nil), // 144: weshnet.protocol.v1.ActivateGroup.Reply
(*DeactivateGroup_Request)(nil), // 145: weshnet.protocol.v1.DeactivateGroup.Request
(*DeactivateGroup_Reply)(nil), // 146: weshnet.protocol.v1.DeactivateGroup.Reply
(*GroupDeviceStatus_Request)(nil), // 147: weshnet.protocol.v1.GroupDeviceStatus.Request
(*GroupDeviceStatus_Reply)(nil), // 148: weshnet.protocol.v1.GroupDeviceStatus.Reply
(*GroupDeviceStatus_Reply_PeerConnected)(nil), // 149: weshnet.protocol.v1.GroupDeviceStatus.Reply.PeerConnected
(*GroupDeviceStatus_Reply_PeerReconnecting)(nil), // 150: weshnet.protocol.v1.GroupDeviceStatus.Reply.PeerReconnecting
(*GroupDeviceStatus_Reply_PeerDisconnected)(nil), // 151: weshnet.protocol.v1.GroupDeviceStatus.Reply.PeerDisconnected
(*DebugListGroups_Request)(nil), // 152: weshnet.protocol.v1.DebugListGroups.Request
(*DebugListGroups_Reply)(nil), // 153: weshnet.protocol.v1.DebugListGroups.Reply
(*DebugInspectGroupStore_Request)(nil), // 154: weshnet.protocol.v1.DebugInspectGroupStore.Request
(*DebugInspectGroupStore_Reply)(nil), // 155: weshnet.protocol.v1.DebugInspectGroupStore.Reply
(*DebugGroup_Request)(nil), // 156: weshnet.protocol.v1.DebugGroup.Request
(*DebugGroup_Reply)(nil), // 157: weshnet.protocol.v1.DebugGroup.Reply
(*CredentialVerificationServiceInitFlow_Request)(nil), // 158: weshnet.protocol.v1.CredentialVerificationServiceInitFlow.Request
(*CredentialVerificationServiceInitFlow_Reply)(nil), // 159: weshnet.protocol.v1.CredentialVerificationServiceInitFlow.Reply
(*CredentialVerificationServiceCompleteFlow_Request)(nil), // 160: weshnet.protocol.v1.CredentialVerificationServiceCompleteFlow.Request
(*CredentialVerificationServiceCompleteFlow_Reply)(nil), // 161: weshnet.protocol.v1.CredentialVerificationServiceCompleteFlow.Reply
(*VerifiedCredentialsList_Request)(nil), // 162: weshnet.protocol.v1.VerifiedCredentialsList.Request
(*VerifiedCredentialsList_Reply)(nil), // 163: weshnet.protocol.v1.VerifiedCredentialsList.Reply
(*ReplicationServiceRegisterGroup_Request)(nil), // 164: weshnet.protocol.v1.ReplicationServiceRegisterGroup.Request
(*ReplicationServiceRegisterGroup_Reply)(nil), // 165: weshnet.protocol.v1.ReplicationServiceRegisterGroup.Reply
(*ReplicationServiceReplicateGroup_Request)(nil), // 166: weshnet.protocol.v1.ReplicationServiceReplicateGroup.Request
(*ReplicationServiceReplicateGroup_Reply)(nil), // 167: weshnet.protocol.v1.ReplicationServiceReplicateGroup.Reply
(*SystemInfo_Request)(nil), // 168: weshnet.protocol.v1.SystemInfo.Request
(*SystemInfo_Reply)(nil), // 169: weshnet.protocol.v1.SystemInfo.Reply
(*SystemInfo_OrbitDB)(nil), // 170: weshnet.protocol.v1.SystemInfo.OrbitDB
(*SystemInfo_P2P)(nil), // 171: weshnet.protocol.v1.SystemInfo.P2P
(*SystemInfo_Process)(nil), // 172: weshnet.protocol.v1.SystemInfo.Process
(*SystemInfo_OrbitDB_ReplicationStatus)(nil), // 173: weshnet.protocol.v1.SystemInfo.OrbitDB.ReplicationStatus
(*PeerList_Request)(nil), // 174: weshnet.protocol.v1.PeerList.Request
(*PeerList_Reply)(nil), // 175: weshnet.protocol.v1.PeerList.Reply
(*PeerList_Peer)(nil), // 176: weshnet.protocol.v1.PeerList.Peer
(*PeerList_Route)(nil), // 177: weshnet.protocol.v1.PeerList.Route
(*PeerList_Stream)(nil), // 178: weshnet.protocol.v1.PeerList.Stream
(*OutOfStoreReceive_Request)(nil), // 179: weshnet.protocol.v1.OutOfStoreReceive.Request
(*OutOfStoreReceive_Reply)(nil), // 180: weshnet.protocol.v1.OutOfStoreReceive.Reply
(*OutOfStoreSeal_Request)(nil), // 181: weshnet.protocol.v1.OutOfStoreSeal.Request
(*OutOfStoreSeal_Reply)(nil), // 182: weshnet.protocol.v1.OutOfStoreSeal.Reply
(*OrbitDBMessageHeads_Box)(nil), // 183: weshnet.protocol.v1.OrbitDBMessageHeads.Box
(*RefreshContactRequest_Peer)(nil), // 184: weshnet.protocol.v1.RefreshContactRequest.Peer
(*RefreshContactRequest_Request)(nil), // 185: weshnet.protocol.v1.RefreshContactRequest.Request
(*RefreshContactRequest_Reply)(nil), // 186: weshnet.protocol.v1.RefreshContactRequest.Reply
}
var file_protocoltypes_proto_depIdxs = []int32{
10, // 0: weshnet.protocol.v1.Account.group:type_name -> weshnet.protocol.v1.Group
0, // 1: weshnet.protocol.v1.Group.group_type:type_name -> weshnet.protocol.v1.GroupType
1, // 2: weshnet.protocol.v1.GroupMetadata.event_type:type_name -> weshnet.protocol.v1.EventType
15, // 3: weshnet.protocol.v1.GroupMetadata.protocol_metadata:type_name -> weshnet.protocol.v1.ProtocolMetadata
94, // 4: weshnet.protocol.v1.MessageHeaders.metadata:type_name -> weshnet.protocol.v1.MessageHeaders.MetadataEntry
15, // 5: weshnet.protocol.v1.EncryptedMessage.protocol_metadata:type_name -> weshnet.protocol.v1.ProtocolMetadata
10, // 6: weshnet.protocol.v1.AccountGroupJoined.group:type_name -> weshnet.protocol.v1.Group
75, // 7: weshnet.protocol.v1.AccountContactRequestOutgoingEnqueued.contact:type_name -> weshnet.protocol.v1.ShareableContact
18, // 8: weshnet.protocol.v1.GroupMetadataEvent.event_context:type_name -> weshnet.protocol.v1.EventContext
12, // 9: weshnet.protocol.v1.GroupMetadataEvent.metadata:type_name -> weshnet.protocol.v1.GroupMetadata
18, // 10: weshnet.protocol.v1.GroupMessageEvent.event_context:type_name -> weshnet.protocol.v1.EventContext
14, // 11: weshnet.protocol.v1.GroupMessageEvent.headers:type_name -> weshnet.protocol.v1.MessageHeaders
76, // 12: weshnet.protocol.v1.ServiceToken.supported_services:type_name -> weshnet.protocol.v1.ServiceTokenSupportedService
5, // 13: weshnet.protocol.v1.ServiceGetConfiguration.Reply.ble_enabled:type_name -> weshnet.protocol.v1.ServiceGetConfiguration.SettingState
5, // 14: weshnet.protocol.v1.ServiceGetConfiguration.Reply.wifi_p2p_enabled:type_name -> weshnet.protocol.v1.ServiceGetConfiguration.SettingState
5, // 15: weshnet.protocol.v1.ServiceGetConfiguration.Reply.mdns_enabled:type_name -> weshnet.protocol.v1.ServiceGetConfiguration.SettingState
5, // 16: weshnet.protocol.v1.ServiceGetConfiguration.Reply.relay_enabled:type_name -> weshnet.protocol.v1.ServiceGetConfiguration.SettingState
75, // 17: weshnet.protocol.v1.ContactRequestSend.Request.contact:type_name -> weshnet.protocol.v1.ShareableContact
75, // 18: weshnet.protocol.v1.DecodeContact.Reply.contact:type_name -> weshnet.protocol.v1.ShareableContact
10, // 19: weshnet.protocol.v1.MultiMemberGroupJoin.Request.group:type_name -> weshnet.protocol.v1.Group
10, // 20: weshnet.protocol.v1.MultiMemberGroupInvitationCreate.Reply.group:type_name -> weshnet.protocol.v1.Group
10, // 21: weshnet.protocol.v1.GroupInfo.Reply.group:type_name -> weshnet.protocol.v1.Group
6, // 22: weshnet.protocol.v1.GroupDeviceStatus.Reply.type:type_name -> weshnet.protocol.v1.GroupDeviceStatus.Type
7, // 23: weshnet.protocol.v1.GroupDeviceStatus.Reply.PeerConnected.transports:type_name -> weshnet.protocol.v1.GroupDeviceStatus.Transport
0, // 24: weshnet.protocol.v1.DebugListGroups.Reply.group_type:type_name -> weshnet.protocol.v1.GroupType
2, // 25: weshnet.protocol.v1.DebugInspectGroupStore.Request.log_type:type_name -> weshnet.protocol.v1.DebugInspectGroupLogType
1, // 26: weshnet.protocol.v1.DebugInspectGroupStore.Reply.metadata_event_type:type_name -> weshnet.protocol.v1.EventType
90, // 27: weshnet.protocol.v1.VerifiedCredentialsList.Reply.credential:type_name -> weshnet.protocol.v1.AccountVerifiedCredentialRegistered
10, // 28: weshnet.protocol.v1.ReplicationServiceReplicateGroup.Request.group:type_name -> weshnet.protocol.v1.Group
172, // 29: weshnet.protocol.v1.SystemInfo.Reply.process:type_name -> weshnet.protocol.v1.SystemInfo.Process
171, // 30: weshnet.protocol.v1.SystemInfo.Reply.p2p:type_name -> weshnet.protocol.v1.SystemInfo.P2P
170, // 31: weshnet.protocol.v1.SystemInfo.Reply.orbitdb:type_name -> weshnet.protocol.v1.SystemInfo.OrbitDB
173, // 32: weshnet.protocol.v1.SystemInfo.OrbitDB.account_metadata:type_name -> weshnet.protocol.v1.SystemInfo.OrbitDB.ReplicationStatus
176, // 33: weshnet.protocol.v1.PeerList.Reply.peers:type_name -> weshnet.protocol.v1.PeerList.Peer
177, // 34: weshnet.protocol.v1.PeerList.Peer.routes:type_name -> weshnet.protocol.v1.PeerList.Route
8, // 35: weshnet.protocol.v1.PeerList.Peer.features:type_name -> weshnet.protocol.v1.PeerList.Feature
4, // 36: weshnet.protocol.v1.PeerList.Peer.direction:type_name -> weshnet.protocol.v1.Direction
4, // 37: weshnet.protocol.v1.PeerList.Route.direction:type_name -> weshnet.protocol.v1.Direction
178, // 38: weshnet.protocol.v1.PeerList.Route.streams:type_name -> weshnet.protocol.v1.PeerList.Stream
86, // 39: weshnet.protocol.v1.OutOfStoreReceive.Reply.message:type_name -> weshnet.protocol.v1.OutOfStoreMessage
184, // 40: weshnet.protocol.v1.RefreshContactRequest.Reply.peers_found:type_name -> weshnet.protocol.v1.RefreshContactRequest.Peer
95, // 41: weshnet.protocol.v1.ProtocolService.ServiceExportData:input_type -> weshnet.protocol.v1.ServiceExportData.Request
97, // 42: weshnet.protocol.v1.ProtocolService.ServiceGetConfiguration:input_type -> weshnet.protocol.v1.ServiceGetConfiguration.Request
99, // 43: weshnet.protocol.v1.ProtocolService.ContactRequestReference:input_type -> weshnet.protocol.v1.ContactRequestReference.Request
101, // 44: weshnet.protocol.v1.ProtocolService.ContactRequestDisable:input_type -> weshnet.protocol.v1.ContactRequestDisable.Request
103, // 45: weshnet.protocol.v1.ProtocolService.ContactRequestEnable:input_type -> weshnet.protocol.v1.ContactRequestEnable.Request
105, // 46: weshnet.protocol.v1.ProtocolService.ContactRequestResetReference:input_type -> weshnet.protocol.v1.ContactRequestResetReference.Request
107, // 47: weshnet.protocol.v1.ProtocolService.ContactRequestSend:input_type -> weshnet.protocol.v1.ContactRequestSend.Request
109, // 48: weshnet.protocol.v1.ProtocolService.ContactRequestAccept:input_type -> weshnet.protocol.v1.ContactRequestAccept.Request
111, // 49: weshnet.protocol.v1.ProtocolService.ContactRequestDiscard:input_type -> weshnet.protocol.v1.ContactRequestDiscard.Request
113, // 50: weshnet.protocol.v1.ProtocolService.ShareContact:input_type -> weshnet.protocol.v1.ShareContact.Request
115, // 51: weshnet.protocol.v1.ProtocolService.DecodeContact:input_type -> weshnet.protocol.v1.DecodeContact.Request
117, // 52: weshnet.protocol.v1.ProtocolService.ContactBlock:input_type -> weshnet.protocol.v1.ContactBlock.Request
119, // 53: weshnet.protocol.v1.ProtocolService.ContactUnblock:input_type -> weshnet.protocol.v1.ContactUnblock.Request
121, // 54: weshnet.protocol.v1.ProtocolService.ContactAliasKeySend:input_type -> weshnet.protocol.v1.ContactAliasKeySend.Request
123, // 55: weshnet.protocol.v1.ProtocolService.MultiMemberGroupCreate:input_type -> weshnet.protocol.v1.MultiMemberGroupCreate.Request
125, // 56: weshnet.protocol.v1.ProtocolService.MultiMemberGroupJoin:input_type -> weshnet.protocol.v1.MultiMemberGroupJoin.Request
127, // 57: weshnet.protocol.v1.ProtocolService.MultiMemberGroupLeave:input_type -> weshnet.protocol.v1.MultiMemberGroupLeave.Request
129, // 58: weshnet.protocol.v1.ProtocolService.MultiMemberGroupAliasResolverDisclose:input_type -> weshnet.protocol.v1.MultiMemberGroupAliasResolverDisclose.Request
131, // 59: weshnet.protocol.v1.ProtocolService.MultiMemberGroupAdminRoleGrant:input_type -> weshnet.protocol.v1.MultiMemberGroupAdminRoleGrant.Request
133, // 60: weshnet.protocol.v1.ProtocolService.MultiMemberGroupInvitationCreate:input_type -> weshnet.protocol.v1.MultiMemberGroupInvitationCreate.Request
135, // 61: weshnet.protocol.v1.ProtocolService.AppMetadataSend:input_type -> weshnet.protocol.v1.AppMetadataSend.Request
137, // 62: weshnet.protocol.v1.ProtocolService.AppMessageSend:input_type -> weshnet.protocol.v1.AppMessageSend.Request
139, // 63: weshnet.protocol.v1.ProtocolService.GroupMetadataList:input_type -> weshnet.protocol.v1.GroupMetadataList.Request
140, // 64: weshnet.protocol.v1.ProtocolService.GroupMessageList:input_type -> weshnet.protocol.v1.GroupMessageList.Request
141, // 65: weshnet.protocol.v1.ProtocolService.GroupInfo:input_type -> weshnet.protocol.v1.GroupInfo.Request
143, // 66: weshnet.protocol.v1.ProtocolService.ActivateGroup:input_type -> weshnet.protocol.v1.ActivateGroup.Request
145, // 67: weshnet.protocol.v1.ProtocolService.DeactivateGroup:input_type -> weshnet.protocol.v1.DeactivateGroup.Request
147, // 68: weshnet.protocol.v1.ProtocolService.GroupDeviceStatus:input_type -> weshnet.protocol.v1.GroupDeviceStatus.Request
152, // 69: weshnet.protocol.v1.ProtocolService.DebugListGroups:input_type -> weshnet.protocol.v1.DebugListGroups.Request
154, // 70: weshnet.protocol.v1.ProtocolService.DebugInspectGroupStore:input_type -> weshnet.protocol.v1.DebugInspectGroupStore.Request
156, // 71: weshnet.protocol.v1.ProtocolService.DebugGroup:input_type -> weshnet.protocol.v1.DebugGroup.Request
168, // 72: weshnet.protocol.v1.ProtocolService.SystemInfo:input_type -> weshnet.protocol.v1.SystemInfo.Request
158, // 73: weshnet.protocol.v1.ProtocolService.CredentialVerificationServiceInitFlow:input_type -> weshnet.protocol.v1.CredentialVerificationServiceInitFlow.Request
160, // 74: weshnet.protocol.v1.ProtocolService.CredentialVerificationServiceCompleteFlow:input_type -> weshnet.protocol.v1.CredentialVerificationServiceCompleteFlow.Request
162, // 75: weshnet.protocol.v1.ProtocolService.VerifiedCredentialsList:input_type -> weshnet.protocol.v1.VerifiedCredentialsList.Request
164, // 76: weshnet.protocol.v1.ProtocolService.ReplicationServiceRegisterGroup:input_type -> weshnet.protocol.v1.ReplicationServiceRegisterGroup.Request
174, // 77: weshnet.protocol.v1.ProtocolService.PeerList:input_type -> weshnet.protocol.v1.PeerList.Request
179, // 78: weshnet.protocol.v1.ProtocolService.OutOfStoreReceive:input_type -> weshnet.protocol.v1.OutOfStoreReceive.Request
181, // 79: weshnet.protocol.v1.ProtocolService.OutOfStoreSeal:input_type -> weshnet.protocol.v1.OutOfStoreSeal.Request
185, // 80: weshnet.protocol.v1.ProtocolService.RefreshContactRequest:input_type -> weshnet.protocol.v1.RefreshContactRequest.Request
96, // 81: weshnet.protocol.v1.ProtocolService.ServiceExportData:output_type -> weshnet.protocol.v1.ServiceExportData.Reply
98, // 82: weshnet.protocol.v1.ProtocolService.ServiceGetConfiguration:output_type -> weshnet.protocol.v1.ServiceGetConfiguration.Reply
100, // 83: weshnet.protocol.v1.ProtocolService.ContactRequestReference:output_type -> weshnet.protocol.v1.ContactRequestReference.Reply
102, // 84: weshnet.protocol.v1.ProtocolService.ContactRequestDisable:output_type -> weshnet.protocol.v1.ContactRequestDisable.Reply
104, // 85: weshnet.protocol.v1.ProtocolService.ContactRequestEnable:output_type -> weshnet.protocol.v1.ContactRequestEnable.Reply
106, // 86: weshnet.protocol.v1.ProtocolService.ContactRequestResetReference:output_type -> weshnet.protocol.v1.ContactRequestResetReference.Reply
108, // 87: weshnet.protocol.v1.ProtocolService.ContactRequestSend:output_type -> weshnet.protocol.v1.ContactRequestSend.Reply
110, // 88: weshnet.protocol.v1.ProtocolService.ContactRequestAccept:output_type -> weshnet.protocol.v1.ContactRequestAccept.Reply
112, // 89: weshnet.protocol.v1.ProtocolService.ContactRequestDiscard:output_type -> weshnet.protocol.v1.ContactRequestDiscard.Reply
114, // 90: weshnet.protocol.v1.ProtocolService.ShareContact:output_type -> weshnet.protocol.v1.ShareContact.Reply
116, // 91: weshnet.protocol.v1.ProtocolService.DecodeContact:output_type -> weshnet.protocol.v1.DecodeContact.Reply
118, // 92: weshnet.protocol.v1.ProtocolService.ContactBlock:output_type -> weshnet.protocol.v1.ContactBlock.Reply
120, // 93: weshnet.protocol.v1.ProtocolService.ContactUnblock:output_type -> weshnet.protocol.v1.ContactUnblock.Reply
122, // 94: weshnet.protocol.v1.ProtocolService.ContactAliasKeySend:output_type -> weshnet.protocol.v1.ContactAliasKeySend.Reply
124, // 95: weshnet.protocol.v1.ProtocolService.MultiMemberGroupCreate:output_type -> weshnet.protocol.v1.MultiMemberGroupCreate.Reply
126, // 96: weshnet.protocol.v1.ProtocolService.MultiMemberGroupJoin:output_type -> weshnet.protocol.v1.MultiMemberGroupJoin.Reply
128, // 97: weshnet.protocol.v1.ProtocolService.MultiMemberGroupLeave:output_type -> weshnet.protocol.v1.MultiMemberGroupLeave.Reply
130, // 98: weshnet.protocol.v1.ProtocolService.MultiMemberGroupAliasResolverDisclose:output_type -> weshnet.protocol.v1.MultiMemberGroupAliasResolverDisclose.Reply
132, // 99: weshnet.protocol.v1.ProtocolService.MultiMemberGroupAdminRoleGrant:output_type -> weshnet.protocol.v1.MultiMemberGroupAdminRoleGrant.Reply
134, // 100: weshnet.protocol.v1.ProtocolService.MultiMemberGroupInvitationCreate:output_type -> weshnet.protocol.v1.MultiMemberGroupInvitationCreate.Reply
136, // 101: weshnet.protocol.v1.ProtocolService.AppMetadataSend:output_type -> weshnet.protocol.v1.AppMetadataSend.Reply
138, // 102: weshnet.protocol.v1.ProtocolService.AppMessageSend:output_type -> weshnet.protocol.v1.AppMessageSend.Reply
64, // 103: weshnet.protocol.v1.ProtocolService.GroupMetadataList:output_type -> weshnet.protocol.v1.GroupMetadataEvent
65, // 104: weshnet.protocol.v1.ProtocolService.GroupMessageList:output_type -> weshnet.protocol.v1.GroupMessageEvent
142, // 105: weshnet.protocol.v1.ProtocolService.GroupInfo:output_type -> weshnet.protocol.v1.GroupInfo.Reply
144, // 106: weshnet.protocol.v1.ProtocolService.ActivateGroup:output_type -> weshnet.protocol.v1.ActivateGroup.Reply
146, // 107: weshnet.protocol.v1.ProtocolService.DeactivateGroup:output_type -> weshnet.protocol.v1.DeactivateGroup.Reply
148, // 108: weshnet.protocol.v1.ProtocolService.GroupDeviceStatus:output_type -> weshnet.protocol.v1.GroupDeviceStatus.Reply
153, // 109: weshnet.protocol.v1.ProtocolService.DebugListGroups:output_type -> weshnet.protocol.v1.DebugListGroups.Reply
155, // 110: weshnet.protocol.v1.ProtocolService.DebugInspectGroupStore:output_type -> weshnet.protocol.v1.DebugInspectGroupStore.Reply
157, // 111: weshnet.protocol.v1.ProtocolService.DebugGroup:output_type -> weshnet.protocol.v1.DebugGroup.Reply
169, // 112: weshnet.protocol.v1.ProtocolService.SystemInfo:output_type -> weshnet.protocol.v1.SystemInfo.Reply
159, // 113: weshnet.protocol.v1.ProtocolService.CredentialVerificationServiceInitFlow:output_type -> weshnet.protocol.v1.CredentialVerificationServiceInitFlow.Reply
161, // 114: weshnet.protocol.v1.ProtocolService.CredentialVerificationServiceCompleteFlow:output_type -> weshnet.protocol.v1.CredentialVerificationServiceCompleteFlow.Reply
163, // 115: weshnet.protocol.v1.ProtocolService.VerifiedCredentialsList:output_type -> weshnet.protocol.v1.VerifiedCredentialsList.Reply
165, // 116: weshnet.protocol.v1.ProtocolService.ReplicationServiceRegisterGroup:output_type -> weshnet.protocol.v1.ReplicationServiceRegisterGroup.Reply
175, // 117: weshnet.protocol.v1.ProtocolService.PeerList:output_type -> weshnet.protocol.v1.PeerList.Reply
180, // 118: weshnet.protocol.v1.ProtocolService.OutOfStoreReceive:output_type -> weshnet.protocol.v1.OutOfStoreReceive.Reply
182, // 119: weshnet.protocol.v1.ProtocolService.OutOfStoreSeal:output_type -> weshnet.protocol.v1.OutOfStoreSeal.Reply
186, // 120: weshnet.protocol.v1.ProtocolService.RefreshContactRequest:output_type -> weshnet.protocol.v1.RefreshContactRequest.Reply
81, // [81:121] is the sub-list for method output_type
41, // [41:81] is the sub-list for method input_type
41, // [41:41] is the sub-list for extension type_name
41, // [41:41] is the sub-list for extension extendee
0, // [0:41] is the sub-list for field type_name
}
func init() { file_protocoltypes_proto_init() }
func file_protocoltypes_proto_init() {
if File_protocoltypes_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_protocoltypes_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*Group); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*GroupHeadsExport); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*GroupMetadata); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*GroupEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[5].Exporter = func(v any, i int) any {
switch v := v.(*MessageHeaders); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[6].Exporter = func(v any, i int) any {
switch v := v.(*ProtocolMetadata); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[7].Exporter = func(v any, i int) any {
switch v := v.(*EncryptedMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[8].Exporter = func(v any, i int) any {
switch v := v.(*MessageEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[9].Exporter = func(v any, i int) any {
switch v := v.(*EventContext); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[10].Exporter = func(v any, i int) any {
switch v := v.(*GroupMetadataPayloadSent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[11].Exporter = func(v any, i int) any {
switch v := v.(*ContactAliasKeyAdded); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[12].Exporter = func(v any, i int) any {
switch v := v.(*GroupMemberDeviceAdded); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[13].Exporter = func(v any, i int) any {
switch v := v.(*DeviceChainKey); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[14].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceChainKeyAdded); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[15].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAliasResolverAdded); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[16].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAdminRoleGranted); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[17].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupInitialMemberAnnounced); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[18].Exporter = func(v any, i int) any {
switch v := v.(*GroupAddAdditionalRendezvousSeed); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[19].Exporter = func(v any, i int) any {
switch v := v.(*GroupRemoveAdditionalRendezvousSeed); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[20].Exporter = func(v any, i int) any {
switch v := v.(*AccountGroupJoined); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[21].Exporter = func(v any, i int) any {
switch v := v.(*AccountGroupLeft); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[22].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestDisabled); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[23].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestEnabled); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[24].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestReferenceReset); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[25].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestOutgoingEnqueued); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[26].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestOutgoingSent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[27].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestIncomingReceived); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[28].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestIncomingDiscarded); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[29].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactRequestIncomingAccepted); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[30].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactBlocked); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[31].Exporter = func(v any, i int) any {
switch v := v.(*AccountContactUnblocked); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[32].Exporter = func(v any, i int) any {
switch v := v.(*GroupReplicating); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[33].Exporter = func(v any, i int) any {
switch v := v.(*ServiceExportData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[34].Exporter = func(v any, i int) any {
switch v := v.(*ServiceGetConfiguration); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[35].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestReference); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[36].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDisable); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[37].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestEnable); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[38].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestResetReference); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[39].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestSend); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[40].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestAccept); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[41].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDiscard); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[42].Exporter = func(v any, i int) any {
switch v := v.(*ShareContact); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[43].Exporter = func(v any, i int) any {
switch v := v.(*DecodeContact); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[44].Exporter = func(v any, i int) any {
switch v := v.(*ContactBlock); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[45].Exporter = func(v any, i int) any {
switch v := v.(*ContactUnblock); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[46].Exporter = func(v any, i int) any {
switch v := v.(*ContactAliasKeySend); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[47].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupCreate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[48].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupJoin); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[49].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupLeave); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[50].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAliasResolverDisclose); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[51].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAdminRoleGrant); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[52].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupInvitationCreate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[53].Exporter = func(v any, i int) any {
switch v := v.(*AppMetadataSend); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[54].Exporter = func(v any, i int) any {
switch v := v.(*AppMessageSend); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[55].Exporter = func(v any, i int) any {
switch v := v.(*GroupMetadataEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[56].Exporter = func(v any, i int) any {
switch v := v.(*GroupMessageEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[57].Exporter = func(v any, i int) any {
switch v := v.(*GroupMetadataList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[58].Exporter = func(v any, i int) any {
switch v := v.(*GroupMessageList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[59].Exporter = func(v any, i int) any {
switch v := v.(*GroupInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[60].Exporter = func(v any, i int) any {
switch v := v.(*ActivateGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[61].Exporter = func(v any, i int) any {
switch v := v.(*DeactivateGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[62].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[63].Exporter = func(v any, i int) any {
switch v := v.(*DebugListGroups); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[64].Exporter = func(v any, i int) any {
switch v := v.(*DebugInspectGroupStore); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[65].Exporter = func(v any, i int) any {
switch v := v.(*DebugGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[66].Exporter = func(v any, i int) any {
switch v := v.(*ShareableContact); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[67].Exporter = func(v any, i int) any {
switch v := v.(*ServiceTokenSupportedService); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[68].Exporter = func(v any, i int) any {
switch v := v.(*ServiceToken); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[69].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceInitFlow); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[70].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceCompleteFlow); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[71].Exporter = func(v any, i int) any {
switch v := v.(*VerifiedCredentialsList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[72].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceRegisterGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[73].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[74].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[75].Exporter = func(v any, i int) any {
switch v := v.(*PeerList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[76].Exporter = func(v any, i int) any {
switch v := v.(*Progress); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[77].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[78].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreMessageEnvelope); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[79].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreReceive); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[80].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreSeal); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[81].Exporter = func(v any, i int) any {
switch v := v.(*AccountVerifiedCredentialRegistered); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[82].Exporter = func(v any, i int) any {
switch v := v.(*FirstLastCounters); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[83].Exporter = func(v any, i int) any {
switch v := v.(*OrbitDBMessageHeads); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[84].Exporter = func(v any, i int) any {
switch v := v.(*RefreshContactRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[86].Exporter = func(v any, i int) any {
switch v := v.(*ServiceExportData_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[87].Exporter = func(v any, i int) any {
switch v := v.(*ServiceExportData_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[88].Exporter = func(v any, i int) any {
switch v := v.(*ServiceGetConfiguration_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[89].Exporter = func(v any, i int) any {
switch v := v.(*ServiceGetConfiguration_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[90].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestReference_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[91].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestReference_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[92].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDisable_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[93].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDisable_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[94].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestEnable_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[95].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestEnable_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[96].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestResetReference_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[97].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestResetReference_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[98].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestSend_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[99].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestSend_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[100].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestAccept_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[101].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestAccept_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[102].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDiscard_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[103].Exporter = func(v any, i int) any {
switch v := v.(*ContactRequestDiscard_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[104].Exporter = func(v any, i int) any {
switch v := v.(*ShareContact_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[105].Exporter = func(v any, i int) any {
switch v := v.(*ShareContact_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[106].Exporter = func(v any, i int) any {
switch v := v.(*DecodeContact_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[107].Exporter = func(v any, i int) any {
switch v := v.(*DecodeContact_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[108].Exporter = func(v any, i int) any {
switch v := v.(*ContactBlock_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[109].Exporter = func(v any, i int) any {
switch v := v.(*ContactBlock_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[110].Exporter = func(v any, i int) any {
switch v := v.(*ContactUnblock_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[111].Exporter = func(v any, i int) any {
switch v := v.(*ContactUnblock_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[112].Exporter = func(v any, i int) any {
switch v := v.(*ContactAliasKeySend_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[113].Exporter = func(v any, i int) any {
switch v := v.(*ContactAliasKeySend_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[114].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupCreate_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[115].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupCreate_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[116].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupJoin_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[117].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupJoin_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[118].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupLeave_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[119].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupLeave_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[120].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAliasResolverDisclose_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[121].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAliasResolverDisclose_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[122].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAdminRoleGrant_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[123].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupAdminRoleGrant_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[124].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupInvitationCreate_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[125].Exporter = func(v any, i int) any {
switch v := v.(*MultiMemberGroupInvitationCreate_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[126].Exporter = func(v any, i int) any {
switch v := v.(*AppMetadataSend_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[127].Exporter = func(v any, i int) any {
switch v := v.(*AppMetadataSend_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[128].Exporter = func(v any, i int) any {
switch v := v.(*AppMessageSend_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[129].Exporter = func(v any, i int) any {
switch v := v.(*AppMessageSend_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[130].Exporter = func(v any, i int) any {
switch v := v.(*GroupMetadataList_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[131].Exporter = func(v any, i int) any {
switch v := v.(*GroupMessageList_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[132].Exporter = func(v any, i int) any {
switch v := v.(*GroupInfo_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[133].Exporter = func(v any, i int) any {
switch v := v.(*GroupInfo_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[134].Exporter = func(v any, i int) any {
switch v := v.(*ActivateGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[135].Exporter = func(v any, i int) any {
switch v := v.(*ActivateGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[136].Exporter = func(v any, i int) any {
switch v := v.(*DeactivateGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[137].Exporter = func(v any, i int) any {
switch v := v.(*DeactivateGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[138].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[139].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[140].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus_Reply_PeerConnected); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[141].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus_Reply_PeerReconnecting); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[142].Exporter = func(v any, i int) any {
switch v := v.(*GroupDeviceStatus_Reply_PeerDisconnected); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[143].Exporter = func(v any, i int) any {
switch v := v.(*DebugListGroups_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[144].Exporter = func(v any, i int) any {
switch v := v.(*DebugListGroups_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[145].Exporter = func(v any, i int) any {
switch v := v.(*DebugInspectGroupStore_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[146].Exporter = func(v any, i int) any {
switch v := v.(*DebugInspectGroupStore_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[147].Exporter = func(v any, i int) any {
switch v := v.(*DebugGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[148].Exporter = func(v any, i int) any {
switch v := v.(*DebugGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[149].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceInitFlow_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[150].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceInitFlow_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[151].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceCompleteFlow_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[152].Exporter = func(v any, i int) any {
switch v := v.(*CredentialVerificationServiceCompleteFlow_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[153].Exporter = func(v any, i int) any {
switch v := v.(*VerifiedCredentialsList_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[154].Exporter = func(v any, i int) any {
switch v := v.(*VerifiedCredentialsList_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[155].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceRegisterGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[156].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceRegisterGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[157].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[158].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[159].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[160].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[161].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_OrbitDB); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[162].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_P2P); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[163].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_Process); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[164].Exporter = func(v any, i int) any {
switch v := v.(*SystemInfo_OrbitDB_ReplicationStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[165].Exporter = func(v any, i int) any {
switch v := v.(*PeerList_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[166].Exporter = func(v any, i int) any {
switch v := v.(*PeerList_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[167].Exporter = func(v any, i int) any {
switch v := v.(*PeerList_Peer); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[168].Exporter = func(v any, i int) any {
switch v := v.(*PeerList_Route); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[169].Exporter = func(v any, i int) any {
switch v := v.(*PeerList_Stream); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[170].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreReceive_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[171].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreReceive_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[172].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreSeal_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[173].Exporter = func(v any, i int) any {
switch v := v.(*OutOfStoreSeal_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[174].Exporter = func(v any, i int) any {
switch v := v.(*OrbitDBMessageHeads_Box); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[175].Exporter = func(v any, i int) any {
switch v := v.(*RefreshContactRequest_Peer); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[176].Exporter = func(v any, i int) any {
switch v := v.(*RefreshContactRequest_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protocoltypes_proto_msgTypes[177].Exporter = func(v any, i int) any {
switch v := v.(*RefreshContactRequest_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_protocoltypes_proto_rawDesc,
NumEnums: 9,
NumMessages: 178,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_protocoltypes_proto_goTypes,
DependencyIndexes: file_protocoltypes_proto_depIdxs,
EnumInfos: file_protocoltypes_proto_enumTypes,
MessageInfos: file_protocoltypes_proto_msgTypes,
}.Build()
File_protocoltypes_proto = out.File
file_protocoltypes_proto_rawDesc = nil
file_protocoltypes_proto_goTypes = nil
file_protocoltypes_proto_depIdxs = nil
}
================================================
FILE: pkg/protocoltypes/protocoltypes.pb.gw.go
================================================
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: protocoltypes.proto
/*
Package protocoltypes is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package protocoltypes
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
func request_ProtocolService_ServiceExportData_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_ServiceExportDataClient, runtime.ServerMetadata, error) {
var protoReq ServiceExportData_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.ServiceExportData(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_ServiceGetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ServiceGetConfiguration_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ServiceGetConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ServiceGetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ServiceGetConfiguration_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ServiceGetConfiguration(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestReference_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestReference_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestReference(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestReference_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestReference_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestReference(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestDisable_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestDisable_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestDisable(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestDisable_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestDisable_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestDisable(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestEnable_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestEnable_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestEnable(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestEnable_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestEnable_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestEnable(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestResetReference_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestResetReference_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestResetReference(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestResetReference_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestResetReference_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestResetReference(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestSend_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestSend(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestSend_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestSend(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestAccept_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestAccept_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestAccept(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestAccept_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestAccept_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestAccept(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactRequestDiscard_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestDiscard_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactRequestDiscard(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactRequestDiscard_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactRequestDiscard_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactRequestDiscard(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ShareContact_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ShareContact_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ShareContact(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ShareContact_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ShareContact_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ShareContact(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_DecodeContact_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DecodeContact_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DecodeContact(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_DecodeContact_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DecodeContact_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.DecodeContact(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactBlock_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactBlock_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactBlock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactBlock_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactBlock_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactBlock(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactUnblock_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactUnblock_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactUnblock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactUnblock_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactUnblock_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactUnblock(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ContactAliasKeySend_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactAliasKeySend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContactAliasKeySend(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ContactAliasKeySend_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContactAliasKeySend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContactAliasKeySend(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupCreate_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupCreate_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupCreate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupCreate_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupCreate_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupCreate(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupJoin_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupJoin_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupJoin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupJoin_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupJoin_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupJoin(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupLeave_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupLeave_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupLeave(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupLeave_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupLeave_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupLeave(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupAliasResolverDisclose_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupAliasResolverDisclose(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupAliasResolverDisclose_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupAliasResolverDisclose(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupAdminRoleGrant_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupAdminRoleGrant_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupAdminRoleGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupAdminRoleGrant_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupAdminRoleGrant_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupAdminRoleGrant(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_MultiMemberGroupInvitationCreate_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupInvitationCreate_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.MultiMemberGroupInvitationCreate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_MultiMemberGroupInvitationCreate_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MultiMemberGroupInvitationCreate_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.MultiMemberGroupInvitationCreate(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_AppMetadataSend_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AppMetadataSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.AppMetadataSend(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_AppMetadataSend_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AppMetadataSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.AppMetadataSend(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_AppMessageSend_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AppMessageSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.AppMessageSend(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_AppMessageSend_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AppMessageSend_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.AppMessageSend(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_GroupMetadataList_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_GroupMetadataListClient, runtime.ServerMetadata, error) {
var protoReq GroupMetadataList_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.GroupMetadataList(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_GroupMessageList_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_GroupMessageListClient, runtime.ServerMetadata, error) {
var protoReq GroupMessageList_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.GroupMessageList(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_GroupInfo_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GroupInfo_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GroupInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_GroupInfo_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GroupInfo_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GroupInfo(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_ActivateGroup_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ActivateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ActivateGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ActivateGroup_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ActivateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ActivateGroup(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_DeactivateGroup_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeactivateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DeactivateGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_DeactivateGroup_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeactivateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.DeactivateGroup(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_GroupDeviceStatus_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_GroupDeviceStatusClient, runtime.ServerMetadata, error) {
var protoReq GroupDeviceStatus_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.GroupDeviceStatus(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_DebugListGroups_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_DebugListGroupsClient, runtime.ServerMetadata, error) {
var protoReq DebugListGroups_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.DebugListGroups(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_DebugInspectGroupStore_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_DebugInspectGroupStoreClient, runtime.ServerMetadata, error) {
var protoReq DebugInspectGroupStore_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.DebugInspectGroupStore(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_DebugGroup_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DebugGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DebugGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_DebugGroup_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DebugGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.DebugGroup(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_SystemInfo_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SystemInfo_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.SystemInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_SystemInfo_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SystemInfo_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SystemInfo(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_CredentialVerificationServiceInitFlow_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CredentialVerificationServiceInitFlow_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CredentialVerificationServiceInitFlow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_CredentialVerificationServiceInitFlow_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CredentialVerificationServiceInitFlow_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.CredentialVerificationServiceInitFlow(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_CredentialVerificationServiceCompleteFlow_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CredentialVerificationServiceCompleteFlow_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CredentialVerificationServiceCompleteFlow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_CredentialVerificationServiceCompleteFlow_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CredentialVerificationServiceCompleteFlow_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.CredentialVerificationServiceCompleteFlow(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_VerifiedCredentialsList_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (ProtocolService_VerifiedCredentialsListClient, runtime.ServerMetadata, error) {
var protoReq VerifiedCredentialsList_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.VerifiedCredentialsList(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ProtocolService_ReplicationServiceRegisterGroup_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicationServiceRegisterGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReplicationServiceRegisterGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_ReplicationServiceRegisterGroup_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicationServiceRegisterGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReplicationServiceRegisterGroup(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_PeerList_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PeerList_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.PeerList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_PeerList_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq PeerList_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.PeerList(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.OutOfStoreReceive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_OutOfStoreReceive_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OutOfStoreReceive_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.OutOfStoreReceive(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_OutOfStoreSeal_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OutOfStoreSeal_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.OutOfStoreSeal(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_OutOfStoreSeal_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OutOfStoreSeal_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.OutOfStoreSeal(ctx, &protoReq)
return msg, metadata, err
}
func request_ProtocolService_RefreshContactRequest_0(ctx context.Context, marshaler runtime.Marshaler, client ProtocolServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RefreshContactRequest_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.RefreshContactRequest(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ProtocolService_RefreshContactRequest_0(ctx context.Context, marshaler runtime.Marshaler, server ProtocolServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RefreshContactRequest_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.RefreshContactRequest(ctx, &protoReq)
return msg, metadata, err
}
// RegisterProtocolServiceHandlerServer registers the http handlers for service ProtocolService to "mux".
// UnaryRPC :call ProtocolServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterProtocolServiceHandlerFromEndpoint instead.
func RegisterProtocolServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ProtocolServiceServer) error {
mux.Handle("POST", pattern_ProtocolService_ServiceExportData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_ServiceGetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ServiceGetConfiguration_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ServiceGetConfiguration_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestReference_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestReference_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestReference_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestDisable_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestDisable_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestDisable_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestEnable_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestEnable_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestEnable_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestResetReference_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestResetReference_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestResetReference_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestSend_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestAccept_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestAccept_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestAccept_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestDiscard_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactRequestDiscard_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestDiscard_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ShareContact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ShareContact_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ShareContact_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DecodeContact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_DecodeContact_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DecodeContact_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactBlock_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactUnblock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactUnblock_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactUnblock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactAliasKeySend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ContactAliasKeySend_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactAliasKeySend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupCreate_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupCreate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupJoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupJoin_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupJoin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupLeave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupLeave_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupLeave_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupAliasResolverDisclose_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupAdminRoleGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupAdminRoleGrant_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupAdminRoleGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupInvitationCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_MultiMemberGroupInvitationCreate_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupInvitationCreate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_AppMetadataSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_AppMetadataSend_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_AppMetadataSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_AppMessageSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_AppMessageSend_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_AppMessageSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupMetadataList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_GroupMessageList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_GroupInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_GroupInfo_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_GroupInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ActivateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ActivateGroup_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ActivateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DeactivateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_DeactivateGroup_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DeactivateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupDeviceStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_DebugListGroups_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_DebugInspectGroupStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_DebugGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_DebugGroup_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DebugGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_SystemInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_SystemInfo_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_SystemInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_CredentialVerificationServiceInitFlow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_CredentialVerificationServiceInitFlow_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_CredentialVerificationServiceInitFlow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_CredentialVerificationServiceCompleteFlow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_CredentialVerificationServiceCompleteFlow_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_CredentialVerificationServiceCompleteFlow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_VerifiedCredentialsList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
})
mux.Handle("POST", pattern_ProtocolService_ReplicationServiceRegisterGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_ReplicationServiceRegisterGroup_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ReplicationServiceRegisterGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_PeerList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_PeerList_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_PeerList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_OutOfStoreReceive_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_OutOfStoreSeal_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_OutOfStoreSeal_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_OutOfStoreSeal_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_RefreshContactRequest_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ProtocolService_RefreshContactRequest_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_RefreshContactRequest_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterProtocolServiceHandlerFromEndpoint is same as RegisterProtocolServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterProtocolServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterProtocolServiceHandler(ctx, mux, conn)
}
// RegisterProtocolServiceHandler registers the http handlers for service ProtocolService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterProtocolServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterProtocolServiceHandlerClient(ctx, mux, NewProtocolServiceClient(conn))
}
// RegisterProtocolServiceHandlerClient registers the http handlers for service ProtocolService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ProtocolServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ProtocolServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ProtocolServiceClient" to call the correct interceptors.
func RegisterProtocolServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ProtocolServiceClient) error {
mux.Handle("POST", pattern_ProtocolService_ServiceExportData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ServiceExportData_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ServiceExportData_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ServiceGetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ServiceGetConfiguration_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ServiceGetConfiguration_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestReference_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestReference_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestReference_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestDisable_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestDisable_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestDisable_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestEnable_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestEnable_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestEnable_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestResetReference_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestResetReference_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestResetReference_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestSend_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestAccept_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestAccept_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestAccept_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactRequestDiscard_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactRequestDiscard_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactRequestDiscard_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ShareContact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ShareContact_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ShareContact_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DecodeContact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_DecodeContact_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DecodeContact_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactBlock_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactUnblock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactUnblock_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactUnblock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ContactAliasKeySend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ContactAliasKeySend_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ContactAliasKeySend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupCreate_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupCreate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupJoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupJoin_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupJoin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupLeave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupLeave_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupLeave_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupAliasResolverDisclose_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupAliasResolverDisclose_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupAdminRoleGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupAdminRoleGrant_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupAdminRoleGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_MultiMemberGroupInvitationCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_MultiMemberGroupInvitationCreate_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_MultiMemberGroupInvitationCreate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_AppMetadataSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_AppMetadataSend_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_AppMetadataSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_AppMessageSend_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_AppMessageSend_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_AppMessageSend_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupMetadataList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_GroupMetadataList_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_GroupMetadataList_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupMessageList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_GroupMessageList_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_GroupMessageList_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_GroupInfo_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_GroupInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ActivateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ActivateGroup_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ActivateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DeactivateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_DeactivateGroup_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DeactivateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_GroupDeviceStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_GroupDeviceStatus_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_GroupDeviceStatus_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DebugListGroups_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_DebugListGroups_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DebugListGroups_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DebugInspectGroupStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_DebugInspectGroupStore_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DebugInspectGroupStore_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_DebugGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_DebugGroup_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_DebugGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_SystemInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_SystemInfo_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_SystemInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_CredentialVerificationServiceInitFlow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_CredentialVerificationServiceInitFlow_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_CredentialVerificationServiceInitFlow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_CredentialVerificationServiceCompleteFlow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_CredentialVerificationServiceCompleteFlow_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_CredentialVerificationServiceCompleteFlow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_VerifiedCredentialsList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_VerifiedCredentialsList_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_VerifiedCredentialsList_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_ReplicationServiceRegisterGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_ReplicationServiceRegisterGroup_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_ReplicationServiceRegisterGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_PeerList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_PeerList_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_PeerList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_OutOfStoreReceive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_OutOfStoreReceive_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_OutOfStoreReceive_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_OutOfStoreSeal_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_OutOfStoreSeal_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_OutOfStoreSeal_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProtocolService_RefreshContactRequest_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProtocolService_RefreshContactRequest_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProtocolService_RefreshContactRequest_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_ProtocolService_ServiceExportData_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ServiceExportData"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ServiceGetConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ServiceGetConfiguration"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestReference_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestReference"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestDisable_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestDisable"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestEnable_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestEnable"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestResetReference_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestResetReference"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestSend"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestAccept_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestAccept"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactRequestDiscard_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactRequestDiscard"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ShareContact_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ShareContact"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_DecodeContact_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "DecodeContact"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactBlock"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactUnblock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactUnblock"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ContactAliasKeySend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ContactAliasKeySend"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupCreate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupCreate"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupJoin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupJoin"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupLeave_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupLeave"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupAliasResolverDisclose_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupAliasResolverDisclose"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupAdminRoleGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupAdminRoleGrant"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_MultiMemberGroupInvitationCreate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "MultiMemberGroupInvitationCreate"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_AppMetadataSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "AppMetadataSend"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_AppMessageSend_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "AppMessageSend"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_GroupMetadataList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "GroupMetadataList"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_GroupMessageList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "GroupMessageList"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_GroupInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "GroupInfo"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ActivateGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ActivateGroup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_DeactivateGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "DeactivateGroup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_GroupDeviceStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "GroupDeviceStatus"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_DebugListGroups_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "DebugListGroups"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_DebugInspectGroupStore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "DebugInspectGroupStore"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_DebugGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "DebugGroup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_SystemInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "SystemInfo"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_CredentialVerificationServiceInitFlow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "CredentialVerificationServiceInitFlow"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_CredentialVerificationServiceCompleteFlow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "CredentialVerificationServiceCompleteFlow"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_VerifiedCredentialsList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "VerifiedCredentialsList"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_ReplicationServiceRegisterGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "ReplicationServiceRegisterGroup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_PeerList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "PeerList"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_OutOfStoreReceive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "OutOfStoreReceive"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_OutOfStoreSeal_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "OutOfStoreSeal"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ProtocolService_RefreshContactRequest_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.protocol.v1.ProtocolService", "RefreshContactRequest"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_ProtocolService_ServiceExportData_0 = runtime.ForwardResponseStream
forward_ProtocolService_ServiceGetConfiguration_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestReference_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestDisable_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestEnable_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestResetReference_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestSend_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestAccept_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactRequestDiscard_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ShareContact_0 = runtime.ForwardResponseMessage
forward_ProtocolService_DecodeContact_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactBlock_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactUnblock_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ContactAliasKeySend_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupCreate_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupJoin_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupLeave_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupAliasResolverDisclose_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupAdminRoleGrant_0 = runtime.ForwardResponseMessage
forward_ProtocolService_MultiMemberGroupInvitationCreate_0 = runtime.ForwardResponseMessage
forward_ProtocolService_AppMetadataSend_0 = runtime.ForwardResponseMessage
forward_ProtocolService_AppMessageSend_0 = runtime.ForwardResponseMessage
forward_ProtocolService_GroupMetadataList_0 = runtime.ForwardResponseStream
forward_ProtocolService_GroupMessageList_0 = runtime.ForwardResponseStream
forward_ProtocolService_GroupInfo_0 = runtime.ForwardResponseMessage
forward_ProtocolService_ActivateGroup_0 = runtime.ForwardResponseMessage
forward_ProtocolService_DeactivateGroup_0 = runtime.ForwardResponseMessage
forward_ProtocolService_GroupDeviceStatus_0 = runtime.ForwardResponseStream
forward_ProtocolService_DebugListGroups_0 = runtime.ForwardResponseStream
forward_ProtocolService_DebugInspectGroupStore_0 = runtime.ForwardResponseStream
forward_ProtocolService_DebugGroup_0 = runtime.ForwardResponseMessage
forward_ProtocolService_SystemInfo_0 = runtime.ForwardResponseMessage
forward_ProtocolService_CredentialVerificationServiceInitFlow_0 = runtime.ForwardResponseMessage
forward_ProtocolService_CredentialVerificationServiceCompleteFlow_0 = runtime.ForwardResponseMessage
forward_ProtocolService_VerifiedCredentialsList_0 = runtime.ForwardResponseStream
forward_ProtocolService_ReplicationServiceRegisterGroup_0 = runtime.ForwardResponseMessage
forward_ProtocolService_PeerList_0 = runtime.ForwardResponseMessage
forward_ProtocolService_OutOfStoreReceive_0 = runtime.ForwardResponseMessage
forward_ProtocolService_OutOfStoreSeal_0 = runtime.ForwardResponseMessage
forward_ProtocolService_RefreshContactRequest_0 = runtime.ForwardResponseMessage
)
================================================
FILE: pkg/protocoltypes/protocoltypes_grpc.pb.go
================================================
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: protocoltypes.proto
package protocoltypes
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
ProtocolService_ServiceExportData_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ServiceExportData"
ProtocolService_ServiceGetConfiguration_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ServiceGetConfiguration"
ProtocolService_ContactRequestReference_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestReference"
ProtocolService_ContactRequestDisable_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestDisable"
ProtocolService_ContactRequestEnable_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestEnable"
ProtocolService_ContactRequestResetReference_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestResetReference"
ProtocolService_ContactRequestSend_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestSend"
ProtocolService_ContactRequestAccept_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestAccept"
ProtocolService_ContactRequestDiscard_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactRequestDiscard"
ProtocolService_ShareContact_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ShareContact"
ProtocolService_DecodeContact_FullMethodName = "/weshnet.protocol.v1.ProtocolService/DecodeContact"
ProtocolService_ContactBlock_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactBlock"
ProtocolService_ContactUnblock_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactUnblock"
ProtocolService_ContactAliasKeySend_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ContactAliasKeySend"
ProtocolService_MultiMemberGroupCreate_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupCreate"
ProtocolService_MultiMemberGroupJoin_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupJoin"
ProtocolService_MultiMemberGroupLeave_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupLeave"
ProtocolService_MultiMemberGroupAliasResolverDisclose_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupAliasResolverDisclose"
ProtocolService_MultiMemberGroupAdminRoleGrant_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupAdminRoleGrant"
ProtocolService_MultiMemberGroupInvitationCreate_FullMethodName = "/weshnet.protocol.v1.ProtocolService/MultiMemberGroupInvitationCreate"
ProtocolService_AppMetadataSend_FullMethodName = "/weshnet.protocol.v1.ProtocolService/AppMetadataSend"
ProtocolService_AppMessageSend_FullMethodName = "/weshnet.protocol.v1.ProtocolService/AppMessageSend"
ProtocolService_GroupMetadataList_FullMethodName = "/weshnet.protocol.v1.ProtocolService/GroupMetadataList"
ProtocolService_GroupMessageList_FullMethodName = "/weshnet.protocol.v1.ProtocolService/GroupMessageList"
ProtocolService_GroupInfo_FullMethodName = "/weshnet.protocol.v1.ProtocolService/GroupInfo"
ProtocolService_ActivateGroup_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ActivateGroup"
ProtocolService_DeactivateGroup_FullMethodName = "/weshnet.protocol.v1.ProtocolService/DeactivateGroup"
ProtocolService_GroupDeviceStatus_FullMethodName = "/weshnet.protocol.v1.ProtocolService/GroupDeviceStatus"
ProtocolService_DebugListGroups_FullMethodName = "/weshnet.protocol.v1.ProtocolService/DebugListGroups"
ProtocolService_DebugInspectGroupStore_FullMethodName = "/weshnet.protocol.v1.ProtocolService/DebugInspectGroupStore"
ProtocolService_DebugGroup_FullMethodName = "/weshnet.protocol.v1.ProtocolService/DebugGroup"
ProtocolService_SystemInfo_FullMethodName = "/weshnet.protocol.v1.ProtocolService/SystemInfo"
ProtocolService_CredentialVerificationServiceInitFlow_FullMethodName = "/weshnet.protocol.v1.ProtocolService/CredentialVerificationServiceInitFlow"
ProtocolService_CredentialVerificationServiceCompleteFlow_FullMethodName = "/weshnet.protocol.v1.ProtocolService/CredentialVerificationServiceCompleteFlow"
ProtocolService_VerifiedCredentialsList_FullMethodName = "/weshnet.protocol.v1.ProtocolService/VerifiedCredentialsList"
ProtocolService_ReplicationServiceRegisterGroup_FullMethodName = "/weshnet.protocol.v1.ProtocolService/ReplicationServiceRegisterGroup"
ProtocolService_PeerList_FullMethodName = "/weshnet.protocol.v1.ProtocolService/PeerList"
ProtocolService_OutOfStoreReceive_FullMethodName = "/weshnet.protocol.v1.ProtocolService/OutOfStoreReceive"
ProtocolService_OutOfStoreSeal_FullMethodName = "/weshnet.protocol.v1.ProtocolService/OutOfStoreSeal"
ProtocolService_RefreshContactRequest_FullMethodName = "/weshnet.protocol.v1.ProtocolService/RefreshContactRequest"
)
// ProtocolServiceClient is the client API for ProtocolService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// ProtocolService is the top-level API to manage the Wesh protocol service.
// Each active Wesh protocol service is considered as a Wesh device and is associated with a Wesh user.
type ProtocolServiceClient interface {
// ServiceExportData exports the current data of the protocol service
ServiceExportData(ctx context.Context, in *ServiceExportData_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ServiceExportData_Reply], error)
// ServiceGetConfiguration gets the current configuration of the protocol service
ServiceGetConfiguration(ctx context.Context, in *ServiceGetConfiguration_Request, opts ...grpc.CallOption) (*ServiceGetConfiguration_Reply, error)
// ContactRequestReference retrieves the information required to create a reference (ie. included in a shareable link) to the current account
ContactRequestReference(ctx context.Context, in *ContactRequestReference_Request, opts ...grpc.CallOption) (*ContactRequestReference_Reply, error)
// ContactRequestDisable disables incoming contact requests
ContactRequestDisable(ctx context.Context, in *ContactRequestDisable_Request, opts ...grpc.CallOption) (*ContactRequestDisable_Reply, error)
// ContactRequestEnable enables incoming contact requests
ContactRequestEnable(ctx context.Context, in *ContactRequestEnable_Request, opts ...grpc.CallOption) (*ContactRequestEnable_Reply, error)
// ContactRequestResetReference changes the contact request reference
ContactRequestResetReference(ctx context.Context, in *ContactRequestResetReference_Request, opts ...grpc.CallOption) (*ContactRequestResetReference_Reply, error)
// ContactRequestSend attempt to send a contact request
ContactRequestSend(ctx context.Context, in *ContactRequestSend_Request, opts ...grpc.CallOption) (*ContactRequestSend_Reply, error)
// ContactRequestAccept accepts a contact request
ContactRequestAccept(ctx context.Context, in *ContactRequestAccept_Request, opts ...grpc.CallOption) (*ContactRequestAccept_Reply, error)
// ContactRequestDiscard ignores a contact request, without informing the other user
ContactRequestDiscard(ctx context.Context, in *ContactRequestDiscard_Request, opts ...grpc.CallOption) (*ContactRequestDiscard_Reply, error)
// ShareContact uses ContactRequestReference to get the contact information for the current account and
// returns the Protobuf encoding of a shareable contact which you can further encode and share. If needed, this
// will reset the contact request reference and enable contact requests. To decode the result, see DecodeContact.
ShareContact(ctx context.Context, in *ShareContact_Request, opts ...grpc.CallOption) (*ShareContact_Reply, error)
// DecodeContact decodes the Protobuf encoding of a shareable contact which was returned by ShareContact.
DecodeContact(ctx context.Context, in *DecodeContact_Request, opts ...grpc.CallOption) (*DecodeContact_Reply, error)
// ContactBlock blocks a contact from sending requests
ContactBlock(ctx context.Context, in *ContactBlock_Request, opts ...grpc.CallOption) (*ContactBlock_Reply, error)
// ContactUnblock unblocks a contact from sending requests
ContactUnblock(ctx context.Context, in *ContactUnblock_Request, opts ...grpc.CallOption) (*ContactUnblock_Reply, error)
// ContactAliasKeySend send an alias key to a contact, the contact will be able to assert that your account is being present on a multi-member group
ContactAliasKeySend(ctx context.Context, in *ContactAliasKeySend_Request, opts ...grpc.CallOption) (*ContactAliasKeySend_Reply, error)
// MultiMemberGroupCreate creates a new multi-member group
MultiMemberGroupCreate(ctx context.Context, in *MultiMemberGroupCreate_Request, opts ...grpc.CallOption) (*MultiMemberGroupCreate_Reply, error)
// MultiMemberGroupJoin joins a multi-member group
MultiMemberGroupJoin(ctx context.Context, in *MultiMemberGroupJoin_Request, opts ...grpc.CallOption) (*MultiMemberGroupJoin_Reply, error)
// MultiMemberGroupLeave leaves a multi-member group
MultiMemberGroupLeave(ctx context.Context, in *MultiMemberGroupLeave_Request, opts ...grpc.CallOption) (*MultiMemberGroupLeave_Reply, error)
// MultiMemberGroupAliasResolverDisclose discloses your alias resolver key
MultiMemberGroupAliasResolverDisclose(ctx context.Context, in *MultiMemberGroupAliasResolverDisclose_Request, opts ...grpc.CallOption) (*MultiMemberGroupAliasResolverDisclose_Reply, error)
// MultiMemberGroupAdminRoleGrant grants an admin role to a group member
MultiMemberGroupAdminRoleGrant(ctx context.Context, in *MultiMemberGroupAdminRoleGrant_Request, opts ...grpc.CallOption) (*MultiMemberGroupAdminRoleGrant_Reply, error)
// MultiMemberGroupInvitationCreate creates an invitation to a multi-member group
MultiMemberGroupInvitationCreate(ctx context.Context, in *MultiMemberGroupInvitationCreate_Request, opts ...grpc.CallOption) (*MultiMemberGroupInvitationCreate_Reply, error)
// AppMetadataSend adds an app event to the metadata store, the message is encrypted using a symmetric key and readable by future group members
AppMetadataSend(ctx context.Context, in *AppMetadataSend_Request, opts ...grpc.CallOption) (*AppMetadataSend_Reply, error)
// AppMessageSend adds an app event to the message store, the message is encrypted using a derived key and readable by current group members
AppMessageSend(ctx context.Context, in *AppMessageSend_Request, opts ...grpc.CallOption) (*AppMessageSend_Reply, error)
// GroupMetadataList replays previous and subscribes to new metadata events from the group
GroupMetadataList(ctx context.Context, in *GroupMetadataList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupMetadataEvent], error)
// GroupMessageList replays previous and subscribes to new message events from the group
GroupMessageList(ctx context.Context, in *GroupMessageList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupMessageEvent], error)
// GroupInfo retrieves information about a group
GroupInfo(ctx context.Context, in *GroupInfo_Request, opts ...grpc.CallOption) (*GroupInfo_Reply, error)
// ActivateGroup explicitly opens a group
ActivateGroup(ctx context.Context, in *ActivateGroup_Request, opts ...grpc.CallOption) (*ActivateGroup_Reply, error)
// DeactivateGroup closes a group
DeactivateGroup(ctx context.Context, in *DeactivateGroup_Request, opts ...grpc.CallOption) (*DeactivateGroup_Reply, error)
// GroupDeviceStatus monitor device status
GroupDeviceStatus(ctx context.Context, in *GroupDeviceStatus_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupDeviceStatus_Reply], error)
DebugListGroups(ctx context.Context, in *DebugListGroups_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DebugListGroups_Reply], error)
DebugInspectGroupStore(ctx context.Context, in *DebugInspectGroupStore_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DebugInspectGroupStore_Reply], error)
DebugGroup(ctx context.Context, in *DebugGroup_Request, opts ...grpc.CallOption) (*DebugGroup_Reply, error)
SystemInfo(ctx context.Context, in *SystemInfo_Request, opts ...grpc.CallOption) (*SystemInfo_Reply, error)
// CredentialVerificationServiceInitFlow Initialize a credential verification flow
CredentialVerificationServiceInitFlow(ctx context.Context, in *CredentialVerificationServiceInitFlow_Request, opts ...grpc.CallOption) (*CredentialVerificationServiceInitFlow_Reply, error)
// CredentialVerificationServiceCompleteFlow Completes a credential verification flow
CredentialVerificationServiceCompleteFlow(ctx context.Context, in *CredentialVerificationServiceCompleteFlow_Request, opts ...grpc.CallOption) (*CredentialVerificationServiceCompleteFlow_Reply, error)
// VerifiedCredentialsList Retrieves the list of verified credentials
VerifiedCredentialsList(ctx context.Context, in *VerifiedCredentialsList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[VerifiedCredentialsList_Reply], error)
// ReplicationServiceRegisterGroup Asks a replication service to distribute a group contents
ReplicationServiceRegisterGroup(ctx context.Context, in *ReplicationServiceRegisterGroup_Request, opts ...grpc.CallOption) (*ReplicationServiceRegisterGroup_Reply, error)
// PeerList returns a list of P2P peers
PeerList(ctx context.Context, in *PeerList_Request, opts ...grpc.CallOption) (*PeerList_Reply, error)
// OutOfStoreReceive parses a payload received outside a synchronized store
OutOfStoreReceive(ctx context.Context, in *OutOfStoreReceive_Request, opts ...grpc.CallOption) (*OutOfStoreReceive_Reply, error)
// OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
OutOfStoreSeal(ctx context.Context, in *OutOfStoreSeal_Request, opts ...grpc.CallOption) (*OutOfStoreSeal_Reply, error)
// RefreshContactRequest try to refresh the contact request for the given contact
RefreshContactRequest(ctx context.Context, in *RefreshContactRequest_Request, opts ...grpc.CallOption) (*RefreshContactRequest_Reply, error)
}
type protocolServiceClient struct {
cc grpc.ClientConnInterface
}
func NewProtocolServiceClient(cc grpc.ClientConnInterface) ProtocolServiceClient {
return &protocolServiceClient{cc}
}
func (c *protocolServiceClient) ServiceExportData(ctx context.Context, in *ServiceExportData_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ServiceExportData_Reply], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[0], ProtocolService_ServiceExportData_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[ServiceExportData_Request, ServiceExportData_Reply]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_ServiceExportDataClient = grpc.ServerStreamingClient[ServiceExportData_Reply]
func (c *protocolServiceClient) ServiceGetConfiguration(ctx context.Context, in *ServiceGetConfiguration_Request, opts ...grpc.CallOption) (*ServiceGetConfiguration_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ServiceGetConfiguration_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ServiceGetConfiguration_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestReference(ctx context.Context, in *ContactRequestReference_Request, opts ...grpc.CallOption) (*ContactRequestReference_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestReference_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestReference_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestDisable(ctx context.Context, in *ContactRequestDisable_Request, opts ...grpc.CallOption) (*ContactRequestDisable_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestDisable_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestDisable_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestEnable(ctx context.Context, in *ContactRequestEnable_Request, opts ...grpc.CallOption) (*ContactRequestEnable_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestEnable_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestEnable_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestResetReference(ctx context.Context, in *ContactRequestResetReference_Request, opts ...grpc.CallOption) (*ContactRequestResetReference_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestResetReference_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestResetReference_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestSend(ctx context.Context, in *ContactRequestSend_Request, opts ...grpc.CallOption) (*ContactRequestSend_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestSend_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestSend_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestAccept(ctx context.Context, in *ContactRequestAccept_Request, opts ...grpc.CallOption) (*ContactRequestAccept_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestAccept_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestAccept_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactRequestDiscard(ctx context.Context, in *ContactRequestDiscard_Request, opts ...grpc.CallOption) (*ContactRequestDiscard_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactRequestDiscard_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactRequestDiscard_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ShareContact(ctx context.Context, in *ShareContact_Request, opts ...grpc.CallOption) (*ShareContact_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ShareContact_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ShareContact_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) DecodeContact(ctx context.Context, in *DecodeContact_Request, opts ...grpc.CallOption) (*DecodeContact_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DecodeContact_Reply)
err := c.cc.Invoke(ctx, ProtocolService_DecodeContact_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactBlock(ctx context.Context, in *ContactBlock_Request, opts ...grpc.CallOption) (*ContactBlock_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactBlock_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactBlock_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactUnblock(ctx context.Context, in *ContactUnblock_Request, opts ...grpc.CallOption) (*ContactUnblock_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactUnblock_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactUnblock_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ContactAliasKeySend(ctx context.Context, in *ContactAliasKeySend_Request, opts ...grpc.CallOption) (*ContactAliasKeySend_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ContactAliasKeySend_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ContactAliasKeySend_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupCreate(ctx context.Context, in *MultiMemberGroupCreate_Request, opts ...grpc.CallOption) (*MultiMemberGroupCreate_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupCreate_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupCreate_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupJoin(ctx context.Context, in *MultiMemberGroupJoin_Request, opts ...grpc.CallOption) (*MultiMemberGroupJoin_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupJoin_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupJoin_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupLeave(ctx context.Context, in *MultiMemberGroupLeave_Request, opts ...grpc.CallOption) (*MultiMemberGroupLeave_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupLeave_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupLeave_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupAliasResolverDisclose(ctx context.Context, in *MultiMemberGroupAliasResolverDisclose_Request, opts ...grpc.CallOption) (*MultiMemberGroupAliasResolverDisclose_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupAliasResolverDisclose_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupAliasResolverDisclose_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupAdminRoleGrant(ctx context.Context, in *MultiMemberGroupAdminRoleGrant_Request, opts ...grpc.CallOption) (*MultiMemberGroupAdminRoleGrant_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupAdminRoleGrant_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupAdminRoleGrant_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) MultiMemberGroupInvitationCreate(ctx context.Context, in *MultiMemberGroupInvitationCreate_Request, opts ...grpc.CallOption) (*MultiMemberGroupInvitationCreate_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MultiMemberGroupInvitationCreate_Reply)
err := c.cc.Invoke(ctx, ProtocolService_MultiMemberGroupInvitationCreate_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) AppMetadataSend(ctx context.Context, in *AppMetadataSend_Request, opts ...grpc.CallOption) (*AppMetadataSend_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AppMetadataSend_Reply)
err := c.cc.Invoke(ctx, ProtocolService_AppMetadataSend_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) AppMessageSend(ctx context.Context, in *AppMessageSend_Request, opts ...grpc.CallOption) (*AppMessageSend_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AppMessageSend_Reply)
err := c.cc.Invoke(ctx, ProtocolService_AppMessageSend_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) GroupMetadataList(ctx context.Context, in *GroupMetadataList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupMetadataEvent], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[1], ProtocolService_GroupMetadataList_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[GroupMetadataList_Request, GroupMetadataEvent]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupMetadataListClient = grpc.ServerStreamingClient[GroupMetadataEvent]
func (c *protocolServiceClient) GroupMessageList(ctx context.Context, in *GroupMessageList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupMessageEvent], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[2], ProtocolService_GroupMessageList_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[GroupMessageList_Request, GroupMessageEvent]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupMessageListClient = grpc.ServerStreamingClient[GroupMessageEvent]
func (c *protocolServiceClient) GroupInfo(ctx context.Context, in *GroupInfo_Request, opts ...grpc.CallOption) (*GroupInfo_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GroupInfo_Reply)
err := c.cc.Invoke(ctx, ProtocolService_GroupInfo_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) ActivateGroup(ctx context.Context, in *ActivateGroup_Request, opts ...grpc.CallOption) (*ActivateGroup_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ActivateGroup_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ActivateGroup_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) DeactivateGroup(ctx context.Context, in *DeactivateGroup_Request, opts ...grpc.CallOption) (*DeactivateGroup_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DeactivateGroup_Reply)
err := c.cc.Invoke(ctx, ProtocolService_DeactivateGroup_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) GroupDeviceStatus(ctx context.Context, in *GroupDeviceStatus_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GroupDeviceStatus_Reply], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[3], ProtocolService_GroupDeviceStatus_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[GroupDeviceStatus_Request, GroupDeviceStatus_Reply]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupDeviceStatusClient = grpc.ServerStreamingClient[GroupDeviceStatus_Reply]
func (c *protocolServiceClient) DebugListGroups(ctx context.Context, in *DebugListGroups_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DebugListGroups_Reply], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[4], ProtocolService_DebugListGroups_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[DebugListGroups_Request, DebugListGroups_Reply]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_DebugListGroupsClient = grpc.ServerStreamingClient[DebugListGroups_Reply]
func (c *protocolServiceClient) DebugInspectGroupStore(ctx context.Context, in *DebugInspectGroupStore_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DebugInspectGroupStore_Reply], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[5], ProtocolService_DebugInspectGroupStore_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[DebugInspectGroupStore_Request, DebugInspectGroupStore_Reply]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_DebugInspectGroupStoreClient = grpc.ServerStreamingClient[DebugInspectGroupStore_Reply]
func (c *protocolServiceClient) DebugGroup(ctx context.Context, in *DebugGroup_Request, opts ...grpc.CallOption) (*DebugGroup_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DebugGroup_Reply)
err := c.cc.Invoke(ctx, ProtocolService_DebugGroup_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) SystemInfo(ctx context.Context, in *SystemInfo_Request, opts ...grpc.CallOption) (*SystemInfo_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SystemInfo_Reply)
err := c.cc.Invoke(ctx, ProtocolService_SystemInfo_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) CredentialVerificationServiceInitFlow(ctx context.Context, in *CredentialVerificationServiceInitFlow_Request, opts ...grpc.CallOption) (*CredentialVerificationServiceInitFlow_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CredentialVerificationServiceInitFlow_Reply)
err := c.cc.Invoke(ctx, ProtocolService_CredentialVerificationServiceInitFlow_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) CredentialVerificationServiceCompleteFlow(ctx context.Context, in *CredentialVerificationServiceCompleteFlow_Request, opts ...grpc.CallOption) (*CredentialVerificationServiceCompleteFlow_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CredentialVerificationServiceCompleteFlow_Reply)
err := c.cc.Invoke(ctx, ProtocolService_CredentialVerificationServiceCompleteFlow_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) VerifiedCredentialsList(ctx context.Context, in *VerifiedCredentialsList_Request, opts ...grpc.CallOption) (grpc.ServerStreamingClient[VerifiedCredentialsList_Reply], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &ProtocolService_ServiceDesc.Streams[6], ProtocolService_VerifiedCredentialsList_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[VerifiedCredentialsList_Request, VerifiedCredentialsList_Reply]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_VerifiedCredentialsListClient = grpc.ServerStreamingClient[VerifiedCredentialsList_Reply]
func (c *protocolServiceClient) ReplicationServiceRegisterGroup(ctx context.Context, in *ReplicationServiceRegisterGroup_Request, opts ...grpc.CallOption) (*ReplicationServiceRegisterGroup_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReplicationServiceRegisterGroup_Reply)
err := c.cc.Invoke(ctx, ProtocolService_ReplicationServiceRegisterGroup_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) PeerList(ctx context.Context, in *PeerList_Request, opts ...grpc.CallOption) (*PeerList_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(PeerList_Reply)
err := c.cc.Invoke(ctx, ProtocolService_PeerList_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) OutOfStoreReceive(ctx context.Context, in *OutOfStoreReceive_Request, opts ...grpc.CallOption) (*OutOfStoreReceive_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OutOfStoreReceive_Reply)
err := c.cc.Invoke(ctx, ProtocolService_OutOfStoreReceive_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) OutOfStoreSeal(ctx context.Context, in *OutOfStoreSeal_Request, opts ...grpc.CallOption) (*OutOfStoreSeal_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OutOfStoreSeal_Reply)
err := c.cc.Invoke(ctx, ProtocolService_OutOfStoreSeal_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *protocolServiceClient) RefreshContactRequest(ctx context.Context, in *RefreshContactRequest_Request, opts ...grpc.CallOption) (*RefreshContactRequest_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RefreshContactRequest_Reply)
err := c.cc.Invoke(ctx, ProtocolService_RefreshContactRequest_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ProtocolServiceServer is the server API for ProtocolService service.
// All implementations must embed UnimplementedProtocolServiceServer
// for forward compatibility.
//
// ProtocolService is the top-level API to manage the Wesh protocol service.
// Each active Wesh protocol service is considered as a Wesh device and is associated with a Wesh user.
type ProtocolServiceServer interface {
// ServiceExportData exports the current data of the protocol service
ServiceExportData(*ServiceExportData_Request, grpc.ServerStreamingServer[ServiceExportData_Reply]) error
// ServiceGetConfiguration gets the current configuration of the protocol service
ServiceGetConfiguration(context.Context, *ServiceGetConfiguration_Request) (*ServiceGetConfiguration_Reply, error)
// ContactRequestReference retrieves the information required to create a reference (ie. included in a shareable link) to the current account
ContactRequestReference(context.Context, *ContactRequestReference_Request) (*ContactRequestReference_Reply, error)
// ContactRequestDisable disables incoming contact requests
ContactRequestDisable(context.Context, *ContactRequestDisable_Request) (*ContactRequestDisable_Reply, error)
// ContactRequestEnable enables incoming contact requests
ContactRequestEnable(context.Context, *ContactRequestEnable_Request) (*ContactRequestEnable_Reply, error)
// ContactRequestResetReference changes the contact request reference
ContactRequestResetReference(context.Context, *ContactRequestResetReference_Request) (*ContactRequestResetReference_Reply, error)
// ContactRequestSend attempt to send a contact request
ContactRequestSend(context.Context, *ContactRequestSend_Request) (*ContactRequestSend_Reply, error)
// ContactRequestAccept accepts a contact request
ContactRequestAccept(context.Context, *ContactRequestAccept_Request) (*ContactRequestAccept_Reply, error)
// ContactRequestDiscard ignores a contact request, without informing the other user
ContactRequestDiscard(context.Context, *ContactRequestDiscard_Request) (*ContactRequestDiscard_Reply, error)
// ShareContact uses ContactRequestReference to get the contact information for the current account and
// returns the Protobuf encoding of a shareable contact which you can further encode and share. If needed, this
// will reset the contact request reference and enable contact requests. To decode the result, see DecodeContact.
ShareContact(context.Context, *ShareContact_Request) (*ShareContact_Reply, error)
// DecodeContact decodes the Protobuf encoding of a shareable contact which was returned by ShareContact.
DecodeContact(context.Context, *DecodeContact_Request) (*DecodeContact_Reply, error)
// ContactBlock blocks a contact from sending requests
ContactBlock(context.Context, *ContactBlock_Request) (*ContactBlock_Reply, error)
// ContactUnblock unblocks a contact from sending requests
ContactUnblock(context.Context, *ContactUnblock_Request) (*ContactUnblock_Reply, error)
// ContactAliasKeySend send an alias key to a contact, the contact will be able to assert that your account is being present on a multi-member group
ContactAliasKeySend(context.Context, *ContactAliasKeySend_Request) (*ContactAliasKeySend_Reply, error)
// MultiMemberGroupCreate creates a new multi-member group
MultiMemberGroupCreate(context.Context, *MultiMemberGroupCreate_Request) (*MultiMemberGroupCreate_Reply, error)
// MultiMemberGroupJoin joins a multi-member group
MultiMemberGroupJoin(context.Context, *MultiMemberGroupJoin_Request) (*MultiMemberGroupJoin_Reply, error)
// MultiMemberGroupLeave leaves a multi-member group
MultiMemberGroupLeave(context.Context, *MultiMemberGroupLeave_Request) (*MultiMemberGroupLeave_Reply, error)
// MultiMemberGroupAliasResolverDisclose discloses your alias resolver key
MultiMemberGroupAliasResolverDisclose(context.Context, *MultiMemberGroupAliasResolverDisclose_Request) (*MultiMemberGroupAliasResolverDisclose_Reply, error)
// MultiMemberGroupAdminRoleGrant grants an admin role to a group member
MultiMemberGroupAdminRoleGrant(context.Context, *MultiMemberGroupAdminRoleGrant_Request) (*MultiMemberGroupAdminRoleGrant_Reply, error)
// MultiMemberGroupInvitationCreate creates an invitation to a multi-member group
MultiMemberGroupInvitationCreate(context.Context, *MultiMemberGroupInvitationCreate_Request) (*MultiMemberGroupInvitationCreate_Reply, error)
// AppMetadataSend adds an app event to the metadata store, the message is encrypted using a symmetric key and readable by future group members
AppMetadataSend(context.Context, *AppMetadataSend_Request) (*AppMetadataSend_Reply, error)
// AppMessageSend adds an app event to the message store, the message is encrypted using a derived key and readable by current group members
AppMessageSend(context.Context, *AppMessageSend_Request) (*AppMessageSend_Reply, error)
// GroupMetadataList replays previous and subscribes to new metadata events from the group
GroupMetadataList(*GroupMetadataList_Request, grpc.ServerStreamingServer[GroupMetadataEvent]) error
// GroupMessageList replays previous and subscribes to new message events from the group
GroupMessageList(*GroupMessageList_Request, grpc.ServerStreamingServer[GroupMessageEvent]) error
// GroupInfo retrieves information about a group
GroupInfo(context.Context, *GroupInfo_Request) (*GroupInfo_Reply, error)
// ActivateGroup explicitly opens a group
ActivateGroup(context.Context, *ActivateGroup_Request) (*ActivateGroup_Reply, error)
// DeactivateGroup closes a group
DeactivateGroup(context.Context, *DeactivateGroup_Request) (*DeactivateGroup_Reply, error)
// GroupDeviceStatus monitor device status
GroupDeviceStatus(*GroupDeviceStatus_Request, grpc.ServerStreamingServer[GroupDeviceStatus_Reply]) error
DebugListGroups(*DebugListGroups_Request, grpc.ServerStreamingServer[DebugListGroups_Reply]) error
DebugInspectGroupStore(*DebugInspectGroupStore_Request, grpc.ServerStreamingServer[DebugInspectGroupStore_Reply]) error
DebugGroup(context.Context, *DebugGroup_Request) (*DebugGroup_Reply, error)
SystemInfo(context.Context, *SystemInfo_Request) (*SystemInfo_Reply, error)
// CredentialVerificationServiceInitFlow Initialize a credential verification flow
CredentialVerificationServiceInitFlow(context.Context, *CredentialVerificationServiceInitFlow_Request) (*CredentialVerificationServiceInitFlow_Reply, error)
// CredentialVerificationServiceCompleteFlow Completes a credential verification flow
CredentialVerificationServiceCompleteFlow(context.Context, *CredentialVerificationServiceCompleteFlow_Request) (*CredentialVerificationServiceCompleteFlow_Reply, error)
// VerifiedCredentialsList Retrieves the list of verified credentials
VerifiedCredentialsList(*VerifiedCredentialsList_Request, grpc.ServerStreamingServer[VerifiedCredentialsList_Reply]) error
// ReplicationServiceRegisterGroup Asks a replication service to distribute a group contents
ReplicationServiceRegisterGroup(context.Context, *ReplicationServiceRegisterGroup_Request) (*ReplicationServiceRegisterGroup_Reply, error)
// PeerList returns a list of P2P peers
PeerList(context.Context, *PeerList_Request) (*PeerList_Reply, error)
// OutOfStoreReceive parses a payload received outside a synchronized store
OutOfStoreReceive(context.Context, *OutOfStoreReceive_Request) (*OutOfStoreReceive_Reply, error)
// OutOfStoreSeal creates a payload of a message present in store to be sent outside a synchronized store
OutOfStoreSeal(context.Context, *OutOfStoreSeal_Request) (*OutOfStoreSeal_Reply, error)
// RefreshContactRequest try to refresh the contact request for the given contact
RefreshContactRequest(context.Context, *RefreshContactRequest_Request) (*RefreshContactRequest_Reply, error)
mustEmbedUnimplementedProtocolServiceServer()
}
// UnimplementedProtocolServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedProtocolServiceServer struct{}
func (UnimplementedProtocolServiceServer) ServiceExportData(*ServiceExportData_Request, grpc.ServerStreamingServer[ServiceExportData_Reply]) error {
return status.Errorf(codes.Unimplemented, "method ServiceExportData not implemented")
}
func (UnimplementedProtocolServiceServer) ServiceGetConfiguration(context.Context, *ServiceGetConfiguration_Request) (*ServiceGetConfiguration_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ServiceGetConfiguration not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestReference(context.Context, *ContactRequestReference_Request) (*ContactRequestReference_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestReference not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestDisable(context.Context, *ContactRequestDisable_Request) (*ContactRequestDisable_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestDisable not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestEnable(context.Context, *ContactRequestEnable_Request) (*ContactRequestEnable_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestEnable not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestResetReference(context.Context, *ContactRequestResetReference_Request) (*ContactRequestResetReference_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestResetReference not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestSend(context.Context, *ContactRequestSend_Request) (*ContactRequestSend_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestSend not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestAccept(context.Context, *ContactRequestAccept_Request) (*ContactRequestAccept_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestAccept not implemented")
}
func (UnimplementedProtocolServiceServer) ContactRequestDiscard(context.Context, *ContactRequestDiscard_Request) (*ContactRequestDiscard_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactRequestDiscard not implemented")
}
func (UnimplementedProtocolServiceServer) ShareContact(context.Context, *ShareContact_Request) (*ShareContact_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ShareContact not implemented")
}
func (UnimplementedProtocolServiceServer) DecodeContact(context.Context, *DecodeContact_Request) (*DecodeContact_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method DecodeContact not implemented")
}
func (UnimplementedProtocolServiceServer) ContactBlock(context.Context, *ContactBlock_Request) (*ContactBlock_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactBlock not implemented")
}
func (UnimplementedProtocolServiceServer) ContactUnblock(context.Context, *ContactUnblock_Request) (*ContactUnblock_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactUnblock not implemented")
}
func (UnimplementedProtocolServiceServer) ContactAliasKeySend(context.Context, *ContactAliasKeySend_Request) (*ContactAliasKeySend_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContactAliasKeySend not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupCreate(context.Context, *MultiMemberGroupCreate_Request) (*MultiMemberGroupCreate_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupCreate not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupJoin(context.Context, *MultiMemberGroupJoin_Request) (*MultiMemberGroupJoin_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupJoin not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupLeave(context.Context, *MultiMemberGroupLeave_Request) (*MultiMemberGroupLeave_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupLeave not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupAliasResolverDisclose(context.Context, *MultiMemberGroupAliasResolverDisclose_Request) (*MultiMemberGroupAliasResolverDisclose_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupAliasResolverDisclose not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupAdminRoleGrant(context.Context, *MultiMemberGroupAdminRoleGrant_Request) (*MultiMemberGroupAdminRoleGrant_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupAdminRoleGrant not implemented")
}
func (UnimplementedProtocolServiceServer) MultiMemberGroupInvitationCreate(context.Context, *MultiMemberGroupInvitationCreate_Request) (*MultiMemberGroupInvitationCreate_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method MultiMemberGroupInvitationCreate not implemented")
}
func (UnimplementedProtocolServiceServer) AppMetadataSend(context.Context, *AppMetadataSend_Request) (*AppMetadataSend_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method AppMetadataSend not implemented")
}
func (UnimplementedProtocolServiceServer) AppMessageSend(context.Context, *AppMessageSend_Request) (*AppMessageSend_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method AppMessageSend not implemented")
}
func (UnimplementedProtocolServiceServer) GroupMetadataList(*GroupMetadataList_Request, grpc.ServerStreamingServer[GroupMetadataEvent]) error {
return status.Errorf(codes.Unimplemented, "method GroupMetadataList not implemented")
}
func (UnimplementedProtocolServiceServer) GroupMessageList(*GroupMessageList_Request, grpc.ServerStreamingServer[GroupMessageEvent]) error {
return status.Errorf(codes.Unimplemented, "method GroupMessageList not implemented")
}
func (UnimplementedProtocolServiceServer) GroupInfo(context.Context, *GroupInfo_Request) (*GroupInfo_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GroupInfo not implemented")
}
func (UnimplementedProtocolServiceServer) ActivateGroup(context.Context, *ActivateGroup_Request) (*ActivateGroup_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ActivateGroup not implemented")
}
func (UnimplementedProtocolServiceServer) DeactivateGroup(context.Context, *DeactivateGroup_Request) (*DeactivateGroup_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeactivateGroup not implemented")
}
func (UnimplementedProtocolServiceServer) GroupDeviceStatus(*GroupDeviceStatus_Request, grpc.ServerStreamingServer[GroupDeviceStatus_Reply]) error {
return status.Errorf(codes.Unimplemented, "method GroupDeviceStatus not implemented")
}
func (UnimplementedProtocolServiceServer) DebugListGroups(*DebugListGroups_Request, grpc.ServerStreamingServer[DebugListGroups_Reply]) error {
return status.Errorf(codes.Unimplemented, "method DebugListGroups not implemented")
}
func (UnimplementedProtocolServiceServer) DebugInspectGroupStore(*DebugInspectGroupStore_Request, grpc.ServerStreamingServer[DebugInspectGroupStore_Reply]) error {
return status.Errorf(codes.Unimplemented, "method DebugInspectGroupStore not implemented")
}
func (UnimplementedProtocolServiceServer) DebugGroup(context.Context, *DebugGroup_Request) (*DebugGroup_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method DebugGroup not implemented")
}
func (UnimplementedProtocolServiceServer) SystemInfo(context.Context, *SystemInfo_Request) (*SystemInfo_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SystemInfo not implemented")
}
func (UnimplementedProtocolServiceServer) CredentialVerificationServiceInitFlow(context.Context, *CredentialVerificationServiceInitFlow_Request) (*CredentialVerificationServiceInitFlow_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method CredentialVerificationServiceInitFlow not implemented")
}
func (UnimplementedProtocolServiceServer) CredentialVerificationServiceCompleteFlow(context.Context, *CredentialVerificationServiceCompleteFlow_Request) (*CredentialVerificationServiceCompleteFlow_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method CredentialVerificationServiceCompleteFlow not implemented")
}
func (UnimplementedProtocolServiceServer) VerifiedCredentialsList(*VerifiedCredentialsList_Request, grpc.ServerStreamingServer[VerifiedCredentialsList_Reply]) error {
return status.Errorf(codes.Unimplemented, "method VerifiedCredentialsList not implemented")
}
func (UnimplementedProtocolServiceServer) ReplicationServiceRegisterGroup(context.Context, *ReplicationServiceRegisterGroup_Request) (*ReplicationServiceRegisterGroup_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReplicationServiceRegisterGroup not implemented")
}
func (UnimplementedProtocolServiceServer) PeerList(context.Context, *PeerList_Request) (*PeerList_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method PeerList not implemented")
}
func (UnimplementedProtocolServiceServer) OutOfStoreReceive(context.Context, *OutOfStoreReceive_Request) (*OutOfStoreReceive_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method OutOfStoreReceive not implemented")
}
func (UnimplementedProtocolServiceServer) OutOfStoreSeal(context.Context, *OutOfStoreSeal_Request) (*OutOfStoreSeal_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method OutOfStoreSeal not implemented")
}
func (UnimplementedProtocolServiceServer) RefreshContactRequest(context.Context, *RefreshContactRequest_Request) (*RefreshContactRequest_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method RefreshContactRequest not implemented")
}
func (UnimplementedProtocolServiceServer) mustEmbedUnimplementedProtocolServiceServer() {}
func (UnimplementedProtocolServiceServer) testEmbeddedByValue() {}
// UnsafeProtocolServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ProtocolServiceServer will
// result in compilation errors.
type UnsafeProtocolServiceServer interface {
mustEmbedUnimplementedProtocolServiceServer()
}
func RegisterProtocolServiceServer(s grpc.ServiceRegistrar, srv ProtocolServiceServer) {
// If the following call pancis, it indicates UnimplementedProtocolServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&ProtocolService_ServiceDesc, srv)
}
func _ProtocolService_ServiceExportData_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(ServiceExportData_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).ServiceExportData(m, &grpc.GenericServerStream[ServiceExportData_Request, ServiceExportData_Reply]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_ServiceExportDataServer = grpc.ServerStreamingServer[ServiceExportData_Reply]
func _ProtocolService_ServiceGetConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ServiceGetConfiguration_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ServiceGetConfiguration(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ServiceGetConfiguration_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ServiceGetConfiguration(ctx, req.(*ServiceGetConfiguration_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestReference_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestReference_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestReference(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestReference_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestReference(ctx, req.(*ContactRequestReference_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestDisable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestDisable_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestDisable(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestDisable_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestDisable(ctx, req.(*ContactRequestDisable_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestEnable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestEnable_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestEnable(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestEnable_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestEnable(ctx, req.(*ContactRequestEnable_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestResetReference_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestResetReference_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestResetReference(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestResetReference_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestResetReference(ctx, req.(*ContactRequestResetReference_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestSend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestSend_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestSend(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestSend_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestSend(ctx, req.(*ContactRequestSend_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestAccept_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestAccept_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestAccept(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestAccept_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestAccept(ctx, req.(*ContactRequestAccept_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactRequestDiscard_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactRequestDiscard_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactRequestDiscard(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactRequestDiscard_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactRequestDiscard(ctx, req.(*ContactRequestDiscard_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ShareContact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ShareContact_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ShareContact(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ShareContact_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ShareContact(ctx, req.(*ShareContact_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_DecodeContact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DecodeContact_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).DecodeContact(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_DecodeContact_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).DecodeContact(ctx, req.(*DecodeContact_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactBlock_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactBlock(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactBlock_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactBlock(ctx, req.(*ContactBlock_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactUnblock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactUnblock_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactUnblock(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactUnblock_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactUnblock(ctx, req.(*ContactUnblock_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ContactAliasKeySend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContactAliasKeySend_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ContactAliasKeySend(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ContactAliasKeySend_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ContactAliasKeySend(ctx, req.(*ContactAliasKeySend_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupCreate_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupCreate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupCreate_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupCreate(ctx, req.(*MultiMemberGroupCreate_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupJoin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupJoin_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupJoin(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupJoin_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupJoin(ctx, req.(*MultiMemberGroupJoin_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupLeave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupLeave_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupLeave(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupLeave_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupLeave(ctx, req.(*MultiMemberGroupLeave_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupAliasResolverDisclose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupAliasResolverDisclose_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupAliasResolverDisclose(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupAliasResolverDisclose_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupAliasResolverDisclose(ctx, req.(*MultiMemberGroupAliasResolverDisclose_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupAdminRoleGrant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupAdminRoleGrant_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupAdminRoleGrant(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupAdminRoleGrant_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupAdminRoleGrant(ctx, req.(*MultiMemberGroupAdminRoleGrant_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_MultiMemberGroupInvitationCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MultiMemberGroupInvitationCreate_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).MultiMemberGroupInvitationCreate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_MultiMemberGroupInvitationCreate_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).MultiMemberGroupInvitationCreate(ctx, req.(*MultiMemberGroupInvitationCreate_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_AppMetadataSend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AppMetadataSend_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).AppMetadataSend(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_AppMetadataSend_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).AppMetadataSend(ctx, req.(*AppMetadataSend_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_AppMessageSend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AppMessageSend_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).AppMessageSend(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_AppMessageSend_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).AppMessageSend(ctx, req.(*AppMessageSend_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_GroupMetadataList_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GroupMetadataList_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).GroupMetadataList(m, &grpc.GenericServerStream[GroupMetadataList_Request, GroupMetadataEvent]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupMetadataListServer = grpc.ServerStreamingServer[GroupMetadataEvent]
func _ProtocolService_GroupMessageList_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GroupMessageList_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).GroupMessageList(m, &grpc.GenericServerStream[GroupMessageList_Request, GroupMessageEvent]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupMessageListServer = grpc.ServerStreamingServer[GroupMessageEvent]
func _ProtocolService_GroupInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GroupInfo_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).GroupInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_GroupInfo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).GroupInfo(ctx, req.(*GroupInfo_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_ActivateGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ActivateGroup_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ActivateGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ActivateGroup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ActivateGroup(ctx, req.(*ActivateGroup_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_DeactivateGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeactivateGroup_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).DeactivateGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_DeactivateGroup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).DeactivateGroup(ctx, req.(*DeactivateGroup_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_GroupDeviceStatus_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GroupDeviceStatus_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).GroupDeviceStatus(m, &grpc.GenericServerStream[GroupDeviceStatus_Request, GroupDeviceStatus_Reply]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_GroupDeviceStatusServer = grpc.ServerStreamingServer[GroupDeviceStatus_Reply]
func _ProtocolService_DebugListGroups_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(DebugListGroups_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).DebugListGroups(m, &grpc.GenericServerStream[DebugListGroups_Request, DebugListGroups_Reply]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_DebugListGroupsServer = grpc.ServerStreamingServer[DebugListGroups_Reply]
func _ProtocolService_DebugInspectGroupStore_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(DebugInspectGroupStore_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).DebugInspectGroupStore(m, &grpc.GenericServerStream[DebugInspectGroupStore_Request, DebugInspectGroupStore_Reply]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_DebugInspectGroupStoreServer = grpc.ServerStreamingServer[DebugInspectGroupStore_Reply]
func _ProtocolService_DebugGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DebugGroup_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).DebugGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_DebugGroup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).DebugGroup(ctx, req.(*DebugGroup_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_SystemInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SystemInfo_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).SystemInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_SystemInfo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).SystemInfo(ctx, req.(*SystemInfo_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_CredentialVerificationServiceInitFlow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CredentialVerificationServiceInitFlow_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).CredentialVerificationServiceInitFlow(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_CredentialVerificationServiceInitFlow_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).CredentialVerificationServiceInitFlow(ctx, req.(*CredentialVerificationServiceInitFlow_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_CredentialVerificationServiceCompleteFlow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CredentialVerificationServiceCompleteFlow_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).CredentialVerificationServiceCompleteFlow(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_CredentialVerificationServiceCompleteFlow_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).CredentialVerificationServiceCompleteFlow(ctx, req.(*CredentialVerificationServiceCompleteFlow_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_VerifiedCredentialsList_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(VerifiedCredentialsList_Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ProtocolServiceServer).VerifiedCredentialsList(m, &grpc.GenericServerStream[VerifiedCredentialsList_Request, VerifiedCredentialsList_Reply]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type ProtocolService_VerifiedCredentialsListServer = grpc.ServerStreamingServer[VerifiedCredentialsList_Reply]
func _ProtocolService_ReplicationServiceRegisterGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReplicationServiceRegisterGroup_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).ReplicationServiceRegisterGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_ReplicationServiceRegisterGroup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).ReplicationServiceRegisterGroup(ctx, req.(*ReplicationServiceRegisterGroup_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_PeerList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PeerList_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).PeerList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_PeerList_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).PeerList(ctx, req.(*PeerList_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_OutOfStoreReceive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(OutOfStoreReceive_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).OutOfStoreReceive(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_OutOfStoreReceive_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).OutOfStoreReceive(ctx, req.(*OutOfStoreReceive_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_OutOfStoreSeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(OutOfStoreSeal_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).OutOfStoreSeal(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_OutOfStoreSeal_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).OutOfStoreSeal(ctx, req.(*OutOfStoreSeal_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ProtocolService_RefreshContactRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RefreshContactRequest_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProtocolServiceServer).RefreshContactRequest(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ProtocolService_RefreshContactRequest_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProtocolServiceServer).RefreshContactRequest(ctx, req.(*RefreshContactRequest_Request))
}
return interceptor(ctx, in, info, handler)
}
// ProtocolService_ServiceDesc is the grpc.ServiceDesc for ProtocolService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ProtocolService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "weshnet.protocol.v1.ProtocolService",
HandlerType: (*ProtocolServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ServiceGetConfiguration",
Handler: _ProtocolService_ServiceGetConfiguration_Handler,
},
{
MethodName: "ContactRequestReference",
Handler: _ProtocolService_ContactRequestReference_Handler,
},
{
MethodName: "ContactRequestDisable",
Handler: _ProtocolService_ContactRequestDisable_Handler,
},
{
MethodName: "ContactRequestEnable",
Handler: _ProtocolService_ContactRequestEnable_Handler,
},
{
MethodName: "ContactRequestResetReference",
Handler: _ProtocolService_ContactRequestResetReference_Handler,
},
{
MethodName: "ContactRequestSend",
Handler: _ProtocolService_ContactRequestSend_Handler,
},
{
MethodName: "ContactRequestAccept",
Handler: _ProtocolService_ContactRequestAccept_Handler,
},
{
MethodName: "ContactRequestDiscard",
Handler: _ProtocolService_ContactRequestDiscard_Handler,
},
{
MethodName: "ShareContact",
Handler: _ProtocolService_ShareContact_Handler,
},
{
MethodName: "DecodeContact",
Handler: _ProtocolService_DecodeContact_Handler,
},
{
MethodName: "ContactBlock",
Handler: _ProtocolService_ContactBlock_Handler,
},
{
MethodName: "ContactUnblock",
Handler: _ProtocolService_ContactUnblock_Handler,
},
{
MethodName: "ContactAliasKeySend",
Handler: _ProtocolService_ContactAliasKeySend_Handler,
},
{
MethodName: "MultiMemberGroupCreate",
Handler: _ProtocolService_MultiMemberGroupCreate_Handler,
},
{
MethodName: "MultiMemberGroupJoin",
Handler: _ProtocolService_MultiMemberGroupJoin_Handler,
},
{
MethodName: "MultiMemberGroupLeave",
Handler: _ProtocolService_MultiMemberGroupLeave_Handler,
},
{
MethodName: "MultiMemberGroupAliasResolverDisclose",
Handler: _ProtocolService_MultiMemberGroupAliasResolverDisclose_Handler,
},
{
MethodName: "MultiMemberGroupAdminRoleGrant",
Handler: _ProtocolService_MultiMemberGroupAdminRoleGrant_Handler,
},
{
MethodName: "MultiMemberGroupInvitationCreate",
Handler: _ProtocolService_MultiMemberGroupInvitationCreate_Handler,
},
{
MethodName: "AppMetadataSend",
Handler: _ProtocolService_AppMetadataSend_Handler,
},
{
MethodName: "AppMessageSend",
Handler: _ProtocolService_AppMessageSend_Handler,
},
{
MethodName: "GroupInfo",
Handler: _ProtocolService_GroupInfo_Handler,
},
{
MethodName: "ActivateGroup",
Handler: _ProtocolService_ActivateGroup_Handler,
},
{
MethodName: "DeactivateGroup",
Handler: _ProtocolService_DeactivateGroup_Handler,
},
{
MethodName: "DebugGroup",
Handler: _ProtocolService_DebugGroup_Handler,
},
{
MethodName: "SystemInfo",
Handler: _ProtocolService_SystemInfo_Handler,
},
{
MethodName: "CredentialVerificationServiceInitFlow",
Handler: _ProtocolService_CredentialVerificationServiceInitFlow_Handler,
},
{
MethodName: "CredentialVerificationServiceCompleteFlow",
Handler: _ProtocolService_CredentialVerificationServiceCompleteFlow_Handler,
},
{
MethodName: "ReplicationServiceRegisterGroup",
Handler: _ProtocolService_ReplicationServiceRegisterGroup_Handler,
},
{
MethodName: "PeerList",
Handler: _ProtocolService_PeerList_Handler,
},
{
MethodName: "OutOfStoreReceive",
Handler: _ProtocolService_OutOfStoreReceive_Handler,
},
{
MethodName: "OutOfStoreSeal",
Handler: _ProtocolService_OutOfStoreSeal_Handler,
},
{
MethodName: "RefreshContactRequest",
Handler: _ProtocolService_RefreshContactRequest_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "ServiceExportData",
Handler: _ProtocolService_ServiceExportData_Handler,
ServerStreams: true,
},
{
StreamName: "GroupMetadataList",
Handler: _ProtocolService_GroupMetadataList_Handler,
ServerStreams: true,
},
{
StreamName: "GroupMessageList",
Handler: _ProtocolService_GroupMessageList_Handler,
ServerStreams: true,
},
{
StreamName: "GroupDeviceStatus",
Handler: _ProtocolService_GroupDeviceStatus_Handler,
ServerStreams: true,
},
{
StreamName: "DebugListGroups",
Handler: _ProtocolService_DebugListGroups_Handler,
ServerStreams: true,
},
{
StreamName: "DebugInspectGroupStore",
Handler: _ProtocolService_DebugInspectGroupStore_Handler,
ServerStreams: true,
},
{
StreamName: "VerifiedCredentialsList",
Handler: _ProtocolService_VerifiedCredentialsList_Handler,
ServerStreams: true,
},
},
Metadata: "protocoltypes.proto",
}
================================================
FILE: pkg/protoio/full.go
================================================
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package protoio
import (
"io"
"google.golang.org/protobuf/proto"
)
func NewFullWriter(w io.Writer) WriteCloser {
return &fullWriter{w, nil}
}
type fullWriter struct {
w io.Writer
buffer []byte
}
func (writer *fullWriter) WriteMsg(msg proto.Message) (err error) {
var data []byte
if m, ok := msg.(marshaler); ok {
n, ok := getSize(m)
if !ok {
_, err = proto.Marshal(msg)
if err != nil {
return err
}
}
if n >= len(writer.buffer) {
writer.buffer = make([]byte, n)
}
_, err = m.MarshalTo(writer.buffer)
if err != nil {
return err
}
data = writer.buffer[:n]
} else {
data, err = proto.Marshal(msg)
if err != nil {
return err
}
}
_, err = writer.w.Write(data)
return err
}
func (writer *fullWriter) Close() error {
if closer, ok := writer.w.(io.Closer); ok {
return closer.Close()
}
return nil
}
type fullReader struct {
r io.Reader
buf []byte
}
func NewFullReader(r io.Reader, maxSize int) ReadCloser {
return &fullReader{r, make([]byte, maxSize)}
}
func (reader *fullReader) ReadMsg(msg proto.Message) error {
length, err := reader.r.Read(reader.buf)
if err != nil {
return err
}
return proto.Unmarshal(reader.buf[:length], msg)
}
func (reader *fullReader) Close() error {
if closer, ok := reader.r.(io.Closer); ok {
return closer.Close()
}
return nil
}
================================================
FILE: pkg/protoio/io.go
================================================
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package protoio
import (
"io"
"google.golang.org/protobuf/proto"
)
type Writer interface {
WriteMsg(proto.Message) error
}
type WriteCloser interface {
Writer
io.Closer
}
type Reader interface {
ReadMsg(msg proto.Message) error
}
type ReadCloser interface {
Reader
io.Closer
}
type marshaler interface {
MarshalTo(data []byte) (n int, err error)
}
func getSize(v any) (int, bool) {
if sz, ok := v.(interface {
Size() (n int)
}); ok {
return sz.Size(), true
} else if sz, ok := v.(interface {
ProtoSize() (n int)
}); ok {
return sz.ProtoSize(), true
}
return 0, false
}
================================================
FILE: pkg/protoio/uint32.go
================================================
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package protoio
import (
"encoding/binary"
"io"
"google.golang.org/protobuf/proto"
)
const uint32BinaryLen = 4
func NewUint32DelimitedWriter(w io.Writer, byteOrder binary.ByteOrder) WriteCloser {
return &uint32Writer{w, byteOrder, nil, make([]byte, uint32BinaryLen)}
}
func NewSizeUint32DelimitedWriter(w io.Writer, byteOrder binary.ByteOrder, size int) WriteCloser {
return &uint32Writer{w, byteOrder, make([]byte, size), make([]byte, uint32BinaryLen)}
}
type uint32Writer struct {
w io.Writer
byteOrder binary.ByteOrder
buffer []byte
lenBuf []byte
}
func (writer *uint32Writer) writeFallback(msg proto.Message) error {
data, err := proto.Marshal(msg)
if err != nil {
return err
}
length := uint32(len(data))
writer.byteOrder.PutUint32(writer.lenBuf, length)
if _, err = writer.w.Write(writer.lenBuf); err != nil {
return err
}
_, err = writer.w.Write(data)
return err
}
func (writer *uint32Writer) WriteMsg(msg proto.Message) error {
m, ok := msg.(marshaler)
if !ok {
return writer.writeFallback(msg)
}
n, ok := getSize(m)
if !ok {
return writer.writeFallback(msg)
}
size := n + uint32BinaryLen
if size > len(writer.buffer) {
writer.buffer = make([]byte, size)
}
writer.byteOrder.PutUint32(writer.buffer, uint32(n))
if _, err := m.MarshalTo(writer.buffer[uint32BinaryLen:]); err != nil {
return err
}
_, err := writer.w.Write(writer.buffer[:size])
return err
}
func (writer *uint32Writer) Close() error {
if closer, ok := writer.w.(io.Closer); ok {
return closer.Close()
}
return nil
}
type uint32Reader struct {
r io.Reader
byteOrder binary.ByteOrder
lenBuf []byte
buf []byte
maxSize int
}
func NewUint32DelimitedReader(r io.Reader, byteOrder binary.ByteOrder, maxSize int) ReadCloser {
return &uint32Reader{r, byteOrder, make([]byte, 4), nil, maxSize}
}
func (reader *uint32Reader) ReadMsg(msg proto.Message) error {
if _, err := io.ReadFull(reader.r, reader.lenBuf); err != nil {
return err
}
length32 := reader.byteOrder.Uint32(reader.lenBuf)
length := int(length32)
if length < 0 || length > reader.maxSize {
return io.ErrShortBuffer
}
if length > len(reader.buf) {
reader.buf = make([]byte, length)
}
_, err := io.ReadFull(reader.r, reader.buf[:length])
if err != nil {
return err
}
return proto.Unmarshal(reader.buf[:length], msg)
}
func (reader *uint32Reader) Close() error {
if closer, ok := reader.r.(io.Closer); ok {
return closer.Close()
}
return nil
}
================================================
FILE: pkg/protoio/varint.go
================================================
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package protoio
import (
"bufio"
"encoding/binary"
"io"
"google.golang.org/protobuf/proto"
)
func NewDelimitedWriter(w io.Writer) WriteCloser {
return &varintWriter{w, make([]byte, binary.MaxVarintLen64), nil}
}
type varintWriter struct {
w io.Writer
lenBuf []byte
buffer []byte
}
func (writer *varintWriter) WriteMsg(msg proto.Message) (err error) {
var data []byte
if m, ok := msg.(marshaler); ok {
n, ok := getSize(m)
if ok {
if n+binary.MaxVarintLen64 >= len(writer.buffer) {
writer.buffer = make([]byte, n+binary.MaxVarintLen64)
}
lenOff := binary.PutUvarint(writer.buffer, uint64(n))
_, err = m.MarshalTo(writer.buffer[lenOff:])
if err != nil {
return err
}
_, err = writer.w.Write(writer.buffer[:lenOff+n])
return err
}
}
// fallback
data, err = proto.Marshal(msg)
if err != nil {
return err
}
length := uint64(len(data))
n := binary.PutUvarint(writer.lenBuf, length)
_, err = writer.w.Write(writer.lenBuf[:n])
if err != nil {
return err
}
_, err = writer.w.Write(data)
return err
}
func (writer *varintWriter) Close() error {
if closer, ok := writer.w.(io.Closer); ok {
return closer.Close()
}
return nil
}
func NewDelimitedReader(r io.Reader, maxSize int) ReadCloser {
var closer io.Closer
if c, ok := r.(io.Closer); ok {
closer = c
}
return &varintReader{bufio.NewReader(r), nil, maxSize, closer}
}
type varintReader struct {
r *bufio.Reader
buf []byte
maxSize int
closer io.Closer
}
func (reader *varintReader) ReadMsg(msg proto.Message) error {
length64, err := binary.ReadUvarint(reader.r)
if err != nil {
return err
}
length := int(length64)
if length < 0 || length > reader.maxSize {
return io.ErrShortBuffer
}
if len(reader.buf) < length {
reader.buf = make([]byte, length)
}
buf := reader.buf[:length]
if _, err := io.ReadFull(reader.r, buf); err != nil {
return err
}
return proto.Unmarshal(buf, msg)
}
func (reader *varintReader) Close() error {
if reader.closer != nil {
return reader.closer.Close()
}
return nil
}
================================================
FILE: pkg/proximitytransport/addr.go
================================================
package proximitytransport
import "net"
// Addr is a net.Addr.
var _ net.Addr = &Addr{}
// Addr represents a network end point address.
type Addr struct {
Address string
transport *proximityTransport
}
// Network returns the address's network name.
func (b *Addr) Network() string { return b.transport.driver.ProtocolName() }
// String return's the string form of the address.
func (b *Addr) String() string { return b.Address }
================================================
FILE: pkg/proximitytransport/conn.go
================================================
package proximitytransport
import (
"context"
"fmt"
"io"
"net"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
tpt "github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/pkg/errors"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
// Conn is a manet.Conn.
var _ manet.Conn = &Conn{}
// Conn is the equivalent of a net.Conn object. It is the
// result of calling the Dial or Listen functions in this
// package, with associated local and remote Multiaddrs.
type Conn struct {
readIn *io.PipeWriter
readOut *io.PipeReader
localMa ma.Multiaddr
remoteMa ma.Multiaddr
ready bool
sync.Mutex
cache *RingBufferMap
mp *mplex
ctx context.Context
cancel func()
transport *proximityTransport
}
// newConn returns an inbound or outbound tpt.CapableConn upgraded from a Conn.
func newConn(ctx context.Context, t *proximityTransport, remoteMa ma.Multiaddr, remotePID peer.ID, netdir network.Direction,
) (tpt.CapableConn, error) {
t.logger.Debug("newConn()", logutil.PrivateString("remoteMa", remoteMa.String()), zap.Bool("inbound", netdir == network.DirInbound))
if netdir == network.DirUnknown {
return nil, fmt.Errorf("invalid network direction")
}
connScope, err := t.swarm.ResourceManager().OpenConnection(netdir, false, remoteMa)
if err != nil {
return nil, fmt.Errorf("resource manager blocked connection : %w", err)
}
// Creates a manet.Conn
pr, pw := io.Pipe()
connCtx, cancel := context.WithCancel(t.listener.ctx)
maconn := &Conn{
readIn: pw,
readOut: pr,
localMa: t.listener.localMa,
remoteMa: remoteMa,
ready: false,
cache: NewRingBufferMap(t.logger, 128),
mp: newMplex(connCtx, t.logger),
ctx: connCtx,
cancel: cancel,
transport: t,
}
// Stores the conn in connMap, will be deleted during conn.Close()
t.connMapMutex.Lock()
t.connMap[maconn.RemoteAddr().String()] = maconn
t.connMapMutex.Unlock()
// Configure mplex and run it
maconn.mp.addInputCache(t.cache)
maconn.mp.addInputCache(maconn.cache)
maconn.mp.setOutput(pw)
// Returns an upgraded CapableConn (muxed, addr filtered, secured, etc...)
return t.upgrader.Upgrade(ctx, t, maconn, netdir, remotePID, connScope)
}
// Read reads data from the connection.
// Timeout handled by the native driver.
func (c *Conn) Read(payload []byte) (n int, err error) {
c.transport.logger.Debug("Conn.Read", logutil.PrivateString("remoteAddr", c.RemoteAddr().String()))
if c.ctx.Err() != nil {
c.transport.logger.Error("Conn.Read failed: conn already closed")
return 0, fmt.Errorf("error: Conn.Read failed: conn already closed")
}
n, err = c.readOut.Read(payload)
if err != nil {
err = errors.Wrap(err, "error: Conn.Read failed: native read failed")
c.transport.logger.Error("Conn.Read", zap.Error(err))
} else {
c.transport.logger.Debug("Conn.Read successful")
}
return n, err
}
// Write writes data to the connection.
// Timeout handled by the native driver.
func (c *Conn) Write(payload []byte) (n int, err error) {
c.transport.logger.Debug("Conn.Write", logutil.PrivateString("remoteAddr", c.RemoteAddr().String()), logutil.PrivateBinary("payload", payload))
if c.ctx.Err() != nil {
return 0, fmt.Errorf("error: Conn.Write failed: conn already closed")
}
// Set connection as ready and flush cached payloads
if !c.isReady() {
c.Lock()
if !c.ready {
c.ready = true
}
c.Unlock()
go c.mp.run(c.RemoteAddr().String())
}
// Write to the peer's device using native driver.
if !c.transport.driver.SendToPeer(c.RemoteAddr().String(), payload) {
c.transport.logger.Error("Conn.Write failed")
return 0, fmt.Errorf("error: Conn.Write failed: native write failed")
}
c.transport.logger.Debug("Conn.Write successful")
return len(payload), nil
}
// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
func (c *Conn) Close() error {
c.transport.logger.Debug("Conn.Close()")
c.cancel()
// Closes read pipe
c.readIn.Close()
c.readOut.Close()
// Removes conn from connmgr's connMap
c.transport.connMapMutex.Lock()
delete(c.transport.connMap, c.RemoteAddr().String())
c.transport.connMapMutex.Unlock()
// Disconnect the driver
c.transport.driver.CloseConnWithPeer(c.RemoteAddr().String())
return nil
}
// isReady tells if libp2p is ready to accept input connections
func (c *Conn) isReady() bool {
c.Lock()
defer c.Unlock()
return c.ready
}
// LocalAddr returns the local network address.
func (c *Conn) LocalAddr() net.Addr {
lAddr, _ := c.LocalMultiaddr().ValueForProtocol(c.transport.driver.ProtocolCode())
return &Addr{
Address: lAddr,
transport: c.transport,
}
}
// RemoteAddr returns the remote network address.
func (c *Conn) RemoteAddr() net.Addr {
rAddr, _ := c.RemoteMultiaddr().ValueForProtocol(c.transport.driver.ProtocolCode())
return &Addr{
Address: rAddr,
transport: c.transport,
}
}
// LocalMultiaddr returns the local Multiaddr associated
// with this connection.
func (c *Conn) LocalMultiaddr() ma.Multiaddr { return c.localMa }
// RemoteMultiaddr returns the remote Multiaddr associated
// with this connection.
func (c *Conn) RemoteMultiaddr() ma.Multiaddr { return c.remoteMa }
// Noop deadline methods, handled by the native driver.
// SetDeadline does nothing
func (c *Conn) SetDeadline(time.Time) error { return nil }
// SetReadDeadline does nothing
func (c *Conn) SetReadDeadline(time.Time) error { return nil }
// SetWriteDeadline does nothing
func (c *Conn) SetWriteDeadline(time.Time) error { return nil }
================================================
FILE: pkg/proximitytransport/example_test.go
================================================
package proximitytransport_test
================================================
FILE: pkg/proximitytransport/listener.go
================================================
package proximitytransport
import (
"context"
"errors"
"net"
network "github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
tpt "github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr"
)
// Listener is a tpt.Listener.
var _ tpt.Listener = &Listener{}
// Listener is an interface closely resembling the net.Listener interface. The
// only real difference is that Accept() returns Conn's of the type in this
// package, and also exposes a Multiaddr method as opposed to a regular Addr
// method.
type Listener struct {
transport *proximityTransport
localMa ma.Multiaddr
inboundConnReq chan connReq // Chan used to accept inbound conn.
ctx context.Context
cancel func()
}
// connReq holds data necessary for inbound conn creation.
type connReq struct {
remoteMa ma.Multiaddr
remotePID peer.ID
}
// newListener starts the native driver then returns a new Listener.
func newListener(ctx context.Context, localMa ma.Multiaddr, t *proximityTransport) *Listener {
t.logger.Debug("newListener()")
ctx, cancel := context.WithCancel(ctx)
listener := &Listener{
transport: t,
localMa: localMa,
inboundConnReq: make(chan connReq),
ctx: ctx,
cancel: cancel,
}
// Starts the native driver.
// If it failed, don't return a error because no other transport
// on the libp2p node will be created.
t.driver.Start(t.swarm.LocalPeer().String())
return listener
}
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn.
func (l *Listener) Accept() (tpt.CapableConn, error) {
for {
select {
case req := <-l.inboundConnReq:
l.transport.logger.Debug("Listener.Accept(): incoming connection")
conn, err := newConn(l.ctx, l.transport, req.remoteMa, req.remotePID, network.DirInbound)
// If the newConn failed for some reason, Accept won't return an error
// because otherwise it will close the listener
if err == nil {
return conn, nil
}
case <-l.ctx.Done():
return nil, errors.New("error: Listener.Accept failed: listener already closed")
}
}
}
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
func (l *Listener) Close() error {
l.transport.logger.Debug("Listener.Close()")
l.cancel()
// Stops the native driver.
l.transport.driver.Stop()
// Removes listener so transport can instantiate a new one later.
l.transport.lock.Lock()
l.transport.listener = nil
l.transport.lock.Unlock()
// Unregister this transport
TransportMapMutex.Lock()
delete(TransportMap, l.transport.driver.ProtocolName())
TransportMapMutex.Unlock()
return nil
}
// Multiaddr returns the listener's (local) Multiaddr.
func (l *Listener) Multiaddr() ma.Multiaddr { return l.localMa }
// Addr returns the net.Listener's network address.
func (l *Listener) Addr() net.Addr {
lAddr, _ := l.localMa.ValueForProtocol(l.transport.driver.ProtocolCode())
return &Addr{
Address: lAddr,
}
}
================================================
FILE: pkg/proximitytransport/mplex.go
================================================
package proximitytransport
/*
The mplex struct as NOT relationship with libp2p mplex package!!!
This mplex struct is a multiplexer taken multiple inputs for one output.
You must initialize mplex by setting input and output before running it.
There are two types of input:
1) RingBufferMap
2) builtin chan []byte
There is only one type of output: *io.PipeWriter
When you start mplex, its flushed buffers first in the order you set them,
and read on its chan []byte.
*/
import (
"context"
"io"
"sync"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
type mplex struct {
inputCaches []*RingBufferMap
inputLock sync.Mutex
input chan []byte
output *io.PipeWriter
ctx context.Context
logger *zap.Logger
}
func newMplex(ctx context.Context, logger *zap.Logger) *mplex {
logger = logger.Named("mplex")
return &mplex{
input: make(chan []byte),
ctx: ctx,
logger: logger,
}
}
func (m *mplex) setOutput(o *io.PipeWriter) {
m.output = o
}
func (m *mplex) addInputCache(c *RingBufferMap) {
m.inputLock.Lock()
m.inputCaches = append(m.inputCaches, c)
m.inputLock.Unlock()
}
func (m *mplex) write(s []byte) {
m.logger.Debug("write", logutil.PrivateBinary("payload", s))
_, err := m.output.Write(s)
if err != nil {
m.logger.Error("write: write pipe error", zap.Error(err))
} else {
m.logger.Debug("write: successful write pipe")
}
}
// run flushes caches and read input channel
func (m *mplex) run(peerID string) {
m.logger.Debug("run: started")
// flush caches
m.inputLock.Lock()
for _, cache := range m.inputCaches {
m.logger.Debug("run: flushing one cache")
payloads := cache.Flush(peerID)
for payload := range payloads {
m.write(payload)
}
}
m.inputLock.Unlock()
// read input
m.logger.Debug("run: reading input channel")
for {
select {
case payload := <-m.input:
m.write(payload)
case <-m.ctx.Done():
return
}
}
}
================================================
FILE: pkg/proximitytransport/proximitydriver.go
================================================
package proximitytransport
type ProximityDriver interface {
// Start the native driver
Start(localPID string)
// Stop the native driver
Stop()
// Check if the native driver is connected to the remote peer
DialPeer(remotePID string) bool
// Send data to the remote peer
SendToPeer(remotePID string, payload []byte) bool
// Close the connection with the remote peer
CloseConnWithPeer(remotePID string)
// Return the multiaddress protocol code
ProtocolCode() int
// Return the multiaddress protocol name
ProtocolName() string
// Return the default multiaddress
DefaultAddr() string
}
type NoopProximityDriver struct {
protocolCode int
protocolName string
defaultAddr string
}
func NewNoopProximityDriver(protocolCode int, protocolName, defaultAddr string) *NoopProximityDriver {
return &NoopProximityDriver{
protocolCode: protocolCode,
protocolName: protocolName,
defaultAddr: defaultAddr,
}
}
func (d *NoopProximityDriver) Start(_ string) {}
func (d *NoopProximityDriver) Stop() {}
func (d *NoopProximityDriver) DialPeer(_ string) bool { return false }
func (d *NoopProximityDriver) SendToPeer(_ string, _ []byte) bool { return false }
func (d *NoopProximityDriver) CloseConnWithPeer(_ string) {}
func (d *NoopProximityDriver) ProtocolCode() int { return d.protocolCode }
func (d *NoopProximityDriver) ProtocolName() string { return d.protocolName }
func (d *NoopProximityDriver) DefaultAddr() string { return d.defaultAddr }
================================================
FILE: pkg/proximitytransport/ringBuffer_map.go
================================================
package proximitytransport
import (
"container/ring"
"sync"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
// RingBufferMap is a map of string:ringBuffer(aka circular buffer)
// The key is a peerID.
type RingBufferMap struct {
sync.Mutex
cache map[string]*ringBuffer
bufferSize int
logger *zap.Logger
}
type ringBuffer struct {
sync.Mutex
buffer *ring.Ring
}
// NewRingBufferMap returns a new connMgr struct
// The size argument is the number of packets to save in cache.
func NewRingBufferMap(logger *zap.Logger, size int) *RingBufferMap {
logger = logger.Named("RingBuffer")
return &RingBufferMap{
cache: make(map[string]*ringBuffer),
bufferSize: size,
logger: logger,
}
}
// Add adds the payload into a circular cache
func (rbm *RingBufferMap) Add(peerID string, payload []byte) {
rbm.logger.Debug("Add", logutil.PrivateString("peerID", peerID), logutil.PrivateBinary("payload", payload))
var rBuffer *ringBuffer
rbm.Lock()
rBuffer, ok := rbm.cache[peerID]
rbm.Unlock()
if !ok {
rBuffer = &ringBuffer{
buffer: ring.New(rbm.bufferSize),
}
}
rBuffer.Lock()
rBuffer.buffer.Value = payload
rBuffer.buffer = rBuffer.buffer.Next()
rBuffer.Unlock()
rbm.Lock()
rbm.cache[peerID] = rBuffer
rbm.Unlock()
}
// Flush puts the cache contents into a chan and clears it
func (rbm *RingBufferMap) Flush(peerID string) <-chan []byte {
rbm.logger.Debug("flushCache", logutil.PrivateString("peerID", peerID))
c := make(chan []byte)
go func() {
rbm.Lock()
rBuffer, ok := rbm.cache[peerID]
rbm.Unlock()
if ok {
rBuffer.Lock()
for i := 0; i < rbm.bufferSize; i++ {
payload, ok := rBuffer.buffer.Value.([]byte)
if !ok {
rBuffer.buffer = rBuffer.buffer.Next()
continue
}
rbm.logger.Debug("flushCache", logutil.PrivateBinary("payload", payload))
c <- payload
rBuffer.buffer.Value = nil
rBuffer.buffer = rBuffer.buffer.Next()
}
rBuffer.Unlock()
rbm.Lock()
delete(rbm.cache, peerID)
rbm.Unlock()
}
close(c)
}()
return c
}
// Delete cache entry
func (rbm *RingBufferMap) Delete(peerID string) {
rbm.logger.Debug("RingBufferMap: Delete called", logutil.PrivateString("peerID", peerID))
rbm.Lock()
_, ok := rbm.cache[peerID]
if ok {
rbm.logger.Debug("RingBufferMap: Delete: cache found", logutil.PrivateString("peerID", peerID))
delete(rbm.cache, peerID)
}
rbm.Unlock()
}
================================================
FILE: pkg/proximitytransport/transport.go
================================================
package proximitytransport
import (
"context"
"fmt"
"sync"
network "github.com/libp2p/go-libp2p/core/network"
peer "github.com/libp2p/go-libp2p/core/peer"
pstore "github.com/libp2p/go-libp2p/core/peerstore"
tpt "github.com/libp2p/go-libp2p/core/transport"
"github.com/libp2p/go-libp2p/p2p/net/swarm"
ma "github.com/multiformats/go-multiaddr"
mafmt "github.com/multiformats/go-multiaddr-fmt"
"github.com/pkg/errors"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
// The ProximityTransport is a libp2p transport that initializes NativeDriver.
// It allows connecting to nearby peers
// proximityTransport is a tpt.transport.
var _ tpt.Transport = &proximityTransport{}
// proximityTransport is a ProximityTransport.
var _ ProximityTransport = &proximityTransport{}
// TransportMap prevents instantiating multiple Transport
var TransportMap = make(map[string]*proximityTransport)
// TransportMapMutex is the mutex for the TransportMap var
var TransportMapMutex sync.RWMutex
// Define log level for driver loggers
const (
Verbose = iota
Debug
Info
Warn
Error
)
type ProximityTransport interface {
HandleFoundPeer(remotePID string) bool
HandleLostPeer(remotePID string)
ReceiveFromPeer(remotePID string, payload []byte)
Log(level int, message string)
}
type proximityTransport struct {
swarm *swarm.Swarm
upgrader tpt.Upgrader
connMap map[string]*Conn
connMapMutex sync.RWMutex
cache *RingBufferMap
lock sync.RWMutex
listener *Listener
driver ProximityDriver
logger *zap.Logger
ctx context.Context
}
func NewTransport(ctx context.Context, l *zap.Logger, driver ProximityDriver) func(swarm *swarm.Swarm, u tpt.Upgrader) (*proximityTransport, error) {
if l == nil {
l = zap.NewNop()
}
l = l.Named("ProximityTransport")
if driver == nil {
l.Error("error: NewTransport: driver is nil")
driver = &NoopProximityDriver{}
}
l.Debug("remi: transport.go: new Transport")
return func(swarm *swarm.Swarm, u tpt.Upgrader) (*proximityTransport, error) {
l.Debug("NewTransport called", zap.String("driver", driver.ProtocolName()))
transport := &proximityTransport{
swarm: swarm,
upgrader: u,
connMap: make(map[string]*Conn),
cache: NewRingBufferMap(l, 128),
driver: driver,
logger: l,
ctx: ctx,
}
return transport, nil
}
}
// Dial dials the peer at the remote address.
// With proximity connections (e.g. MC, BLE, Nearby) you can only dial a device that is already connected with the native driver.
func (t *proximityTransport) Dial(ctx context.Context, remoteMa ma.Multiaddr, remotePID peer.ID) (tpt.CapableConn, error) {
// proximityTransport needs to have a running listener in order to dial other peer
// because native driver is initialized during listener creation.
t.lock.RLock()
defer t.lock.RUnlock()
if t.listener == nil {
return nil, errors.New("error: proximityTransport.Dial: no active listener")
}
// remoteAddr is supposed to be equal to remotePID since with proximity transports:
// multiaddr = //
remoteAddr, err := remoteMa.ValueForProtocol(t.driver.ProtocolCode())
if err != nil || remoteAddr != remotePID.String() {
return nil, errors.Wrap(err, "error: proximityTransport.Dial: wrong multiaddr")
}
// Check if native driver is already connected to peer's device.
// With proximity connections you can't really dial, only auto-connect with peer nearby.
if !t.driver.DialPeer(remoteAddr) {
return nil, errors.New("error: proximityTransport.Dial: peer not connected through the native driver")
}
// Can't have two connections on the same multiaddr
t.connMapMutex.RLock()
_, ok := t.connMap[remoteAddr]
t.connMapMutex.RUnlock()
if ok {
return nil, errors.New("error: proximityTransport.Dial: already connected to this address")
}
// Returns an outbound conn.
return newConn(ctx, t, remoteMa, remotePID, network.DirOutbound)
}
// CanDial returns true if this transport believes it can dial the given
// multiaddr.
func (t *proximityTransport) CanDial(remoteMa ma.Multiaddr) bool {
// multiaddr validation checker
return mafmt.Base(t.driver.ProtocolCode()).Matches(remoteMa)
}
// Listen listens on the given multiaddr.
// Proximity connections can't listen on more than one listener.
func (t *proximityTransport) Listen(localMa ma.Multiaddr) (tpt.Listener, error) {
// localAddr is supposed to be equal to the localPID
// or to DefaultAddr since multiaddr == //
localPID := t.swarm.LocalPeer().String()
localAddr, err := localMa.ValueForProtocol(t.driver.ProtocolCode())
if err != nil || (localMa.String() != t.driver.DefaultAddr() && localAddr != localPID) {
return nil, errors.Wrap(err, "error: proximityTransport.Listen: wrong multiaddr")
}
// Replaces default bind by local host peerID
if localMa.String() == t.driver.DefaultAddr() {
localMa, err = ma.NewMultiaddr(fmt.Sprintf("/%s/%s", t.driver.ProtocolName(), localPID))
if err != nil { // Should never append.
panic(err)
}
}
// If the a listener already exists for this driver, returns an error.
TransportMapMutex.RLock()
_, ok := TransportMap[t.driver.ProtocolName()]
TransportMapMutex.RUnlock()
t.lock.RLock()
if ok || t.listener != nil {
t.lock.RUnlock()
return nil, errors.New("error: proximityTransport.Listen: one listener maximum")
}
t.lock.RUnlock()
// Register this transport
TransportMapMutex.Lock()
TransportMap[t.driver.ProtocolName()] = t
TransportMapMutex.Unlock()
t.lock.Lock()
defer t.lock.Unlock()
t.listener = newListener(t.ctx, localMa, t)
return t.listener, err
}
// ReceiveFromPeer is called by native driver when peer's device sent data.
// If the connection is not found, data is added in the transport cache level.
// If the connection is not activated yet, data is added in the connection cache level.
// Cache are circular buffer, avoiding RAM memory attack.
func (t *proximityTransport) ReceiveFromPeer(remotePID string, payload []byte) {
t.logger.Debug("ReceiveFromPeer()", zap.String("remotePID", remotePID), logutil.PrivateBinary("payload", payload))
// copy value from driver
data := make([]byte, len(payload))
copy(data, payload)
t.connMapMutex.RLock()
c, ok := t.connMap[remotePID]
t.connMapMutex.RUnlock()
if ok {
// Put payload in the Conn cache if libp2p connection is not ready
if !c.isReady() {
c.Lock()
if !c.ready {
t.logger.Info("ReceiveFromPeer: connection is not ready to accept incoming packets, add it to cache")
c.cache.Add(remotePID, data)
c.Unlock()
return
}
c.Unlock()
}
// Write the payload into pipe
c.mp.input <- data
} else {
t.logger.Info("ReceiveFromPeer: no Conn found, put payload in cache")
t.cache.Add(remotePID, data)
}
}
// HandleFoundPeer is called by the native driver when a new peer is found.
// Adds the peer in the PeerStore and initiates a connection with it
func (t *proximityTransport) HandleFoundPeer(sRemotePID string) bool {
t.logger.Debug("HandleFoundPeer", zap.String("remotePID", sRemotePID))
remotePID, err := peer.Decode(sRemotePID)
if err != nil {
t.logger.Error("HandleFoundPeer: wrong remote peerID")
return false
}
remoteMa, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%s", t.driver.ProtocolName(), sRemotePID))
if err != nil {
// Should never occur
panic(err)
}
// Checks if a listener is currently running.
t.lock.RLock()
if t.listener == nil || t.listener.ctx.Err() != nil {
t.lock.RUnlock()
t.logger.Error("HandleFoundPeer: listener not running")
return false
}
// Get snapshot of listener
listener := t.listener
// unblock here to prevent blocking other APIs of Listener or Transport
t.lock.RUnlock()
// Adds peer to peerstore.
t.swarm.Peerstore().AddAddr(remotePID, remoteMa,
pstore.TempAddrTTL)
// Delete previous cache if it exists
t.cache.Delete(sRemotePID)
// Peer with lexicographical smallest peerID inits libp2p connection.
if listener.Addr().String() < sRemotePID {
t.logger.Debug("HandleFoundPeer: outgoing libp2p connection")
// Async connect so HandleFoundPeer can return and unlock the native driver.
// Needed to read and write during the connect handshake.
go func() {
// Need to use listener than t.listener here to not have to check valid value of t.listener
err := t.connect(listener.ctx, peer.AddrInfo{
ID: remotePID,
Addrs: []ma.Multiaddr{remoteMa},
})
if err != nil {
t.logger.Error("HandleFoundPeer: async connect error", zap.Error(err))
t.swarm.Peerstore().SetAddr(remotePID, remoteMa, -1)
t.driver.CloseConnWithPeer(sRemotePID)
}
}()
return true
}
t.logger.Debug("HandleFoundPeer: incoming libp2p connection")
// Peer with lexicographical biggest peerID accepts incoming connection.
// FIXME : consider to push this code in go routine to prevent blocking native driver
select {
case listener.inboundConnReq <- connReq{
remoteMa: remoteMa,
remotePID: remotePID,
}:
return true
case <-listener.ctx.Done():
return false
}
}
// Adapted from https://github.com/libp2p/go-libp2p/blob/v0.38.1/p2p/host/basic/basic_host.go#L795
func (t *proximityTransport) connect(ctx context.Context, pi peer.AddrInfo) error {
// absorb addresses into peerstore
t.swarm.Peerstore().AddAddrs(pi.ID, pi.Addrs, pstore.TempAddrTTL)
forceDirect, _ := network.GetForceDirectDial(ctx)
canUseLimitedConn, _ := network.GetAllowLimitedConn(ctx)
if !forceDirect {
connectedness := t.swarm.Connectedness(pi.ID)
if connectedness == network.Connected || (canUseLimitedConn && connectedness == network.Limited) {
return nil
}
}
_, err := t.swarm.DialPeer(ctx, pi.ID)
return err
}
// HandleLostPeer is called by the native driver when the connection with the peer is lost.
// Closes connections with the peer.
func (t *proximityTransport) HandleLostPeer(sRemotePID string) {
t.logger.Debug("HandleLostPeer", logutil.PrivateString("remotePID", sRemotePID))
remotePID, err := peer.Decode(sRemotePID)
if err != nil {
t.logger.Error("HandleLostPeer: wrong remote peerID")
return
}
remoteMa, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%s", t.driver.ProtocolName(), sRemotePID))
if err != nil {
// Should never occur
panic(err)
}
// Remove peer's address to peerstore.
t.swarm.Peerstore().SetAddr(remotePID, remoteMa, -1)
// Close the peer connection
conns := t.swarm.ConnsToPeer(remotePID)
for _, conn := range conns {
if conn.RemoteMultiaddr().Equal(remoteMa) {
conn.Close()
}
}
}
func (t *proximityTransport) Log(level int, message string) {
switch level {
case Verbose, Debug:
t.logger.Debug(message)
case Info:
t.logger.Info(message)
case Warn:
t.logger.Warn(message)
case Error:
t.logger.Error(message)
}
}
// Proxy returns true if this transport proxies.
func (t *proximityTransport) Proxy() bool {
return false
}
// Protocols returns the set of protocols handled by this transport.
func (t *proximityTransport) Protocols() []int {
return []int{t.driver.ProtocolCode()}
}
func (t *proximityTransport) String() string {
return t.driver.ProtocolName()
}
================================================
FILE: pkg/rendezvous/emitterio_sync_client.go
================================================
package rendezvous
import (
"context"
"encoding/json"
"fmt"
"io"
"sync"
"time"
emitter "github.com/berty/emitter-go/v2"
rendezvous "github.com/berty/go-libp2p-rendezvous"
pb "github.com/berty/go-libp2p-rendezvous/pb"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
)
type SyncClient interface {
rendezvous.RendezvousSyncClient
io.Closer
}
type registrationMessage struct {
registration *rendezvous.Registration
psDetails *EmitterPubSubSubscriptionDetails
}
type emitterClient struct {
logger *zap.Logger
client *emitter.Client
ctx context.Context
cancel context.CancelFunc
usage int
}
type emitterClientManager struct {
ctx context.Context
cancel context.CancelFunc
clients map[string]*emitterClient
outChans map[string][]chan *rendezvous.Registration
inChan chan *registrationMessage
mu sync.Mutex
logger *zap.Logger
}
func (e *emitterClientManager) Close() (err error) {
e.mu.Lock()
for _, client := range e.clients {
client.Close()
}
e.cancel()
e.mu.Unlock()
return nil
}
func (e *emitterClient) Close() (err error) {
e.cancel()
e.client.Disconnect(time.Millisecond * 100)
return nil
}
func (e *emitterClient) subscribeToServerUpdates(inChan chan *registrationMessage, psDetails *EmitterPubSubSubscriptionDetails) (err error) {
e.logger.Debug("subscribing", zap.String("chan", psDetails.ChannelName))
return e.client.Subscribe(psDetails.ReadKey, psDetails.ChannelName, func(_ *emitter.Client, message emitter.Message) {
reg := &pb.RegistrationRecord{}
e.logger.Debug("receiving a message", zap.Any("topic", message.Topic()))
err := proto.Unmarshal(message.Payload(), reg)
if err != nil {
e.logger.Error("unable to unmarshall ", zap.Error(err))
return
}
pid, err := peer.Decode(reg.Id)
if err != nil {
e.logger.Error("unable to decode ", zap.Error(err))
return
}
maddrs := make([]multiaddr.Multiaddr, len(reg.Addrs))
for i, addrBytes := range reg.Addrs {
maddrs[i], err = multiaddr.NewMultiaddrBytes(addrBytes)
if err != nil {
e.logger.Error("unable to decode multiaddr bytes", zap.Error(err))
return
}
}
var fields []string
for _, maddr := range maddrs {
fields = append(fields, maddr.String())
}
e.logger.Debug("receiving a peer", zap.String("topic", reg.Ns), zap.String("peer", pid.String()), zap.Strings("maddrs", fields))
inChan <- ®istrationMessage{
registration: &rendezvous.Registration{
Peer: peer.AddrInfo{
ID: pid,
Addrs: maddrs,
},
Ns: reg.Ns,
Ttl: int(reg.Ttl),
},
psDetails: psDetails,
}
}, emitter.WithLast(1))
}
func (e *emitterClientManager) getClient(psDetails *EmitterPubSubSubscriptionDetails) (client *emitterClient, err error) {
var ok bool
if client, ok = e.clients[psDetails.ServerAddr]; ok {
return
}
noophandler := func(*emitter.Client, emitter.Message) {}
cl, err := emitter.Connect(psDetails.ServerAddr, noophandler, emitter.WithLogger(e.logger.Named("cl")))
if err != nil {
return
}
wrapCtx, cancel := context.WithCancel(context.Background())
client = &emitterClient{
logger: e.logger.Named("cl"),
ctx: wrapCtx,
cancel: cancel,
client: cl,
}
e.clients[psDetails.ServerAddr] = client
return
}
func (e *emitterClientManager) Subscribe(ctx context.Context, psDetailsStr string) (<-chan *rendezvous.Registration, error) {
psDetails := &EmitterPubSubSubscriptionDetails{}
err := json.Unmarshal([]byte(psDetailsStr), psDetails)
if err != nil {
return nil, fmt.Errorf("unable to decode json: %w", err)
}
e.mu.Lock()
defer e.mu.Unlock()
client, err := e.getClient(psDetails)
if err != nil {
return nil, fmt.Errorf("unable to : %w", err)
}
sliceName := makeOutChanName(psDetails.ServerAddr, psDetails.ChannelName)
if _, ok := e.outChans[sliceName]; !ok {
e.logger.Debug("subscribing",
zap.String("channel", psDetails.ChannelName), zap.String("target", psDetails.ServerAddr))
if err := client.subscribeToServerUpdates(e.inChan, psDetails); err != nil {
return nil, fmt.Errorf("unable to subscribe to broker's channel: %w", err)
}
}
ch := make(chan *rendezvous.Registration)
e.outChans[sliceName] = append(e.outChans[sliceName], ch)
client.usage++
go func() {
select {
case <-ctx.Done():
case <-client.ctx.Done():
}
e.unsubscribe(psDetails, ch)
close(ch)
}()
return ch, nil
}
type EmitterClientOptions struct {
Logger *zap.Logger
}
func NewEmitterClient(opts *EmitterClientOptions) SyncClient {
if opts == nil {
opts = &EmitterClientOptions{}
}
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
ctx, cancel := context.WithCancel(context.Background())
manager := &emitterClientManager{
ctx: ctx,
cancel: cancel,
clients: map[string]*emitterClient{},
logger: opts.Logger.Named("emitter"),
outChans: map[string][]chan *rendezvous.Registration{},
inChan: make(chan *registrationMessage),
}
manager.logger.Debug("starting rdvp emitter client")
go func() {
for {
select {
case <-ctx.Done():
close(manager.inChan)
return
case registration := <-manager.inChan:
outChanName := makeOutChanName(registration.psDetails.ServerAddr, registration.psDetails.ChannelName)
manager.mu.Lock()
channels, ok := manager.outChans[outChanName]
manager.mu.Unlock()
if !ok {
manager.logger.Warn("received an event for an unknown channel", zap.String("channel", registration.psDetails.ChannelName))
continue
}
for _, ch := range channels {
ch <- registration.registration
}
}
}
}()
return manager
}
func (e *emitterClientManager) GetServiceType() string {
return EmitterServiceType
}
func makeOutChanName(serverAddr, channelName string) string {
return fmt.Sprintf("%s:%s", serverAddr, channelName)
}
func (e *emitterClientManager) unsubscribe(details *EmitterPubSubSubscriptionDetails, ch chan *rendezvous.Registration) {
e.mu.Lock()
defer e.mu.Unlock()
sliceName := makeOutChanName(details.ServerAddr, details.ChannelName)
for i, outChan := range e.outChans[sliceName] {
if outChan == ch {
e.outChans[sliceName] = append(e.outChans[sliceName][:i], e.outChans[sliceName][i+1:]...)
break
}
}
client, err := e.getClient(details)
if err != nil {
e.logger.Error("unable to find client", zap.Error(err))
return
}
if len(e.outChans[sliceName]) == 0 {
if err := client.client.Unsubscribe(details.ReadKey, details.ChannelName); err != nil {
e.logger.Error("unable to unsubscribe from client", zap.Error(err))
}
}
client.usage--
if client.usage <= 0 {
e.clients[details.ServerAddr].cancel()
delete(e.clients, details.ServerAddr)
}
}
================================================
FILE: pkg/rendezvous/emitterio_sync_provider.go
================================================
package rendezvous
import (
"encoding/json"
"fmt"
"math/big"
"time"
emitter "github.com/berty/emitter-go/v2"
rendezvous "github.com/berty/go-libp2p-rendezvous"
pb "github.com/berty/go-libp2p-rendezvous/pb"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
)
const EmitterServiceType = "emitter-io"
type EmitterPubSub struct {
client *emitter.Client
adminKey string
serverAddr string
publicaddr string
logger *zap.Logger
}
type EmitterPubSubSubscriptionDetails struct {
ServerAddr string
ReadKey string
ChannelName string
}
type EmitterOptions struct {
Logger *zap.Logger
ServerPublicAddr string
EmitterOptions []func(*emitter.Client)
}
func NewEmitterServer(serverAddr string, adminKey string, options *EmitterOptions) (*EmitterPubSub, error) {
if options == nil {
options = &EmitterOptions{}
}
if options.ServerPublicAddr == "" {
options.ServerPublicAddr = serverAddr
}
if options.Logger == nil {
options.Logger = zap.NewNop()
}
options.Logger = options.Logger.Named("emitter")
c, err := emitter.Connect(serverAddr, func(_ *emitter.Client, msg emitter.Message) {
options.Logger.Debug("emitter received msg", zap.String("topic", msg.Topic()))
}, emitter.WithLogger(options.Logger.Named("cl")))
if err != nil {
options.Logger.Error("error on `Connect`", zap.Error(err))
}
options.Logger.Debug("connected to emitter", zap.String("target", serverAddr))
ps := &EmitterPubSub{
client: c,
adminKey: adminKey,
logger: options.Logger,
publicaddr: options.ServerPublicAddr,
serverAddr: serverAddr,
}
return ps, nil
}
// nolint:revive
func (p *EmitterPubSub) Register(pid peer.ID, ns string, addrs [][]byte, ttlAsSeconds int, counter uint64) {
p.logger.Debug("register", zap.String("pid", pid.String()), zap.String("ns", ns))
channel := channelForRendezvousPoint(ns)
writeKey, err := p.writeKeyForChannel(channel)
if err != nil {
p.logger.Error("unable to create topic for NS", zap.Error(err))
return
}
dataToSend := &pb.RegistrationRecord{
Id: pid.String(),
Addrs: addrs,
Ns: ns,
Ttl: time.Now().Add(time.Duration(ttlAsSeconds) * time.Second).UnixMilli(),
}
marshaled, err := proto.Marshal(dataToSend)
if err != nil {
p.logger.Error("unable to marshal proto", zap.Error(err))
return
}
if err := p.client.PublishWithTTL(writeKey, channel, marshaled, ttlAsSeconds); err != nil {
p.logger.Error("unable to publish on channel", zap.Error(err))
return
}
p.logger.Debug("publishing done", zap.String("pid", pid.String()), zap.String("channel", channel))
}
func (p *EmitterPubSub) Unregister(_ peer.ID, _ string) {
p.logger.Debug("unsupported method unregister")
}
func (p *EmitterPubSub) Subscribe(ns string) (string, error) {
channel := channelForRendezvousPoint(ns)
readKey, err := p.readKeysForChannel(channel)
if err != nil {
return "", err
}
jsonData, err := json.Marshal(&EmitterPubSubSubscriptionDetails{
ServerAddr: p.publicaddr,
ReadKey: readKey,
ChannelName: channel,
})
if err != nil {
return "", err
}
return string(jsonData), nil
}
func (p *EmitterPubSub) GetServiceType() string {
return EmitterServiceType
}
func (p *EmitterPubSub) Close() error {
p.client.Disconnect(time.Second)
return nil
}
func (p *EmitterPubSub) writeKeyForChannel(channelName string) (string, error) {
return p.keyForChannel(channelName, "w")
}
func (p *EmitterPubSub) readKeysForChannel(channelName string) (string, error) {
return p.keyForChannel(channelName, "r")
}
func (p *EmitterPubSub) keyForChannel(channelName string, permissions string) (string, error) {
key, err := p.client.GenerateKey(p.adminKey, channelName, permissions, int(time.Hour.Seconds()*24))
if err != nil {
return "", fmt.Errorf("unable to generate key: %w", err)
}
return key, nil
}
func channelForRendezvousPoint(topic string) string {
// force base62 encoded topic (without '+' and '#' that are wildcard in the mqtt world)
topic = toBase62(topic)
return fmt.Sprintf("rdvp/%s/", topic)
}
func toBase62(topic string) string {
var i big.Int
i.SetBytes([]byte(topic))
return i.Text(62)
}
var (
_ rendezvous.RendezvousSync = (*EmitterPubSub)(nil)
_ rendezvous.RendezvousSyncSubscribable = (*EmitterPubSub)(nil)
)
================================================
FILE: pkg/rendezvous/emitterio_sync_test.go
================================================
package rendezvous_test
import (
"context"
"os"
"sync"
"sync/atomic"
"testing"
"time"
rendezvous "github.com/berty/go-libp2p-rendezvous"
db "github.com/berty/go-libp2p-rendezvous/db/sqlcipher"
"github.com/berty/go-libp2p-rendezvous/test_utils"
"github.com/libp2p/go-libp2p/core/host"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
berty_rendezvous "berty.tech/weshnet/v2/pkg/rendezvous"
)
func MakeRendezvousServiceTest(ctx context.Context, host host.Host, path string, rzs ...rendezvous.RendezvousSync) (*rendezvous.RendezvousService, error) {
dbi, err := db.OpenDB(ctx, path)
if err != nil {
return nil, err
}
return rendezvous.NewRendezvousService(host, dbi, rzs...), nil
}
func getEmitterRendezvousClients(ctx context.Context, t *testing.T, hosts []host.Host) []rendezvous.RendezvousClient {
t.Helper()
clients := make([]rendezvous.RendezvousClient, len(hosts)-1)
for i, host := range hosts[1:] {
syncClient := berty_rendezvous.NewEmitterClient(nil)
t.Cleanup(func() {
syncClient.Close()
})
clients[i] = rendezvous.NewRendezvousClient(host, hosts[0].ID(), syncClient)
}
return clients
}
func TestEmitterIOFlow(t *testing.T) {
// @NOTE(gfanton): see tools/emitter-server to test it
// TEST_EMITTER_SERVER_ADDR= TEST_EMITTER_ADMINKEY= go test .
const topic = "foo1"
serverAddr := os.Getenv("TEST_EMITTER_SERVER_ADDR")
adminKey := os.Getenv("TEST_EMITTER_ADMINKEY")
if adminKey == "" || serverAddr == "" {
t.Skip("cannot test emitter, no adminKey/serverAddr provided")
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
// Instantiate server and clients
hosts := test_utils.GetRendezvousHosts(t, ctx, mn, 4)
for _, h := range hosts {
t.Cleanup(func() {
_ = h.Close()
})
}
logger, err := zap.NewDevelopment()
require.NoError(t, err)
emitterPubSubSync, err := berty_rendezvous.NewEmitterServer(serverAddr, adminKey, &berty_rendezvous.EmitterOptions{
Logger: logger.Named("emitter"),
})
require.NoError(t, err)
defer emitterPubSubSync.Close()
svc, err := MakeRendezvousServiceTest(ctx, hosts[0], ":memory:", emitterPubSubSync)
require.NoError(t, err)
defer svc.DB.Close()
clients := getEmitterRendezvousClients(ctx, t, hosts)
regFound := int64(0)
wg := sync.WaitGroup{}
const announcementCount = 5
for _, client := range clients[1:] {
wg.Add(1)
ctx, cancel := context.WithTimeout(ctx, time.Second*5)
ch, err := client.DiscoverSubscribe(ctx, topic)
require.NoError(t, err)
go func() {
regFoundForPeer := 0
defer cancel()
defer wg.Done()
for p := range ch {
if test_utils.CheckPeerInfo(t, p, hosts[2], false) == true {
regFoundForPeer++
atomic.AddInt64(®Found, 1)
}
if regFoundForPeer == announcementCount {
go func() {
// this allows more events to be received
time.Sleep(time.Millisecond * 500)
cancel()
}()
}
}
}()
}
for i := 0; i < announcementCount; i++ {
_, err = clients[1].Register(ctx, topic, rendezvous.DefaultTTL)
require.NoError(t, err)
}
wg.Wait()
if regFound != int64(len(clients[1:]))*announcementCount {
require.FailNowf(t, "number of records doesn't match", "expected %d records to be found got %d", int64(len(clients[1:])), regFound)
}
}
================================================
FILE: pkg/rendezvous/rendezvous.go
================================================
package rendezvous
import (
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"time"
)
const DefaultRotationInterval = time.Hour * 24
func RoundTimePeriod(date time.Time, interval time.Duration) time.Time {
if interval < 0 {
interval = -interval
}
intervalSeconds := int64(interval.Seconds())
periodsElapsed := date.Unix() / intervalSeconds
totalTime := periodsElapsed * intervalSeconds
return time.Unix(totalTime, 0).In(date.Location())
}
func NextTimePeriod(date time.Time, interval time.Duration) time.Time {
if interval < 0 {
interval = -interval
}
return RoundTimePeriod(date, interval).Add(interval)
}
func GenerateRendezvousPointForPeriod(topic, seed []byte, date time.Time) []byte {
buf := make([]byte, 8)
mac := hmac.New(sha256.New, append(topic, seed...))
binary.BigEndian.PutUint64(buf, uint64(date.Unix()))
// hash.Hash.Write never returns an error, as documented at
// https://pkg.go.dev/hash#Hash
mac.Write(buf) //nolint:errcheck
sum := mac.Sum(nil)
return sum
}
================================================
FILE: pkg/rendezvous/rendezvous_test.go
================================================
package rendezvous_test
import (
"encoding/hex"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/rendezvous"
)
func TestRoundTimePeriod_Next(t *testing.T) {
cases := []struct {
time time.Time
period time.Duration
out time.Time
next time.Time
}{
{
time: time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC),
period: time.Hour,
out: time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC),
next: time.Date(2020, 4, 10, 13, 0, 0, 0, time.UTC),
},
{
time: time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC),
period: -time.Hour,
out: time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC),
next: time.Date(2020, 4, 10, 13, 0, 0, 0, time.UTC),
},
{
time: time.Date(2020, 4, 10, 12, 34, 56, 0, time.UTC),
period: time.Hour,
out: time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC),
next: time.Date(2020, 4, 10, 13, 0, 0, 0, time.UTC),
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("tc: %d", i), func(t *testing.T) {
rounded := rendezvous.RoundTimePeriod(tc.time, tc.period)
require.Equal(t, tc.out, rounded)
next := rendezvous.NextTimePeriod(tc.time, tc.period)
require.Equal(t, tc.next, next)
})
}
}
func TestGenerateRendezvousPointForPeriod(t *testing.T) {
baseTimeA := time.Date(2020, 4, 10, 12, 0, 0, 0, time.UTC)
baseTimeB := time.Date(2020, 4, 10, 13, 0, 0, 0, time.UTC)
cases := []struct {
topic []byte
seed []byte
expected string // as hex string
time time.Time
}{
{
topic: []byte("topicA"),
seed: []byte("seedA"),
expected: "8b7fdc831ca90f78995f32d8b9cf7bc8682a7fc250fe13a9b7c5c0851a3b8cbc",
time: baseTimeA,
},
{
topic: []byte("topicA"),
seed: []byte("seedA"),
expected: "ec86e0cb471195733ebbeb04277aafcfc60a19c09195cf04e60b50857465c27f",
time: baseTimeB,
},
{
topic: []byte("topicA"),
seed: []byte("seedB"),
expected: "f87f5dfc4e8a68be75d6008ab3aa0a4295b6049e9ec21f03d0c1410895171683",
time: baseTimeA,
},
{
topic: []byte("topicB"),
seed: []byte("seedA"),
expected: "6350bd507198a9acb816dcadae8c5c6ff6c96ee6c9606c8ebe15c1f645ac4c4e",
time: baseTimeA,
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("tc: %d", i), func(t *testing.T) {
point := rendezvous.GenerateRendezvousPointForPeriod(tc.topic, tc.seed, tc.time)
require.Equal(t, tc.expected, hex.EncodeToString(point))
})
}
}
================================================
FILE: pkg/rendezvous/rotation.go
================================================
package rendezvous
import (
"encoding/base64"
"fmt"
"sync"
"time"
)
var (
RotationGracePeriod = time.Minute * 10
MinimumDelayRotation = time.Minute
)
type RotationInterval struct {
interval time.Duration
cacheTopics map[string]*Point
cacheRotations map[string]*Point
muCache sync.RWMutex
}
func NewStaticRotationInterval() *RotationInterval {
// from https://stackoverflow.com/a/32620397
maxTime := time.Unix(1<<63-62135596801, 999999999)
return NewRotationInterval(time.Until(maxTime))
}
func NewRotationInterval(interval time.Duration) *RotationInterval {
return &RotationInterval{
interval: interval,
cacheTopics: make(map[string]*Point),
cacheRotations: make(map[string]*Point),
}
}
func (r *RotationInterval) RegisterRotation(at time.Time, topic string, seed []byte) {
point := r.NewRendezvousPointForPeriod(at, topic, seed)
r.muCache.Lock()
r.registerPoint(point)
r.muCache.Unlock()
}
func (r *RotationInterval) RoundTimePeriod(at time.Time) time.Time {
return RoundTimePeriod(at, r.interval)
}
func (r *RotationInterval) NextTimePeriod(at time.Time) time.Time {
return NextTimePeriod(at, r.interval)
}
func (r *RotationInterval) PointForRawRotation(rotation []byte) (*Point, error) {
return r.PointForRotation(base64.StdEncoding.EncodeToString(rotation))
}
func (r *RotationInterval) PointForRotation(rotation string) (*Point, error) {
r.muCache.Lock()
defer r.muCache.Unlock()
if point, ok := r.cacheRotations[rotation]; ok {
if point.IsExpired() {
point = r.rotate(point, DefaultRotationInterval)
}
return point, nil
}
return nil, fmt.Errorf("unable to get rendez vous, no matching rotation registered")
}
func (r *RotationInterval) PointForTopic(topic string) (*Point, error) {
r.muCache.Lock()
defer r.muCache.Unlock()
if point, ok := r.cacheTopics[topic]; ok {
if point.IsExpired() {
point = r.rotate(point, DefaultRotationInterval)
}
return point, nil
}
return nil, fmt.Errorf("unable to get rendezvous point, no matching topic registered")
}
func (r *RotationInterval) NewRendezvousPointForPeriod(at time.Time, topic string, seed []byte) (point *Point) {
at = r.RoundTimePeriod(at)
rotation := GenerateRendezvousPointForPeriod([]byte(topic), seed, at)
next := r.NextTimePeriod(at)
return &Point{
rp: r,
rotation: rotation,
topic: topic,
seed: seed,
deadline: next,
}
}
func (r *RotationInterval) registerPoint(point *Point) {
keytopic, keyrotation := point.keys()
r.cacheTopics[keytopic] = point
r.cacheRotations[keyrotation] = point
}
func (r *RotationInterval) rotate(old *Point, graceperiod time.Duration) *Point {
newPoint := old.NextPoint()
// register new point
r.registerPoint(newPoint)
cleanuptime := max(time.Until(newPoint.Deadline().Add(graceperiod)), 0)
// cleanup after the grace period
time.AfterFunc(cleanuptime, func() {
r.muCache.Lock()
_, keyrotation := old.keys()
delete(r.cacheRotations, keyrotation)
r.muCache.Unlock()
})
return newPoint
}
type Point struct {
rp *RotationInterval
topic string
rotation []byte
seed []byte
deadline time.Time
}
func (p *Point) NextPoint() *Point {
if p.IsExpired() {
return p.rp.NewRendezvousPointForPeriod(time.Now(), p.topic, p.seed)
}
return p.rp.NewRendezvousPointForPeriod(p.deadline.Add(time.Second), p.topic, p.seed)
}
func (p *Point) Seed() []byte {
return p.seed
}
func (p *Point) keys() (topic string, rotation string) {
topic = p.Topic()
rotation = p.RotationTopic()
return
}
func (p *Point) Topic() string {
return p.topic
}
func (p *Point) RawTopic() []byte {
return []byte(p.topic)
}
func (p *Point) RotationTopic() string {
return base64.StdEncoding.EncodeToString(p.rotation)
}
func (p *Point) RawRotationTopic() []byte {
return p.rotation
}
func (p *Point) Deadline() time.Time {
return p.deadline
}
func (p *Point) TTL() time.Duration {
return time.Until(p.deadline)
}
func (p *Point) IsExpired() bool {
return p.TTL() > 0
}
================================================
FILE: pkg/replicationtypes/bertyreplication.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: replicationtypes/bertyreplication.proto
package replicationtypes
import (
protocoltypes "berty.tech/weshnet/v2/pkg/protocoltypes"
_ "github.com/srikrsna/protoc-gen-gotag/tagger"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ReplicatedGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PublicKey string `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty" gorm:"primaryKey"`
SignPub string `protobuf:"bytes,2,opt,name=sign_pub,json=signPub,proto3" json:"sign_pub,omitempty"`
LinkKey string `protobuf:"bytes,3,opt,name=link_key,json=linkKey,proto3" json:"link_key,omitempty"`
CreatedAt int64 `protobuf:"varint,100,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
UpdatedAt int64 `protobuf:"varint,101,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
MetadataEntriesCount int64 `protobuf:"varint,102,opt,name=metadata_entries_count,json=metadataEntriesCount,proto3" json:"metadata_entries_count,omitempty"`
MetadataLatestHead string `protobuf:"bytes,103,opt,name=metadata_latest_head,json=metadataLatestHead,proto3" json:"metadata_latest_head,omitempty"`
MessageEntriesCount int64 `protobuf:"varint,104,opt,name=message_entries_count,json=messageEntriesCount,proto3" json:"message_entries_count,omitempty"`
MessageLatestHead string `protobuf:"bytes,105,opt,name=message_latest_head,json=messageLatestHead,proto3" json:"message_latest_head,omitempty"`
}
func (x *ReplicatedGroup) Reset() {
*x = ReplicatedGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicatedGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicatedGroup) ProtoMessage() {}
func (x *ReplicatedGroup) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicatedGroup.ProtoReflect.Descriptor instead.
func (*ReplicatedGroup) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{0}
}
func (x *ReplicatedGroup) GetPublicKey() string {
if x != nil {
return x.PublicKey
}
return ""
}
func (x *ReplicatedGroup) GetSignPub() string {
if x != nil {
return x.SignPub
}
return ""
}
func (x *ReplicatedGroup) GetLinkKey() string {
if x != nil {
return x.LinkKey
}
return ""
}
func (x *ReplicatedGroup) GetCreatedAt() int64 {
if x != nil {
return x.CreatedAt
}
return 0
}
func (x *ReplicatedGroup) GetUpdatedAt() int64 {
if x != nil {
return x.UpdatedAt
}
return 0
}
func (x *ReplicatedGroup) GetMetadataEntriesCount() int64 {
if x != nil {
return x.MetadataEntriesCount
}
return 0
}
func (x *ReplicatedGroup) GetMetadataLatestHead() string {
if x != nil {
return x.MetadataLatestHead
}
return ""
}
func (x *ReplicatedGroup) GetMessageEntriesCount() int64 {
if x != nil {
return x.MessageEntriesCount
}
return 0
}
func (x *ReplicatedGroup) GetMessageLatestHead() string {
if x != nil {
return x.MessageLatestHead
}
return ""
}
type ReplicatedGroupToken struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ReplicatedGroupPublicKey string `protobuf:"bytes,1,opt,name=replicated_group_public_key,json=replicatedGroupPublicKey,proto3" json:"replicated_group_public_key,omitempty" gorm:"index;primaryKey;autoIncrement:false"`
ReplicatedGroup *ReplicatedGroup `protobuf:"bytes,2,opt,name=replicated_group,json=replicatedGroup,proto3" json:"replicated_group,omitempty"`
TokenIssuer string `protobuf:"bytes,3,opt,name=token_issuer,json=tokenIssuer,proto3" json:"token_issuer,omitempty" gorm:"primaryKey;autoIncrement:false"`
TokenId string `protobuf:"bytes,4,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty" gorm:"primaryKey;autoIncrement:false"`
CreatedAt int64 `protobuf:"varint,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
}
func (x *ReplicatedGroupToken) Reset() {
*x = ReplicatedGroupToken{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicatedGroupToken) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicatedGroupToken) ProtoMessage() {}
func (x *ReplicatedGroupToken) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicatedGroupToken.ProtoReflect.Descriptor instead.
func (*ReplicatedGroupToken) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{1}
}
func (x *ReplicatedGroupToken) GetReplicatedGroupPublicKey() string {
if x != nil {
return x.ReplicatedGroupPublicKey
}
return ""
}
func (x *ReplicatedGroupToken) GetReplicatedGroup() *ReplicatedGroup {
if x != nil {
return x.ReplicatedGroup
}
return nil
}
func (x *ReplicatedGroupToken) GetTokenIssuer() string {
if x != nil {
return x.TokenIssuer
}
return ""
}
func (x *ReplicatedGroupToken) GetTokenId() string {
if x != nil {
return x.TokenId
}
return ""
}
func (x *ReplicatedGroupToken) GetCreatedAt() int64 {
if x != nil {
return x.CreatedAt
}
return 0
}
type ReplicationServiceReplicateGroup struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicationServiceReplicateGroup) Reset() {
*x = ReplicationServiceReplicateGroup{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{2}
}
type ReplicateGlobalStats struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicateGlobalStats) Reset() {
*x = ReplicateGlobalStats{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGlobalStats) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGlobalStats) ProtoMessage() {}
func (x *ReplicateGlobalStats) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGlobalStats.ProtoReflect.Descriptor instead.
func (*ReplicateGlobalStats) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{3}
}
type ReplicateGroupStats struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicateGroupStats) Reset() {
*x = ReplicateGroupStats{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGroupStats) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGroupStats) ProtoMessage() {}
func (x *ReplicateGroupStats) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGroupStats.ProtoReflect.Descriptor instead.
func (*ReplicateGroupStats) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{4}
}
type ReplicationServiceReplicateGroup_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Group *protocoltypes.Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *ReplicationServiceReplicateGroup_Request) Reset() {
*x = ReplicationServiceReplicateGroup_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup_Request) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup_Request) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup_Request.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup_Request) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{2, 0}
}
func (x *ReplicationServiceReplicateGroup_Request) GetGroup() *protocoltypes.Group {
if x != nil {
return x.Group
}
return nil
}
type ReplicationServiceReplicateGroup_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
}
func (x *ReplicationServiceReplicateGroup_Reply) Reset() {
*x = ReplicationServiceReplicateGroup_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicationServiceReplicateGroup_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicationServiceReplicateGroup_Reply) ProtoMessage() {}
func (x *ReplicationServiceReplicateGroup_Reply) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicationServiceReplicateGroup_Reply.ProtoReflect.Descriptor instead.
func (*ReplicationServiceReplicateGroup_Reply) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{2, 1}
}
func (x *ReplicationServiceReplicateGroup_Reply) GetOk() bool {
if x != nil {
return x.Ok
}
return false
}
type ReplicateGlobalStats_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReplicateGlobalStats_Request) Reset() {
*x = ReplicateGlobalStats_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGlobalStats_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGlobalStats_Request) ProtoMessage() {}
func (x *ReplicateGlobalStats_Request) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGlobalStats_Request.ProtoReflect.Descriptor instead.
func (*ReplicateGlobalStats_Request) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{3, 0}
}
type ReplicateGlobalStats_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
StartedAt int64 `protobuf:"varint,1,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
ReplicatedGroups int64 `protobuf:"varint,2,opt,name=replicated_groups,json=replicatedGroups,proto3" json:"replicated_groups,omitempty"`
TotalMetadataEntries int64 `protobuf:"varint,3,opt,name=total_metadata_entries,json=totalMetadataEntries,proto3" json:"total_metadata_entries,omitempty"`
TotalMessageEntries int64 `protobuf:"varint,4,opt,name=total_message_entries,json=totalMessageEntries,proto3" json:"total_message_entries,omitempty"`
}
func (x *ReplicateGlobalStats_Reply) Reset() {
*x = ReplicateGlobalStats_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGlobalStats_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGlobalStats_Reply) ProtoMessage() {}
func (x *ReplicateGlobalStats_Reply) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGlobalStats_Reply.ProtoReflect.Descriptor instead.
func (*ReplicateGlobalStats_Reply) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{3, 1}
}
func (x *ReplicateGlobalStats_Reply) GetStartedAt() int64 {
if x != nil {
return x.StartedAt
}
return 0
}
func (x *ReplicateGlobalStats_Reply) GetReplicatedGroups() int64 {
if x != nil {
return x.ReplicatedGroups
}
return 0
}
func (x *ReplicateGlobalStats_Reply) GetTotalMetadataEntries() int64 {
if x != nil {
return x.TotalMetadataEntries
}
return 0
}
func (x *ReplicateGlobalStats_Reply) GetTotalMessageEntries() int64 {
if x != nil {
return x.TotalMessageEntries
}
return 0
}
type ReplicateGroupStats_Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
GroupPublicKey string `protobuf:"bytes,1,opt,name=group_public_key,json=groupPublicKey,proto3" json:"group_public_key,omitempty"`
}
func (x *ReplicateGroupStats_Request) Reset() {
*x = ReplicateGroupStats_Request{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGroupStats_Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGroupStats_Request) ProtoMessage() {}
func (x *ReplicateGroupStats_Request) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGroupStats_Request.ProtoReflect.Descriptor instead.
func (*ReplicateGroupStats_Request) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{4, 0}
}
func (x *ReplicateGroupStats_Request) GetGroupPublicKey() string {
if x != nil {
return x.GroupPublicKey
}
return ""
}
type ReplicateGroupStats_Reply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Group *ReplicatedGroup `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"`
}
func (x *ReplicateGroupStats_Reply) Reset() {
*x = ReplicateGroupStats_Reply{}
if protoimpl.UnsafeEnabled {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReplicateGroupStats_Reply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReplicateGroupStats_Reply) ProtoMessage() {}
func (x *ReplicateGroupStats_Reply) ProtoReflect() protoreflect.Message {
mi := &file_replicationtypes_bertyreplication_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReplicateGroupStats_Reply.ProtoReflect.Descriptor instead.
func (*ReplicateGroupStats_Reply) Descriptor() ([]byte, []int) {
return file_replicationtypes_bertyreplication_proto_rawDescGZIP(), []int{4, 1}
}
func (x *ReplicateGroupStats_Reply) GetGroup() *ReplicatedGroup {
if x != nil {
return x.Group
}
return nil
}
var File_replicationtypes_bertyreplication_proto protoreflect.FileDescriptor
var file_replicationtypes_bertyreplication_proto_rawDesc = []byte{
0x0a, 0x27, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70,
0x65, 0x73, 0x2f, 0x62, 0x65, 0x72, 0x74, 0x79, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76,
0x31, 0x1a, 0x13, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x74, 0x79, 0x70, 0x65, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x74, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2f, 0x74,
0x61, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88, 0x03, 0x0a, 0x0f,
0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12,
0x35, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x42, 0x16, 0x9a, 0x84, 0x9e, 0x03, 0x11, 0x67, 0x6f, 0x72, 0x6d, 0x3a, 0x22,
0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x22, 0x52, 0x09, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x70,
0x75, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x69, 0x67, 0x6e, 0x50, 0x75,
0x62, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x03,
0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x65, 0x20, 0x01, 0x28, 0x03, 0x52,
0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x66, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x30, 0x0a, 0x14, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x61, 0x74,
0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x67, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12,
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x48, 0x65,
0x61, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x65, 0x6e,
0x74, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x68, 0x20, 0x01, 0x28,
0x03, 0x52, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x69, 0x20,
0x01, 0x28, 0x09, 0x52, 0x11, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x61, 0x74, 0x65,
0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x22, 0x90, 0x03, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
0x6f, 0x0a, 0x1b, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0x9a, 0x84, 0x9e, 0x03, 0x2b, 0x67, 0x6f, 0x72, 0x6d, 0x3a,
0x22, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, 0x65,
0x79, 0x3b, 0x61, 0x75, 0x74, 0x6f, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a,
0x66, 0x61, 0x6c, 0x73, 0x65, 0x22, 0x52, 0x18, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79,
0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77, 0x65, 0x73,
0x68, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x47,
0x72, 0x6f, 0x75, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x73,
0x73, 0x75, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0x9a, 0x84, 0x9e, 0x03,
0x25, 0x67, 0x6f, 0x72, 0x6d, 0x3a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, 0x65,
0x79, 0x3b, 0x61, 0x75, 0x74, 0x6f, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a,
0x66, 0x61, 0x6c, 0x73, 0x65, 0x22, 0x52, 0x0b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x73, 0x73,
0x75, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0x9a, 0x84, 0x9e, 0x03, 0x25, 0x67, 0x6f, 0x72, 0x6d,
0x3a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x3b, 0x61, 0x75, 0x74,
0x6f, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65,
0x22, 0x52, 0x07, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x78, 0x0a, 0x20, 0x52, 0x65, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52,
0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x3b, 0x0a,
0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x17, 0x0a, 0x05, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x02, 0x6f, 0x6b, 0x22, 0xe1, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a, 0x09, 0x0a, 0x07,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0xbd, 0x01, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c,
0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74,
0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x67,
0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x72, 0x65, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x34, 0x0a,
0x16, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x74,
0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x03, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a,
0x33, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x72,
0x6f, 0x75, 0x70, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x1a, 0x46, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3d, 0x0a,
0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x77,
0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x32, 0xab, 0x03, 0x0a,
0x12, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x92, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x40, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e,
0x65, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76,
0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x80, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x73, 0x12, 0x34, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x7d, 0x0a, 0x13, 0x52,
0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61,
0x74, 0x73, 0x12, 0x33, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65,
0x74, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53,
0x74, 0x61, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x42, 0x2c, 0x5a, 0x2a, 0x62, 0x65,
0x72, 0x74, 0x79, 0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_replicationtypes_bertyreplication_proto_rawDescOnce sync.Once
file_replicationtypes_bertyreplication_proto_rawDescData = file_replicationtypes_bertyreplication_proto_rawDesc
)
func file_replicationtypes_bertyreplication_proto_rawDescGZIP() []byte {
file_replicationtypes_bertyreplication_proto_rawDescOnce.Do(func() {
file_replicationtypes_bertyreplication_proto_rawDescData = protoimpl.X.CompressGZIP(file_replicationtypes_bertyreplication_proto_rawDescData)
})
return file_replicationtypes_bertyreplication_proto_rawDescData
}
var file_replicationtypes_bertyreplication_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_replicationtypes_bertyreplication_proto_goTypes = []any{
(*ReplicatedGroup)(nil), // 0: weshnet.replication.v1.ReplicatedGroup
(*ReplicatedGroupToken)(nil), // 1: weshnet.replication.v1.ReplicatedGroupToken
(*ReplicationServiceReplicateGroup)(nil), // 2: weshnet.replication.v1.ReplicationServiceReplicateGroup
(*ReplicateGlobalStats)(nil), // 3: weshnet.replication.v1.ReplicateGlobalStats
(*ReplicateGroupStats)(nil), // 4: weshnet.replication.v1.ReplicateGroupStats
(*ReplicationServiceReplicateGroup_Request)(nil), // 5: weshnet.replication.v1.ReplicationServiceReplicateGroup.Request
(*ReplicationServiceReplicateGroup_Reply)(nil), // 6: weshnet.replication.v1.ReplicationServiceReplicateGroup.Reply
(*ReplicateGlobalStats_Request)(nil), // 7: weshnet.replication.v1.ReplicateGlobalStats.Request
(*ReplicateGlobalStats_Reply)(nil), // 8: weshnet.replication.v1.ReplicateGlobalStats.Reply
(*ReplicateGroupStats_Request)(nil), // 9: weshnet.replication.v1.ReplicateGroupStats.Request
(*ReplicateGroupStats_Reply)(nil), // 10: weshnet.replication.v1.ReplicateGroupStats.Reply
(*protocoltypes.Group)(nil), // 11: weshnet.protocol.v1.Group
}
var file_replicationtypes_bertyreplication_proto_depIdxs = []int32{
0, // 0: weshnet.replication.v1.ReplicatedGroupToken.replicated_group:type_name -> weshnet.replication.v1.ReplicatedGroup
11, // 1: weshnet.replication.v1.ReplicationServiceReplicateGroup.Request.group:type_name -> weshnet.protocol.v1.Group
0, // 2: weshnet.replication.v1.ReplicateGroupStats.Reply.group:type_name -> weshnet.replication.v1.ReplicatedGroup
5, // 3: weshnet.replication.v1.ReplicationService.ReplicateGroup:input_type -> weshnet.replication.v1.ReplicationServiceReplicateGroup.Request
7, // 4: weshnet.replication.v1.ReplicationService.ReplicateGlobalStats:input_type -> weshnet.replication.v1.ReplicateGlobalStats.Request
9, // 5: weshnet.replication.v1.ReplicationService.ReplicateGroupStats:input_type -> weshnet.replication.v1.ReplicateGroupStats.Request
6, // 6: weshnet.replication.v1.ReplicationService.ReplicateGroup:output_type -> weshnet.replication.v1.ReplicationServiceReplicateGroup.Reply
8, // 7: weshnet.replication.v1.ReplicationService.ReplicateGlobalStats:output_type -> weshnet.replication.v1.ReplicateGlobalStats.Reply
10, // 8: weshnet.replication.v1.ReplicationService.ReplicateGroupStats:output_type -> weshnet.replication.v1.ReplicateGroupStats.Reply
6, // [6:9] is the sub-list for method output_type
3, // [3:6] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_replicationtypes_bertyreplication_proto_init() }
func file_replicationtypes_bertyreplication_proto_init() {
if File_replicationtypes_bertyreplication_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_replicationtypes_bertyreplication_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*ReplicatedGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*ReplicatedGroupToken); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[3].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGlobalStats); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[4].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGroupStats); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[5].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[6].Exporter = func(v any, i int) any {
switch v := v.(*ReplicationServiceReplicateGroup_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[7].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGlobalStats_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[8].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGlobalStats_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[9].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGroupStats_Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_replicationtypes_bertyreplication_proto_msgTypes[10].Exporter = func(v any, i int) any {
switch v := v.(*ReplicateGroupStats_Reply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_replicationtypes_bertyreplication_proto_rawDesc,
NumEnums: 0,
NumMessages: 11,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_replicationtypes_bertyreplication_proto_goTypes,
DependencyIndexes: file_replicationtypes_bertyreplication_proto_depIdxs,
MessageInfos: file_replicationtypes_bertyreplication_proto_msgTypes,
}.Build()
File_replicationtypes_bertyreplication_proto = out.File
file_replicationtypes_bertyreplication_proto_rawDesc = nil
file_replicationtypes_bertyreplication_proto_goTypes = nil
file_replicationtypes_bertyreplication_proto_depIdxs = nil
}
================================================
FILE: pkg/replicationtypes/bertyreplication.pb.gw.go
================================================
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: replicationtypes/bertyreplication.proto
/*
Package replicationtypes is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package replicationtypes
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
func request_ReplicationService_ReplicateGroup_0(ctx context.Context, marshaler runtime.Marshaler, client ReplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicationServiceReplicateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReplicateGroup(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ReplicationService_ReplicateGroup_0(ctx context.Context, marshaler runtime.Marshaler, server ReplicationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicationServiceReplicateGroup_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReplicateGroup(ctx, &protoReq)
return msg, metadata, err
}
func request_ReplicationService_ReplicateGlobalStats_0(ctx context.Context, marshaler runtime.Marshaler, client ReplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicateGlobalStats_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReplicateGlobalStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ReplicationService_ReplicateGlobalStats_0(ctx context.Context, marshaler runtime.Marshaler, server ReplicationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicateGlobalStats_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReplicateGlobalStats(ctx, &protoReq)
return msg, metadata, err
}
func request_ReplicationService_ReplicateGroupStats_0(ctx context.Context, marshaler runtime.Marshaler, client ReplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicateGroupStats_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReplicateGroupStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ReplicationService_ReplicateGroupStats_0(ctx context.Context, marshaler runtime.Marshaler, server ReplicationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReplicateGroupStats_Request
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReplicateGroupStats(ctx, &protoReq)
return msg, metadata, err
}
// RegisterReplicationServiceHandlerServer registers the http handlers for service ReplicationService to "mux".
// UnaryRPC :call ReplicationServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterReplicationServiceHandlerFromEndpoint instead.
func RegisterReplicationServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ReplicationServiceServer) error {
mux.Handle("POST", pattern_ReplicationService_ReplicateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ReplicationService_ReplicateGroup_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ReplicationService_ReplicateGlobalStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ReplicationService_ReplicateGlobalStats_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGlobalStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ReplicationService_ReplicateGroupStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ReplicationService_ReplicateGroupStats_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGroupStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterReplicationServiceHandlerFromEndpoint is same as RegisterReplicationServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterReplicationServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterReplicationServiceHandler(ctx, mux, conn)
}
// RegisterReplicationServiceHandler registers the http handlers for service ReplicationService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterReplicationServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterReplicationServiceHandlerClient(ctx, mux, NewReplicationServiceClient(conn))
}
// RegisterReplicationServiceHandlerClient registers the http handlers for service ReplicationService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ReplicationServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ReplicationServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ReplicationServiceClient" to call the correct interceptors.
func RegisterReplicationServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ReplicationServiceClient) error {
mux.Handle("POST", pattern_ReplicationService_ReplicateGroup_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ReplicationService_ReplicateGroup_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGroup_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ReplicationService_ReplicateGlobalStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ReplicationService_ReplicateGlobalStats_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGlobalStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ReplicationService_ReplicateGroupStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ReplicationService_ReplicateGroupStats_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ReplicationService_ReplicateGroupStats_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_ReplicationService_ReplicateGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.replication.v1.ReplicationService", "ReplicateGroup"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ReplicationService_ReplicateGlobalStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.replication.v1.ReplicationService", "ReplicateGlobalStats"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ReplicationService_ReplicateGroupStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"weshnet.replication.v1.ReplicationService", "ReplicateGroupStats"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_ReplicationService_ReplicateGroup_0 = runtime.ForwardResponseMessage
forward_ReplicationService_ReplicateGlobalStats_0 = runtime.ForwardResponseMessage
forward_ReplicationService_ReplicateGroupStats_0 = runtime.ForwardResponseMessage
)
================================================
FILE: pkg/replicationtypes/bertyreplication_grpc.pb.go
================================================
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: replicationtypes/bertyreplication.proto
package replicationtypes
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
ReplicationService_ReplicateGroup_FullMethodName = "/weshnet.replication.v1.ReplicationService/ReplicateGroup"
ReplicationService_ReplicateGlobalStats_FullMethodName = "/weshnet.replication.v1.ReplicationService/ReplicateGlobalStats"
ReplicationService_ReplicateGroupStats_FullMethodName = "/weshnet.replication.v1.ReplicationService/ReplicateGroupStats"
)
// ReplicationServiceClient is the client API for ReplicationService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// ReplicationService
type ReplicationServiceClient interface {
// ReplicateGroup
ReplicateGroup(ctx context.Context, in *ReplicationServiceReplicateGroup_Request, opts ...grpc.CallOption) (*ReplicationServiceReplicateGroup_Reply, error)
ReplicateGlobalStats(ctx context.Context, in *ReplicateGlobalStats_Request, opts ...grpc.CallOption) (*ReplicateGlobalStats_Reply, error)
ReplicateGroupStats(ctx context.Context, in *ReplicateGroupStats_Request, opts ...grpc.CallOption) (*ReplicateGroupStats_Reply, error)
}
type replicationServiceClient struct {
cc grpc.ClientConnInterface
}
func NewReplicationServiceClient(cc grpc.ClientConnInterface) ReplicationServiceClient {
return &replicationServiceClient{cc}
}
func (c *replicationServiceClient) ReplicateGroup(ctx context.Context, in *ReplicationServiceReplicateGroup_Request, opts ...grpc.CallOption) (*ReplicationServiceReplicateGroup_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReplicationServiceReplicateGroup_Reply)
err := c.cc.Invoke(ctx, ReplicationService_ReplicateGroup_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *replicationServiceClient) ReplicateGlobalStats(ctx context.Context, in *ReplicateGlobalStats_Request, opts ...grpc.CallOption) (*ReplicateGlobalStats_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReplicateGlobalStats_Reply)
err := c.cc.Invoke(ctx, ReplicationService_ReplicateGlobalStats_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *replicationServiceClient) ReplicateGroupStats(ctx context.Context, in *ReplicateGroupStats_Request, opts ...grpc.CallOption) (*ReplicateGroupStats_Reply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReplicateGroupStats_Reply)
err := c.cc.Invoke(ctx, ReplicationService_ReplicateGroupStats_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ReplicationServiceServer is the server API for ReplicationService service.
// All implementations must embed UnimplementedReplicationServiceServer
// for forward compatibility.
//
// ReplicationService
type ReplicationServiceServer interface {
// ReplicateGroup
ReplicateGroup(context.Context, *ReplicationServiceReplicateGroup_Request) (*ReplicationServiceReplicateGroup_Reply, error)
ReplicateGlobalStats(context.Context, *ReplicateGlobalStats_Request) (*ReplicateGlobalStats_Reply, error)
ReplicateGroupStats(context.Context, *ReplicateGroupStats_Request) (*ReplicateGroupStats_Reply, error)
mustEmbedUnimplementedReplicationServiceServer()
}
// UnimplementedReplicationServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedReplicationServiceServer struct{}
func (UnimplementedReplicationServiceServer) ReplicateGroup(context.Context, *ReplicationServiceReplicateGroup_Request) (*ReplicationServiceReplicateGroup_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReplicateGroup not implemented")
}
func (UnimplementedReplicationServiceServer) ReplicateGlobalStats(context.Context, *ReplicateGlobalStats_Request) (*ReplicateGlobalStats_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReplicateGlobalStats not implemented")
}
func (UnimplementedReplicationServiceServer) ReplicateGroupStats(context.Context, *ReplicateGroupStats_Request) (*ReplicateGroupStats_Reply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReplicateGroupStats not implemented")
}
func (UnimplementedReplicationServiceServer) mustEmbedUnimplementedReplicationServiceServer() {}
func (UnimplementedReplicationServiceServer) testEmbeddedByValue() {}
// UnsafeReplicationServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ReplicationServiceServer will
// result in compilation errors.
type UnsafeReplicationServiceServer interface {
mustEmbedUnimplementedReplicationServiceServer()
}
func RegisterReplicationServiceServer(s grpc.ServiceRegistrar, srv ReplicationServiceServer) {
// If the following call pancis, it indicates UnimplementedReplicationServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&ReplicationService_ServiceDesc, srv)
}
func _ReplicationService_ReplicateGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReplicationServiceReplicateGroup_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ReplicationServiceServer).ReplicateGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ReplicationService_ReplicateGroup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ReplicationServiceServer).ReplicateGroup(ctx, req.(*ReplicationServiceReplicateGroup_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ReplicationService_ReplicateGlobalStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReplicateGlobalStats_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ReplicationServiceServer).ReplicateGlobalStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ReplicationService_ReplicateGlobalStats_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ReplicationServiceServer).ReplicateGlobalStats(ctx, req.(*ReplicateGlobalStats_Request))
}
return interceptor(ctx, in, info, handler)
}
func _ReplicationService_ReplicateGroupStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReplicateGroupStats_Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ReplicationServiceServer).ReplicateGroupStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ReplicationService_ReplicateGroupStats_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ReplicationServiceServer).ReplicateGroupStats(ctx, req.(*ReplicateGroupStats_Request))
}
return interceptor(ctx, in, info, handler)
}
// ReplicationService_ServiceDesc is the grpc.ServiceDesc for ReplicationService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ReplicationService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "weshnet.replication.v1.ReplicationService",
HandlerType: (*ReplicationServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ReplicateGroup",
Handler: _ReplicationService_ReplicateGroup_Handler,
},
{
MethodName: "ReplicateGlobalStats",
Handler: _ReplicationService_ReplicateGlobalStats_Handler,
},
{
MethodName: "ReplicateGroupStats",
Handler: _ReplicationService_ReplicateGroupStats_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "replicationtypes/bertyreplication.proto",
}
================================================
FILE: pkg/replicationtypes/consts.go
================================================
package replicationtypes
const (
ServiceReplicationRegisteredPrefix = "user_registration"
ServiceReplicationKeyGroupPrefix = "group"
)
================================================
FILE: pkg/replicationtypes/models.go
================================================
package replicationtypes
import (
"encoding/base64"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func (m *ReplicatedGroup) ToGroup() (*protocoltypes.Group, error) {
pk, err := base64.RawURLEncoding.DecodeString(m.PublicKey)
if err != nil {
return nil, err
}
signPub, err := base64.RawURLEncoding.DecodeString(m.SignPub)
if err != nil {
return nil, err
}
linkKey, err := base64.RawURLEncoding.DecodeString(m.LinkKey)
if err != nil {
return nil, err
}
return &protocoltypes.Group{
PublicKey: pk,
SignPub: signPub,
LinkKey: linkKey,
}, nil
}
================================================
FILE: pkg/secretstore/chain_key.go
================================================
package secretstore
import (
crand "crypto/rand"
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
"golang.org/x/crypto/nacl/box"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
// newDeviceChainKey creates a new random chain key
func newDeviceChainKey() (*protocoltypes.DeviceChainKey, error) {
chainKey := make([]byte, 32)
_, err := crand.Read(chainKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoRandomGeneration.Wrap(err)
}
return &protocoltypes.DeviceChainKey{
ChainKey: chainKey,
Counter: 0,
}, nil
}
// encryptDeviceChainKey encrypts a device chain key for a target member
func encryptDeviceChainKey(localDevicePrivateKey crypto.PrivKey, remoteMemberPubKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey, group *protocoltypes.Group) ([]byte, error) {
chainKeyBytes, err := proto.Marshal(deviceChainKey)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localDevicePrivateKey, remoteMemberPubKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
nonce := groupIDToNonce(group)
encryptedChainKey := box.Seal(nil, chainKeyBytes, nonce, mongPub, mongPriv)
return encryptedChainKey, nil
}
// decryptDeviceChainKey decrypts a chain key sent by the given device
func decryptDeviceChainKey(encryptedDeviceChainKey []byte, group *protocoltypes.Group, localMemberPrivateKey crypto.PrivKey, senderDevicePubKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
mongPriv, mongPub, err := cryptoutil.EdwardsToMontgomery(localMemberPrivateKey, senderDevicePubKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
nonce := groupIDToNonce(group)
decryptedSecret := &protocoltypes.DeviceChainKey{}
decryptedMessage, ok := box.Open(nil, encryptedDeviceChainKey, nonce, mongPub, mongPriv)
if !ok {
return nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(fmt.Errorf("unable to decrypt message"))
}
err = proto.Unmarshal(decryptedMessage, decryptedSecret)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return decryptedSecret, nil
}
// groupIDToNonce converts a group public key to a value which can be used as
// a nonce of the nacl library
func groupIDToNonce(group *protocoltypes.Group) *[cryptoutil.NonceSize]byte {
// Nonce doesn't need to be secret, random nor unpredictable, it just needs
// to be used only once for a given sender+receiver set, and we will send
// only one SecretEntryPayload per localDevicePrivateKey+remoteMemberPubKey
// So we can reuse groupID as nonce for all SecretEntryPayload and save
// 24 bytes of storage and bandwidth for each of them.
//
// See https://pynacl.readthedocs.io/en/stable/secret/#nonce
// See Security Model here: https://nacl.cr.yp.to/box.html
var nonce [cryptoutil.NonceSize]byte
gid := group.GetPublicKey()
copy(nonce[:], gid)
return &nonce
}
================================================
FILE: pkg/secretstore/datastore_keys.go
================================================
package secretstore
import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/libp2p/go-libp2p/core/crypto"
"berty.tech/weshnet/v2/pkg/errcode"
)
const (
// dsNamespaceChainKeyForDeviceOnGroup is a namespace stores the current
// state of a device chain key for a given group.
// It contains the secret used to derive the next value of the chain key
// and used to generate a message key for the message at `counter` value,
// then put in the dsNamespacePrecomputedMessageKeys namespace.
dsNamespaceChainKeyForDeviceOnGroup = "chainKeyForDeviceOnGroup"
// dsNamespacePrecomputedMessageKeys is a namespace storing precomputed
// message keys for a given group, device and message counter.
// As the chain key stored has already been derived, these message keys
// need to be computed beforehand.
// The corresponding message can then be decrypted via a quick lookup.
dsNamespacePrecomputedMessageKeys = "precomputedMessageKeys"
// dsNamespaceMessageKeyForCIDs is a namespace containing the message key
// for a given CID once the corresponding message has been decrypted.
dsNamespaceMessageKeyForCIDs = "messageKeyForCIDs"
// dsNamespaceOutOfStoreGroupHint is a namespace where HMAC value are
// associated to a group public key.
// It is used when receiving an out-of-store message (e.g. a push
// notification) to identify the group on which the message belongs, which
// can then be decrypted.
dsNamespaceOutOfStoreGroupHint = "outOfStoreGroupHint"
// dsNamespaceOutOfStoreGroupHintCounters is a namespace storing first and
// last counter values for generated group hints inside the
// dsNamespaceOutOfStoreGroupHint namespace
dsNamespaceOutOfStoreGroupHintCounters = "outOfStoreGroupHintCounters"
// dsNamespaceGroupDatastore is a namespace to store groups by their public
// key
dsNamespaceGroupDatastore = "groupByPublicKey"
)
func dsKeyForGroup(key []byte) datastore.Key {
return datastore.KeyWithNamespaces([]string{
dsNamespaceGroupDatastore,
base64.RawURLEncoding.EncodeToString(key),
})
}
// dsKeyForPrecomputedMessageKey returns a datastore.Key where will be stored a
// precalculated message key for a given group and device
func dsKeyForPrecomputedMessageKey(groupPublicKey, devicePublicKey []byte, counter uint64) datastore.Key {
return datastore.KeyWithNamespaces([]string{
dsNamespacePrecomputedMessageKeys,
hex.EncodeToString(groupPublicKey),
hex.EncodeToString(devicePublicKey),
fmt.Sprintf("%d", counter),
})
}
// dsKeyForCurrentChainKey returns a datastore.Key where will be stored a
// device chain key for a given group.
func dsKeyForCurrentChainKey(groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (datastore.Key, error) {
devicePublicKeyBytes, err := devicePublicKey.Raw()
if err != nil {
return datastore.Key{}, errcode.ErrCode_ErrSerialization.Wrap(err)
}
groupPublicKeyBytes, err := groupPublicKey.Raw()
if err != nil {
return datastore.Key{}, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return datastore.KeyWithNamespaces([]string{
dsNamespaceChainKeyForDeviceOnGroup,
hex.EncodeToString(groupPublicKeyBytes),
hex.EncodeToString(devicePublicKeyBytes),
}), nil
}
// dsKeyForMessageKeyByCID returns a datastore.Key where will be stored a
// message decryption key for a given message CID.
func dsKeyForMessageKeyByCID(id cid.Cid) datastore.Key {
// TODO: specify the id
return datastore.KeyWithNamespaces([]string{
dsNamespaceMessageKeyForCIDs,
id.String(),
})
}
// dsKeyForOutOfStoreMessageGroupHint returns a datastore.Key where will be
// stored a group public key for a given push group reference.
func dsKeyForOutOfStoreMessageGroupHint(ref []byte) datastore.Key {
return datastore.KeyWithNamespaces([]string{
dsNamespaceOutOfStoreGroupHint,
base64.RawURLEncoding.EncodeToString(ref),
})
}
// dsKeyForOutOfStoreFirstLastCounters returns the datastore.Key where will be
// stored a protocoltypes.FirstLastCounters struct for the given group public
// key and device public key.
func dsKeyForOutOfStoreFirstLastCounters(groupPK, devicePK []byte) datastore.Key {
return datastore.KeyWithNamespaces([]string{
dsNamespaceOutOfStoreGroupHintCounters,
base64.RawURLEncoding.EncodeToString(groupPK),
base64.RawURLEncoding.EncodeToString(devicePK),
})
}
================================================
FILE: pkg/secretstore/device_keystore_wrapper.go
================================================
package secretstore
import (
"crypto/ed25519"
crand "crypto/rand"
"encoding/hex"
"fmt"
"strings"
"sync"
"github.com/aead/ecdh"
keystore "github.com/ipfs/go-ipfs-keystore"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const (
keyAccount = "accountSK"
keyAccountProof = "accountProofSK"
keyDevice = "deviceSK"
keyMemberDevice = "memberDeviceSK"
keyMember = "memberSK"
keyContactGroup = "contactGroupSK"
)
// deviceKeystore is a wrapper around a keystore.Keystore object.
// It contains methods to manipulate member and device keys.
type deviceKeystore struct {
keystore keystore.Keystore
mu sync.Mutex
logger *zap.Logger
}
// newDeviceKeystore instantiate a new device keystore
func newDeviceKeystore(ks keystore.Keystore, logger *zap.Logger) *deviceKeystore {
if logger == nil {
logger = zap.NewNop()
}
return &deviceKeystore{
keystore: ks,
logger: logger,
}
}
// getAccountPrivateKey returns the private key of the current account
func (a *deviceKeystore) getAccountPrivateKey() (crypto.PrivKey, error) {
a.mu.Lock()
defer a.mu.Unlock()
return a.getOrGenerateNamedKey(keyAccount)
}
// getAccountProofPrivateKey returns the private proof key of
// the current account
func (a *deviceKeystore) getAccountProofPrivateKey() (crypto.PrivKey, error) {
a.mu.Lock()
defer a.mu.Unlock()
return a.getOrGenerateNamedKey(keyAccountProof)
}
// devicePrivateKey returns the current private key of the current device for
// the account and one-to-one conversations
func (a *deviceKeystore) devicePrivateKey() (crypto.PrivKey, error) {
a.mu.Lock()
defer a.mu.Unlock()
return a.getOrGenerateNamedKey(keyDevice)
}
// contactGroupPrivateKey retrieves the key for the contact group
// shared with the supplied contact's public key, this key will be derived to
// form the contact group keys
func (a *deviceKeystore) contactGroupPrivateKey(contactPublicKey crypto.PubKey) (crypto.PrivKey, error) {
accountPrivateKey, err := a.getAccountPrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return a.getOrComputeECDH(keyContactGroup, contactPublicKey, accountPrivateKey)
}
// memberDeviceForMultiMemberGroup retrieves the device private key for the
// supplied group
func (a *deviceKeystore) memberDeviceForMultiMemberGroup(groupPublicKey crypto.PubKey) (*ownMemberDevice, error) {
memberPrivateKey, err := a.computeMemberKeyForMultiMemberGroup(groupPublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to get or generate a device key for group member: %w", err))
}
devicePrivateKey, err := a.getOrGenerateDeviceKeyForMultiMemberGroup(groupPublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return newOwnMemberDevice(memberPrivateKey, devicePrivateKey), nil
}
// memberDeviceForGroup computes or retrieves the member and device key for the
// supplied group
func (a *deviceKeystore) memberDeviceForGroup(group *protocoltypes.Group) (*ownMemberDevice, error) {
publicKey, err := group.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unable to get public key for group: %w", err))
}
switch group.GetGroupType() {
case protocoltypes.GroupType_GroupTypeAccount, protocoltypes.GroupType_GroupTypeContact:
memberPrivateKey, err := a.getAccountPrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
devicePrivateKey, err := a.devicePrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return newOwnMemberDevice(memberPrivateKey, devicePrivateKey), nil
case protocoltypes.GroupType_GroupTypeMultiMember:
return a.memberDeviceForMultiMemberGroup(publicKey)
}
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unknown group type"))
}
// getOrGenerateNamedKey retrieves a private key by its name, or generate it
// if missing
func (a *deviceKeystore) getOrGenerateNamedKey(name string) (crypto.PrivKey, error) {
privateKey, err := a.keystore.Get(name)
if err == nil {
return privateKey, nil
} else if err.Error() != keystore.ErrNoSuchKey.Error() {
return nil, errcode.ErrCode_ErrDBRead.Wrap(fmt.Errorf("unable to perform get operation on keystore: %w", err))
}
privateKey, _, err = crypto.GenerateEd25519Key(crand.Reader)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(fmt.Errorf("unable to generate an ed25519 key: %w", err))
}
if err := a.keystore.Put(name, privateKey); err != nil {
return nil, errcode.ErrCode_ErrDBWrite.Wrap(fmt.Errorf("unable to perform put operation on keystore: %w", err))
}
return privateKey, nil
}
// getOrGenerateDeviceKeyForMultiMemberGroup fetches or generate a new device
// key for a multi-member group. The results do not need to be deterministic
// as it will only be used on the current device.
func (a *deviceKeystore) getOrGenerateDeviceKeyForMultiMemberGroup(groupPublicKey crypto.PubKey) (crypto.PrivKey, error) {
a.mu.Lock()
defer a.mu.Unlock()
groupPublicKeyRaw, err := groupPublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
name := strings.Join([]string{keyMemberDevice, hex.EncodeToString(groupPublicKeyRaw)}, "_")
return a.getOrGenerateNamedKey(name)
}
// getOrComputeECDH fetches a named private key or computes one via an
// elliptic-curve Diffie-Hellman key agreement if not cached
func (a *deviceKeystore) getOrComputeECDH(nameSpace string, publicKey crypto.PubKey, ownPrivateKey crypto.PrivKey) (crypto.PrivKey, error) {
a.mu.Lock()
defer a.mu.Unlock()
publicKeyRaw, err := publicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
name := strings.Join([]string{nameSpace, hex.EncodeToString(publicKeyRaw)}, "_")
privateKey, err := a.keystore.Get(name)
if err == nil {
return privateKey, nil
} else if err.Error() != keystore.ErrNoSuchKey.Error() {
return nil, errcode.ErrCode_ErrDBRead.Wrap(fmt.Errorf("unable to perform get operation on keystore: %w", err))
}
privateKeyBytes, publicKeyBytes, err := cryptoutil.EdwardsToMontgomery(ownPrivateKey, publicKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
secret := ecdh.X25519().ComputeSecret(privateKeyBytes, publicKeyBytes)
groupSecretPrivateKey := ed25519.NewKeyFromSeed(secret)
privateKey, _, err = crypto.KeyPairFromStdKey(&groupSecretPrivateKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(err)
}
if err := a.keystore.Put(name, privateKey); err != nil {
return nil, errcode.ErrCode_ErrDBWrite.Wrap(err)
}
return privateKey, nil
}
// computeMemberKeyForMultiMemberGroup returns a deterministic private key
// for a multi member group, this allows a group to be joined from two
// different devices simultaneously without requiring a consensus.
func (a *deviceKeystore) computeMemberKeyForMultiMemberGroup(groupPublicKey crypto.PubKey) (crypto.PrivKey, error) {
accountProofPrivateKey, err := a.getAccountProofPrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return a.getOrComputeECDH(keyMember, groupPublicKey, accountProofPrivateKey)
}
// restoreAccountKeys restores exported LibP2P keys into the deviceKeystore, it
// will fail if accounts keys are already created or imported into the keystore
func (a *deviceKeystore) restoreAccountKeys(accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte) error {
privateKeys := map[string]crypto.PrivKey{}
for keyName, keyBytes := range map[string][]byte{
keyAccount: accountPrivateKeyBytes,
keyAccountProof: accountProofPrivateKeyBytes,
} {
var err error
privateKeys[keyName], err = getEd25519PrivateKeyFromLibP2PFormattedBytes(keyBytes)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
}
if privateKeys[keyAccount].Equals(privateKeys[keyAccountProof]) {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("the account key cannot be the same value as the account proof key"))
}
for keyName := range privateKeys {
if exists, err := a.keystore.Has(keyName); err != nil {
return errcode.ErrCode_ErrDBRead.Wrap(err)
} else if exists {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("an account is already set in this keystore"))
}
}
for keyName, privateKey := range privateKeys {
if err := a.keystore.Put(keyName, privateKey); err != nil {
return errcode.ErrCode_ErrDBWrite.Wrap(err)
}
}
return nil
}
================================================
FILE: pkg/secretstore/device_keystore_wrapper_test.go
================================================
package secretstore_test
import (
crand "crypto/rand"
"testing"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/assert"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
func Test_New_AccountPrivKey_AccountProofPrivKey(t *testing.T) {
acc, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc)
sk1, skProof1, err := acc.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk1)
assert.NotNil(t, skProof1)
sk2, skProof2, err := acc.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk2)
assert.NotNil(t, skProof2)
assert.Equal(t, sk1, sk2)
assert.Equal(t, skProof1, skProof2)
assert.NotEqual(t, sk1, skProof1)
assert.NotEqual(t, sk1, skProof2)
assert.NotEqual(t, sk2, skProof1)
assert.NotEqual(t, sk2, skProof2)
}
func Test_ExportAccountKeys_ImportAccountKeys(t *testing.T) {
acc1, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc1)
sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk1)
assert.NotNil(t, skProof1)
acc2, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc2)
// Testing with a nil value
{
assert.Error(t, acc2.ImportAccountKeys(nil, skProof1))
assert.Error(t, acc2.ImportAccountKeys(sk1, nil))
}
// Testing with an unsupported key format
{
invalidPriv, _, err := crypto.GenerateSecp256k1Key(crand.Reader)
assert.NoError(t, err)
invalidPrivBytes, err := crypto.MarshalPrivateKey(invalidPriv)
assert.NoError(t, err)
assert.Error(t, acc2.ImportAccountKeys(sk1, invalidPrivBytes))
assert.Error(t, acc2.ImportAccountKeys(invalidPrivBytes, skProof1))
}
// Testing with an invalid key format
{
garbageBytes := []byte("garbage")
assert.Error(t, acc2.ImportAccountKeys(sk1, garbageBytes))
assert.Error(t, acc2.ImportAccountKeys(garbageBytes, skProof1))
}
// Testing with account and proof key being the same
{
assert.Error(t, acc2.ImportAccountKeys(sk1, sk1))
}
// Valid test case
{
assert.NoError(t, acc2.ImportAccountKeys(sk1, skProof1))
}
// Attempting to import keys again
{
assert.Error(t, acc2.ImportAccountKeys(sk1, skProof1))
}
sk2, skProof2, err := acc1.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk2)
assert.NotNil(t, skProof2)
assert.Equal(t, sk1, sk2)
assert.Equal(t, skProof1, skProof2)
assert.NotEqual(t, sk1, skProof1)
assert.NotEqual(t, sk1, skProof2)
assert.NotEqual(t, sk2, skProof1)
assert.NotEqual(t, sk2, skProof2)
}
func Test_DevicePrivKey(t *testing.T) {
acc1, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc1)
sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk1)
assert.NotNil(t, skProof1)
acc2, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc1)
err = acc2.ImportAccountKeys(sk1, skProof1)
assert.NoError(t, err)
sk2, skProof2, err := acc2.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk2)
assert.NotNil(t, skProof2)
accGroup1, memberDevice1, err := acc1.GetGroupForAccount()
assert.NoError(t, err)
assert.NotNil(t, accGroup1)
memberDevice2, err := acc2.GetOwnMemberDeviceForGroup(accGroup1)
assert.NoError(t, err)
assert.NotNil(t, memberDevice2)
assert.True(t, memberDevice1.Member().Equals(memberDevice2.Member()))
assert.False(t, memberDevice1.Device().Equals(memberDevice2.Device()))
}
func Test_ContactGroupPrivKey(t *testing.T) {
acc1, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc1)
_, acc1MemberDevice, err := acc1.GetGroupForAccount()
assert.NoError(t, err)
assert.NotNil(t, acc1MemberDevice)
acc2, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc2)
_, acc2MemberDevice, err := acc2.GetGroupForAccount()
assert.NoError(t, err)
assert.NotNil(t, acc2MemberDevice)
grp1, err := acc1.GetGroupForContact(acc2MemberDevice.Member())
assert.NoError(t, err)
assert.NotNil(t, grp1)
grp2, err := acc2.GetGroupForContact(acc1MemberDevice.Member())
assert.NoError(t, err)
assert.NotNil(t, grp2)
assert.Equal(t, grp1.PublicKey, grp2.PublicKey)
assert.Equal(t, grp1.Secret, grp2.Secret)
assert.Equal(t, grp1.GroupType, grp2.GroupType)
}
func Test_MemberDeviceForGroup_multimember(t *testing.T) {
acc1, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc1)
sk1, skProof1, err := acc1.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk1)
assert.NotNil(t, skProof1)
acc2, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, acc2)
err = acc2.ImportAccountKeys(sk1, skProof1)
assert.NoError(t, err)
sk2, skProof2, err := acc2.ExportAccountKeysForBackup()
assert.NoError(t, err)
assert.NotNil(t, sk2)
assert.NotNil(t, skProof2)
g, _, err := protocoltypes.NewGroupMultiMember()
assert.NoError(t, err)
omd1, err := acc1.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
omd2, err := acc2.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
omd1M := omd1.Member()
omd2M := omd2.Member()
omd1D := omd1.Device()
omd2D := omd2.Device()
assert.True(t, omd1M.Equals(omd2M))
assert.False(t, omd1D.Equals(omd2D))
}
================================================
FILE: pkg/secretstore/doc.go
================================================
// Package secretstore contains function related to device, groups and messages keys.
package secretstore
================================================
FILE: pkg/secretstore/keys_utils.go
================================================
package secretstore
import (
"crypto/ed25519"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
"github.com/libp2p/go-libp2p/core/crypto"
crypto_pb "github.com/libp2p/go-libp2p/core/crypto/pb"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
// getEd25519PrivateKeyFromLibP2PFormattedBytes transforms an exported LibP2P
// private key into a crypto.PrivKey instance, ensuring it is an ed25519 key
func getEd25519PrivateKeyFromLibP2PFormattedBytes(rawKeyBytes []byte) (crypto.PrivKey, error) {
if len(rawKeyBytes) == 0 {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("missing key data"))
}
privateKey, err := crypto.UnmarshalPrivateKey(rawKeyBytes)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
if privateKey.Type() != crypto_pb.KeyType_Ed25519 {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid key format"))
}
return privateKey, nil
}
// getKeysForGroupOfContact returns derived private keys for contact group
// using a private key via two accounts account keys (via an ECDH).
func getKeysForGroupOfContact(contactPairPrivateKey crypto.PrivKey) (crypto.PrivKey, crypto.PrivKey, error) {
// Salt length must be equal to hash length (64 bytes for sha256)
hash := sha256.New
contactPairPrivateKeyBytes, err := contactPairPrivateKey.Raw()
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
// Generate Pseudo Random Key using contactPairPrivateKeyBytes as IKM and salt
prk := hkdf.Extract(hash, contactPairPrivateKeyBytes, nil)
if len(prk) == 0 {
return nil, nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to instantiate pseudo random key"))
}
// Expand using extracted prk and groupID as info (kind of namespace)
kdf := hkdf.Expand(hash, prk, nil)
// Generate next KDF and message keys
groupSeed, err := io.ReadAll(io.LimitReader(kdf, 32))
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
groupSecretSeed, err := io.ReadAll(io.LimitReader(kdf, 32))
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
stdGroupPrivateKey := ed25519.NewKeyFromSeed(groupSeed)
groupPrivateKey, _, err := crypto.KeyPairFromStdKey(&stdGroupPrivateKey)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
stdGroupSecretPrivateKey := ed25519.NewKeyFromSeed(groupSecretSeed)
groupSecretPrivateKey, _, err := crypto.KeyPairFromStdKey(&stdGroupSecretPrivateKey)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return groupPrivateKey, groupSecretPrivateKey, nil
}
// getGroupForContact returns a protocoltypes.Group instance for a contact,
// using a private key via two accounts account keys (via an ECDH)
func getGroupForContact(contactPairPrivateKey crypto.PrivKey) (*protocoltypes.Group, error) {
groupPrivateKey, groupSecretPrivateKey, err := getKeysForGroupOfContact(contactPairPrivateKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
pubBytes, err := groupPrivateKey.GetPublic().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(groupSecretPrivateKey)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return &protocoltypes.Group{
PublicKey: pubBytes,
Secret: signingBytes,
SecretSig: nil,
GroupType: protocoltypes.GroupType_GroupTypeContact,
}, nil
}
// getGroupOutOfStoreSecret retrieves the out of store group secret
func getGroupOutOfStoreSecret(m *protocoltypes.Group) ([]byte, error) {
if len(m.GetSecret()) == 0 {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("no secret known for group"))
}
arr := [cryptoutil.KeySize]byte{}
kdf := hkdf.New(sha3.New256, m.GetSecret(), nil, []byte(namespaceOutOfStoreSecret))
if _, err := io.ReadFull(kdf, arr[:]); err != nil {
return nil, errcode.ErrCode_ErrStreamRead.Wrap(err)
}
return arr[:], nil
}
// createOutOfStoreGroupReference creates a hash used to identify an out of
// store (e.g. push notification) message origin
func createOutOfStoreGroupReference(m *protocoltypes.Group, sender []byte, counter uint64) ([]byte, error) {
secret, err := getGroupOutOfStoreSecret(m)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
arr := [cryptoutil.KeySize]byte{}
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, counter)
kdf := hkdf.New(sha3.New256, secret, nil, append(sender, buf...))
if _, err := io.ReadFull(kdf, arr[:]); err != nil {
return nil, errcode.ErrCode_ErrStreamRead.Wrap(err)
}
return arr[:], nil
}
================================================
FILE: pkg/secretstore/member_device.go
================================================
package secretstore
import (
"github.com/libp2p/go-libp2p/core/crypto"
)
type ownMemberDevice struct {
member crypto.PrivKey
device crypto.PrivKey
public *memberDevice
}
// newOwnMemberDevice instantiate a new ownMemberDevice allowing signing
// and encrypting data as both a device or a member part of a group.
// It also contains the public counterpart of the member and device keys.
func newOwnMemberDevice(member, device crypto.PrivKey) *ownMemberDevice {
return &ownMemberDevice{
member: member,
device: device,
public: newMemberDevice(member.GetPublic(), device.GetPublic()),
}
}
func (d *ownMemberDevice) MemberSign(data []byte) ([]byte, error) {
return d.member.Sign(data)
}
func (d *ownMemberDevice) DeviceSign(data []byte) ([]byte, error) {
return d.device.Sign(data)
}
func (d *ownMemberDevice) Member() crypto.PubKey {
return d.public.member
}
func (d *ownMemberDevice) Device() crypto.PubKey {
return d.public.device
}
type memberDevice struct {
member crypto.PubKey
device crypto.PubKey
}
func NewMemberDevice(member, device crypto.PubKey) MemberDevice {
return newMemberDevice(member, device)
}
func newMemberDevice(member, device crypto.PubKey) *memberDevice {
return &memberDevice{
member: member,
device: device,
}
}
func (m *memberDevice) Member() crypto.PubKey {
return m.member
}
func (m *memberDevice) Device() crypto.PubKey {
return m.device
}
================================================
FILE: pkg/secretstore/secret_store.go
================================================
package secretstore
import (
"context"
"fmt"
"sync"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"golang.org/x/crypto/nacl/secretbox"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/internal/datastoreutil"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const (
namespaceDeviceKeystore = "device_keystore"
namespaceOutOfStoreSecret = "push_secret_ref" // nolint:gosec
)
type secretStore struct {
logger *zap.Logger
datastore datastore.Datastore
deviceKeystore *deviceKeystore
messageMutex sync.RWMutex
preComputedKeysCount int
precomputeOutOfStoreGroupRefsCount uint64
}
func (o *NewSecretStoreOptions) applyDefaults(rootDatastore datastore.Datastore) {
if o.Logger == nil {
o.Logger = zap.NewNop()
}
if o.Keystore == nil {
o.Keystore = ipfsutil.NewDatastoreKeystore(datastoreutil.NewNamespacedDatastore(rootDatastore, datastore.NewKey(namespaceDeviceKeystore)))
}
if o.PreComputedKeysCount <= 0 {
o.PreComputedKeysCount = PrecomputeMessageKeyCount
}
if o.PrecomputeOutOfStoreGroupRefsCount <= 0 {
o.PrecomputeOutOfStoreGroupRefsCount = PrecomputeOutOfStoreGroupRefsCount
}
}
// NewSecretStore instantiates a new SecretStore
func NewSecretStore(rootDatastore datastore.Datastore, opts *NewSecretStoreOptions) (SecretStore, error) {
return newSecretStore(rootDatastore, opts)
}
// newSecretStore instantiates a new secretStore
func newSecretStore(rootDatastore datastore.Datastore, opts *NewSecretStoreOptions) (*secretStore, error) {
if rootDatastore == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("a datastore is required"))
}
if opts == nil {
opts = &NewSecretStoreOptions{}
}
opts.applyDefaults(rootDatastore)
devKeystore := newDeviceKeystore(opts.Keystore, opts.Logger)
store := &secretStore{
logger: opts.Logger,
datastore: rootDatastore,
deviceKeystore: devKeystore,
preComputedKeysCount: opts.PreComputedKeysCount,
precomputeOutOfStoreGroupRefsCount: uint64(opts.PrecomputeOutOfStoreGroupRefsCount),
}
return store, nil
}
// NewInMemSecretStore instantiates a SecretStore using a volatile backend.
func NewInMemSecretStore(opts *NewSecretStoreOptions) (SecretStore, error) {
return newInMemSecretStore(opts)
}
// newInMemSecretStore instantiates a secretStore using a volatile backend.
func newInMemSecretStore(opts *NewSecretStoreOptions) (*secretStore, error) {
return newSecretStore(dssync.MutexWrap(datastore.NewMapDatastore()), opts)
}
func (s *secretStore) Close() error {
return nil
}
func (s *secretStore) PutGroup(ctx context.Context, g *protocoltypes.Group) error {
pk, err := g.GetPubKey()
if err != nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
// TODO: check if partial group or full group and complete if necessary
if ok, err := s.hasGroup(ctx, pk); err != nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(err)
} else if ok {
return nil
}
data, err := proto.Marshal(g)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
if err := s.datastore.Put(ctx, dsKeyForGroup(g.GetPublicKey()), data); err != nil {
return errcode.ErrCode_ErrKeystorePut.Wrap(err)
}
memberDevice, err := s.GetOwnMemberDeviceForGroup(g)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
// Force generation of chain key for own device
_, err = s.GetShareableChainKey(ctx, g, memberDevice.Member())
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
return nil
}
func (s *secretStore) GetOwnMemberDeviceForGroup(g *protocoltypes.Group) (OwnMemberDevice, error) {
return s.deviceKeystore.memberDeviceForGroup(g)
}
func (s *secretStore) OpenOutOfStoreMessage(ctx context.Context, payload []byte) (*protocoltypes.OutOfStoreMessage, *protocoltypes.Group, []byte, bool, error) {
oosMessageEnv := &protocoltypes.OutOfStoreMessageEnvelope{}
if err := proto.Unmarshal(payload, oosMessageEnv); err != nil {
return nil, nil, nil, false, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
groupPublicKey, err := s.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, oosMessageEnv.GroupReference)
if err != nil {
return nil, nil, nil, false, errcode.ErrCode_ErrNotFound.Wrap(err)
}
oosMessage, err := s.decryptOutOfStoreMessageEnv(ctx, oosMessageEnv, groupPublicKey)
if err != nil {
return nil, nil, nil, false, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
clear, newlyDecrypted, err := s.OutOfStoreMessageOpen(ctx, oosMessage, groupPublicKey)
if err != nil {
return nil, nil, nil, false, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
group, err := s.FetchGroupByPublicKey(ctx, groupPublicKey)
if err == nil {
if err := s.UpdateOutOfStoreGroupReferences(ctx, oosMessage.DevicePk, oosMessage.Counter, group); err != nil {
s.logger.Error("unable to update push group references", zap.Error(err))
}
}
return oosMessage, group, clear, !newlyDecrypted, nil
}
func (s *secretStore) decryptOutOfStoreMessageEnv(ctx context.Context, env *protocoltypes.OutOfStoreMessageEnvelope, groupPK crypto.PubKey) (*protocoltypes.OutOfStoreMessage, error) {
nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
g, err := s.FetchGroupByPublicKey(ctx, groupPK)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unable to find group, err: %w", err))
}
secret := g.GetSharedSecret()
data, ok := secretbox.Open(nil, env.Box, nonce, secret)
if !ok {
return nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(fmt.Errorf("unable to decrypt message"))
}
outOfStoreMessage := &protocoltypes.OutOfStoreMessage{}
if err := proto.Unmarshal(data, outOfStoreMessage); err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return outOfStoreMessage, nil
}
func (s *secretStore) FetchGroupByPublicKey(ctx context.Context, publicKey crypto.PubKey) (*protocoltypes.Group, error) {
keyBytes, err := publicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
data, err := s.datastore.Get(ctx, dsKeyForGroup(keyBytes))
if err != nil {
return nil, errcode.ErrCode_ErrMissingMapKey.Wrap(err)
}
g := &protocoltypes.Group{}
if err := proto.Unmarshal(data, g); err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return g, nil
}
func (s *secretStore) GetAccountProofPublicKey() (crypto.PubKey, error) {
privateKey, err := s.deviceKeystore.getAccountPrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return privateKey.GetPublic(), nil
}
func (s *secretStore) ImportAccountKeys(accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte) error {
return s.deviceKeystore.restoreAccountKeys(accountPrivateKeyBytes, accountProofPrivateKeyBytes)
}
func (s *secretStore) ExportAccountKeysForBackup() (accountPrivateKeyBytes []byte, accountProofPrivateKeyBytes []byte, err error) {
accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
if err != nil {
return nil, nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
accountProofPrivateKey, err := s.deviceKeystore.getAccountProofPrivateKey()
if err != nil {
return nil, nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
accountPrivateKeyBytes, err = crypto.MarshalPrivateKey(accountPrivateKey)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
accountProofPrivateKeyBytes, err = crypto.MarshalPrivateKey(accountProofPrivateKey)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return accountPrivateKeyBytes, accountProofPrivateKeyBytes, nil
}
func (s *secretStore) GetAccountPrivateKey() (crypto.PrivKey, error) {
accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return accountPrivateKey, nil
}
func (s *secretStore) GetGroupForAccount() (*protocoltypes.Group, OwnMemberDevice, error) {
accountPrivateKey, err := s.deviceKeystore.getAccountPrivateKey()
if err != nil {
return nil, nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
accountProofPrivateKey, err := s.deviceKeystore.getAccountProofPrivateKey()
if err != nil {
return nil, nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
devicePrivateKey, err := s.deviceKeystore.devicePrivateKey()
if err != nil {
return nil, nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
pubBytes, err := accountPrivateKey.GetPublic().Raw()
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
signingBytes, err := cryptoutil.SeedFromEd25519PrivateKey(accountProofPrivateKey)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return &protocoltypes.Group{
PublicKey: pubBytes,
Secret: signingBytes,
SecretSig: nil,
GroupType: protocoltypes.GroupType_GroupTypeAccount,
}, newOwnMemberDevice(accountPrivateKey, devicePrivateKey), nil
}
func (s *secretStore) GetGroupForContact(contactPublicKey crypto.PubKey) (*protocoltypes.Group, error) {
contactPairPrivateKey, err := s.deviceKeystore.contactGroupPrivateKey(contactPublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return getGroupForContact(contactPairPrivateKey)
}
func (s *secretStore) OpenEnvelopeHeaders(data []byte, g *protocoltypes.Group) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error) {
env := &protocoltypes.MessageEnvelope{}
err := proto.Unmarshal(data, env)
if err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
nonce, err := cryptoutil.NonceSliceToArray(env.Nonce)
if err != nil {
return nil, nil, errcode.ErrCode_ErrSerialization.Wrap(fmt.Errorf("unable to convert slice to array: %w", err))
}
headersBytes, ok := secretbox.Open(nil, env.MessageHeaders, nonce, g.GetSharedSecret())
if !ok {
return nil, nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(fmt.Errorf("secretbox failed to open headers"))
}
headers := &protocoltypes.MessageHeaders{}
if err := proto.Unmarshal(headersBytes, headers); err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return env, headers, nil
}
func (s *secretStore) SealOutOfStoreMessageEnvelope(id cid.Cid, env *protocoltypes.MessageEnvelope, headers *protocoltypes.MessageHeaders, group *protocoltypes.Group) (*protocoltypes.OutOfStoreMessageEnvelope, error) {
oosMessage := &protocoltypes.OutOfStoreMessage{
Cid: id.Bytes(),
DevicePk: headers.DevicePk,
Counter: headers.Counter,
Sig: headers.Sig,
EncryptedPayload: env.Message,
Nonce: env.Nonce,
}
data, err := proto.Marshal(oosMessage)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
nonce, err := cryptoutil.GenerateNonce()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoNonceGeneration.Wrap(err)
}
secret, err := cryptoutil.KeySliceToArray(group.Secret)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyConversion.Wrap(fmt.Errorf("unable to convert slice to array: %w", err))
}
encryptedData := secretbox.Seal(nil, data, nonce, secret)
pushGroupRef, err := createOutOfStoreGroupReference(group, headers.DevicePk, headers.Counter)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return &protocoltypes.OutOfStoreMessageEnvelope{
Nonce: nonce[:],
Box: encryptedData,
GroupReference: pushGroupRef,
}, nil
}
// hasGroup checks whether a group is already known by the secretStore
func (s *secretStore) hasGroup(ctx context.Context, key crypto.PubKey) (bool, error) {
keyBytes, err := key.Raw()
if err != nil {
return false, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return s.datastore.Has(ctx, dsKeyForGroup(keyBytes))
}
================================================
FILE: pkg/secretstore/secret_store_interfaces.go
================================================
package secretstore
import (
"context"
"github.com/ipfs/go-cid"
keystore "github.com/ipfs/go-ipfs-keystore"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const (
PrecomputeOutOfStoreGroupRefsCount = 100
PrecomputeMessageKeyCount = 100
)
type messageKey [32]byte
type SecretStore interface {
//
// Account methods
//
// GetAccountProofPublicKey returns the user's account proof public key
GetAccountProofPublicKey() (accountProofPublicKey crypto.PubKey, err error)
// ImportAccountKeys restores backup of account keys into the SecretStore, it should fail if the store is already used by an account
ImportAccountKeys(accountPrivateKey []byte, accountProofPrivateKey []byte) error
// ExportAccountKeysForBackup returns the account's private key and proof private key of the user for a backup
ExportAccountKeysForBackup() (accountPrivateKey []byte, accountProofPrivateKey []byte, err error)
// GetAccountPrivateKey returns the account's private key, avoid using it, use GetGroupForAccount to get the account public key or sign data instead
GetAccountPrivateKey() (accountPrivateKey crypto.PrivKey, err error)
//
// Groups methods
//
// GetGroupForAccount returns the Account's Group of the user
GetGroupForAccount() (group *protocoltypes.Group, ownMemberDevice OwnMemberDevice, err error)
// GetGroupForContact returns a contact group for communicating with the provided account
GetGroupForContact(contactPublicKey crypto.PubKey) (group *protocoltypes.Group, err error)
// PutGroup stores a group into the store
PutGroup(ctx context.Context, group *protocoltypes.Group) error
// FetchGroupByPublicKey gets an account from the store using the provided public key
FetchGroupByPublicKey(ctx context.Context, publicKey crypto.PubKey) (group *protocoltypes.Group, err error)
//
// Envelopes methods
//
// OpenEnvelopeHeaders opens a message headers for a given group
OpenEnvelopeHeaders(data []byte, group *protocoltypes.Group) (*protocoltypes.MessageEnvelope, *protocoltypes.MessageHeaders, error)
// OpenEnvelopePayload opens a message payload with the given group headers
OpenEnvelopePayload(ctx context.Context, msgEnvelope *protocoltypes.MessageEnvelope, msgHeaders *protocoltypes.MessageHeaders, groupPublicKey crypto.PubKey, ownPublicKey crypto.PubKey, msgCID cid.Cid) (*protocoltypes.EncryptedMessage, error)
// SealEnvelope creates an encrypted payload to be sent to a group
SealEnvelope(ctx context.Context, group *protocoltypes.Group, messagePayload []byte) (sealedEnvelope []byte, err error)
//
// Group member-device pairs methods
//
// GetOwnMemberDeviceForGroup gets a member and device key-pairs representing the current device in a given group
GetOwnMemberDeviceForGroup(group *protocoltypes.Group) (OwnMemberDevice, error)
//
// Chain-keys methods
//
// RegisterChainKey records another device chain-key
RegisterChainKey(ctx context.Context, group *protocoltypes.Group, senderDevicePublicKey crypto.PubKey, encryptedDeviceChainKey []byte) error
// GetShareableChainKey returns a chain-key that can be decrypted by the provided member of a group
GetShareableChainKey(ctx context.Context, group *protocoltypes.Group, targetMemberPublicKey crypto.PubKey) (encryptedDeviceChainKey []byte, err error)
// IsChainKeyKnownForDevice checks whether a chain key of a device is already known
IsChainKeyKnownForDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (isKnown bool)
//
// Out-of-store messages methods
//
// SealOutOfStoreMessageEnvelope encrypts a message to be sent outside a synchronized store
SealOutOfStoreMessageEnvelope(id cid.Cid, env *protocoltypes.MessageEnvelope, headers *protocoltypes.MessageHeaders, group *protocoltypes.Group) (*protocoltypes.OutOfStoreMessageEnvelope, error)
// OpenOutOfStoreMessage opens a message received outside a synchronized store
OpenOutOfStoreMessage(ctx context.Context, payload []byte) (outOfStoreMessage *protocoltypes.OutOfStoreMessage, group *protocoltypes.Group, clearPayload []byte, alreadyDecrypted bool, err error)
// UpdateOutOfStoreGroupReferences computes references of messages which might be received outside a synchronized store
UpdateOutOfStoreGroupReferences(ctx context.Context, devicePublicKeyBytes []byte, first uint64, group *protocoltypes.Group) error
// Close frees resources created by the secret store
Close() error
}
// NewSecretStoreOptions contains the options that can be passed to NewSecretStore
type NewSecretStoreOptions struct {
// PreComputedKeysCount specifies the number of keys to precompute,
// defaults to PrecomputeMessageKeyCount
PreComputedKeysCount int
// PrecomputeOutOfStoreGroupRefsCount specifies the number of out of store references
// to precompute, defaults to PrecomputeOutOfStoreGroupRefsCount
PrecomputeOutOfStoreGroupRefsCount int
// Keystore specifies an implementation of a keystore to be used, can be
// helpful if you want to rely on a hardware based keystore instead of a
// software one
Keystore keystore.Keystore
// Logger specifies which logger to use, logging is disabled by default
Logger *zap.Logger
// DisableOutOfStoreSupport explicitly disables support of out-of-store
// payloads
DisableOutOfStoreSupport bool
}
// MemberDevice is the public keys of a device and its member
type MemberDevice interface {
// Member returns the member public key
Member() crypto.PubKey
// Device returns the device public key
Device() crypto.PubKey
}
// OwnMemberDevice is a MemberDevice for the current device, able to sign data
type OwnMemberDevice interface {
MemberDevice
// MemberSign signs the given data as a member of a group
MemberSign(data []byte) ([]byte, error)
// DeviceSign signs the given data as a device of a group
DeviceSign(data []byte) ([]byte, error)
}
================================================
FILE: pkg/secretstore/secret_store_messages.go
================================================
package secretstore
import (
"context"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/nacl/secretbox"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
// decryptionContext contains context about a decrypted message, its CID, the
// associated message key and whether it had been previously opened.
type decryptionContext struct {
newlyDecrypted bool
messageKey *messageKey
cid cid.Cid
}
// computedMessageKey is a precomputed message key for a given counter used in the cache namespace.
type computedMessageKey struct {
counter uint64
messageKey *messageKey
}
// getDeviceChainKeyForGroupAndDevice returns the device chain key for the given group and device.
func (s *secretStore) getDeviceChainKeyForGroupAndDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
key, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
// Not mutex here
dsBytes, err := s.datastore.Get(ctx, key)
if err == datastore.ErrNotFound {
return nil, errcode.ErrCode_ErrMissingInput.Wrap(err)
} else if err != nil {
return nil, errcode.ErrCode_ErrMessageKeyPersistenceGet.Wrap(err)
}
ds := &protocoltypes.DeviceChainKey{}
if err := proto.Unmarshal(dsBytes, ds); err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
return ds, nil
}
// IsChainKeyKnownForDevice returns true if the device chain key is known for the given group and device.
func (s *secretStore) IsChainKeyKnownForDevice(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (has bool) {
if s == nil {
return false
}
key, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
if err != nil {
return false
}
s.messageMutex.RLock()
defer s.messageMutex.RUnlock()
has, _ = s.datastore.Has(ctx, key)
return
}
// delPrecomputedKey deletes the message key in the cache namespace for the given group, device and counter.
func (s *secretStore) delPrecomputedKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, msgCounter uint64) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
devicePublicKeyRaw, err := devicePublicKey.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
groupPublicKeyRaw, err := groupPublicKey.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
id := dsKeyForPrecomputedMessageKey(groupPublicKeyRaw, devicePublicKeyRaw, msgCounter)
err = s.datastore.Delete(ctx, id)
if err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
return nil
}
// postDecryptActions is called after a message has been decrypted.
// It saves the message key from the cache namespace to find it quickly on subsequent read operations.
// It derives the chain key in the cache namespace.
func (s *secretStore) postDecryptActions(ctx context.Context, decryptionCtx *decryptionContext, groupPublicKey crypto.PubKey, ownPublicKey crypto.PubKey, msgHeaders *protocoltypes.MessageHeaders) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
// Message was newly decrypted, we can save the message key and derive
// future keys if necessary.
if decryptionCtx == nil || !decryptionCtx.newlyDecrypted {
return nil
}
var (
deviceChainKey *protocoltypes.DeviceChainKey
err error
)
devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(msgHeaders.DevicePk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if err = s.putKeyForCID(ctx, decryptionCtx.cid, decryptionCtx.messageKey); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if err = s.delPrecomputedKey(ctx, groupPublicKey, devicePublicKey, msgHeaders.Counter); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if deviceChainKey, err = s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
// If the message was not emitted by the current Device we might need
// to update the current chain key
if ownPublicKey == nil || !ownPublicKey.Equals(devicePublicKey) {
if err = s.updateCurrentKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
func (s *secretStore) GetShareableChainKey(ctx context.Context, group *protocoltypes.Group, targetMemberPublicKey crypto.PubKey) ([]byte, error) {
deviceChainKey, err := s.getOwnDeviceChainKeyForGroup(ctx, group)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
privateMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
encryptedDeviceChainKey, err := encryptDeviceChainKey(privateMemberDevice.device, targetMemberPublicKey, deviceChainKey, group)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoEncrypt.Wrap(err)
}
return encryptedDeviceChainKey, nil
}
// getOwnDeviceChainKeyForGroup returns the device chain key for the current
// device on a given group.
// If the chain key has not been created yet, it will be generated and
// registered.
func (s *secretStore) getOwnDeviceChainKeyForGroup(ctx context.Context, group *protocoltypes.Group) (*protocoltypes.DeviceChainKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if s.deviceKeystore == nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
}
md, err := s.deviceKeystore.memberDeviceForGroup(group)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
groupPublicKey, err := group.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
s.messageMutex.Lock()
defer s.messageMutex.Unlock()
ds, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, md.Device())
if errcode.Is(err, errcode.ErrCode_ErrMissingInput) {
// If secret does not exist, create it
deviceChainKey, err := newDeviceChainKey()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
if err = s.registerChainKey(ctx, group, md.Device(), deviceChainKey, true); err != nil {
return nil, errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
return deviceChainKey, nil
}
if err != nil {
return nil, errcode.ErrCode_ErrMessageKeyPersistenceGet.Wrap(err)
}
return ds, nil
}
// RegisterChainKey registers a chain key for the given group and device.
// If the device chain key is not from the current device, the function will
// precompute and store in the cache namespace the next message keys.
// It is the exported version of registerChainKey.
func (s *secretStore) RegisterChainKey(ctx context.Context, group *protocoltypes.Group, senderDevicePublicKey crypto.PubKey, encryptedDeviceChainKey []byte) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if s.deviceKeystore == nil {
return errcode.ErrCode_ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
}
localMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
if err != nil {
return errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
deviceChainKey, err := decryptDeviceChainKey(encryptedDeviceChainKey, group, localMemberDevice.member, senderDevicePublicKey)
if err != nil {
return errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
hasSecretBeenSentByCurrentDevice := localMemberDevice.Member().Equals(senderDevicePublicKey)
return s.registerChainKey(ctx, group, senderDevicePublicKey, deviceChainKey, hasSecretBeenSentByCurrentDevice)
}
// registerChainKey registers a chain key for the given group and device.
// If the chain key is not from the current device, the function will
// precompute and store in the cache namespace the next message keys.
func (s *secretStore) registerChainKey(ctx context.Context, group *protocoltypes.Group, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey, isCurrentDeviceChainKey bool) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
groupPublicKey, err := group.GetPubKey()
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if _, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey); err == nil {
// Device is already registered, ignore it
s.logger.Debug("device already registered in group",
logutil.PrivateBinary("devicePublicKey", logutil.CryptoKeyToBytes(devicePublicKey)),
logutil.PrivateBinary("groupPublicKey", logutil.CryptoKeyToBytes(groupPublicKey)),
)
return nil
}
s.logger.Debug("registering chain key",
logutil.PrivateBinary("devicePublicKey", logutil.CryptoKeyToBytes(devicePublicKey)),
logutil.PrivateBinary("groupPublicKey", logutil.CryptoKeyToBytes(groupPublicKey)),
)
// If own Device store key as is, no need to precompute future keys
if isCurrentDeviceChainKey {
if err := s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
return nil
}
s.messageMutex.Lock()
if deviceChainKey, err = s.preComputeKeys(ctx, devicePublicKey, groupPublicKey, deviceChainKey); err != nil {
s.messageMutex.Unlock()
return errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
if err := s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
s.messageMutex.Unlock()
return errcode.ErrCode_ErrInternal.Wrap(err)
}
s.messageMutex.Unlock()
devicePublicKeyBytes, err := devicePublicKey.Raw()
if err == nil {
if err := s.UpdateOutOfStoreGroupReferences(ctx, devicePublicKeyBytes, deviceChainKey.Counter, group); err != nil {
s.logger.Error("updating out of store group references failed", zap.Error(err))
}
}
return nil
}
// preComputeKeys precomputes the next m.preComputedKeysCount keys for the given device and group and put them in the cache namespace.
func (s *secretStore) preComputeKeys(ctx context.Context, devicePublicKey crypto.PubKey, groupPublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) (*protocoltypes.DeviceChainKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
chainKeyValue := deviceChainKey.ChainKey
counter := deviceChainKey.Counter
groupPublicKeyBytes, err := groupPublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
knownDeviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
if err != nil && !errcode.Is(err, errcode.ErrCode_ErrMissingInput) {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
var preComputedKeys []computedMessageKey
for i := 0; i < s.getPrecomputedKeyExpectedCount(); i++ {
counter++
knownMK, err := s.getPrecomputedMessageKey(ctx, groupPublicKey, devicePublicKey, counter)
if err != nil && !errcode.Is(err, errcode.ErrCode_ErrMissingInput) {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
newChainKeyValue, mk, err := deriveNextKeys(chainKeyValue, nil, groupPublicKeyBytes)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
chainKeyValue = newChainKeyValue
if knownMK != nil && knownDeviceChainKey != nil {
if knownDeviceChainKey.Counter != counter-1 {
continue
}
}
preComputedKeys = append(preComputedKeys, computedMessageKey{counter, &mk})
}
err = s.putPrecomputedKeys(ctx, groupPublicKey, devicePublicKey, preComputedKeys)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return &protocoltypes.DeviceChainKey{
Counter: counter,
ChainKey: chainKeyValue,
}, nil
}
// getPrecomputedKeyExpectedCount returns the number of precomputed keys that
// should be in the cache namespace of the keystore.
func (s *secretStore) getPrecomputedKeyExpectedCount() int {
if s == nil || s.preComputedKeysCount < 0 {
return 0
}
return s.preComputedKeysCount
}
// preComputeNextKey precomputes the next key for the given group and device and adds it to the cache namespace.
func (s *secretStore) preComputeNextKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey) (*protocoltypes.DeviceChainKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if devicePublicKey == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("devicePublicKey cannot be nil"))
}
groupPublicKeyBytes, err := groupPublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
ds, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
newCounter := ds.Counter + 1
// TODO: Salt?
newCK, mk, err := deriveNextKeys(ds.ChainKey, nil, groupPublicKeyBytes)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
err = s.putPrecomputedKeys(ctx, groupPublicKey, devicePublicKey, []computedMessageKey{{newCounter, &mk}})
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return &protocoltypes.DeviceChainKey{
Counter: newCounter,
ChainKey: newCK,
}, nil
}
// getPrecomputedMessageKey returns the precomputed message key put in the cache
// namespace for the given group and device at the given counter.
func (s *secretStore) getPrecomputedMessageKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, counter uint64) (*messageKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
deviceRaw, err := devicePublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
groupRaw, err := groupPublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, counter)
key, err := s.datastore.Get(ctx, id)
if err == datastore.ErrNotFound {
return nil, errcode.ErrCode_ErrMissingInput.Wrap(fmt.Errorf("key for message does not exist in datastore"))
}
if err != nil {
return nil, errcode.ErrCode_ErrMessageKeyPersistenceGet.Wrap(err)
}
keyArray, err := cryptoutil.KeySliceToArray(key)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return (*messageKey)(keyArray), nil
}
// putPrecomputedKeys puts the given precomputed keys in the cache namespace.
// It will try to use a batch if the store supports it.
func (s *secretStore) putPrecomputedKeys(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, preComputedMessageKeys []computedMessageKey) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
s.logger.Debug("putting precomputed keys", zap.Int("count", len(preComputedMessageKeys)))
if len(preComputedMessageKeys) == 0 {
return nil
}
deviceRaw, err := devicePublicKey.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
groupRaw, err := groupPublicKey.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
if batchedDatastore, ok := s.datastore.(datastore.BatchingFeature); ok {
batch, err := batchedDatastore.Batch(ctx)
if err == datastore.ErrBatchUnsupported {
return s.putPrecomputedKeysNonBatched(ctx, groupRaw, deviceRaw, preComputedMessageKeys)
}
return s.putPrecomputedKeysBatched(ctx, batch, groupRaw, deviceRaw, preComputedMessageKeys)
}
return s.putPrecomputedKeysNonBatched(ctx, groupRaw, deviceRaw, preComputedMessageKeys)
}
func (s *secretStore) putPrecomputedKeysBatched(ctx context.Context, batch datastore.Batch, groupRaw []byte, deviceRaw []byte, preComputedMessageKeys []computedMessageKey) error {
for _, preComputedKey := range preComputedMessageKeys {
id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, preComputedKey.counter)
if err := batch.Put(ctx, id, preComputedKey.messageKey[:]); err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
}
if err := batch.Commit(ctx); err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
return nil
}
func (s *secretStore) putPrecomputedKeysNonBatched(ctx context.Context, groupRaw []byte, deviceRaw []byte, preComputedMessageKeys []computedMessageKey) error {
for _, preComputedKey := range preComputedMessageKeys {
id := dsKeyForPrecomputedMessageKey(groupRaw, deviceRaw, preComputedKey.counter)
if err := s.datastore.Put(ctx, id, preComputedKey.messageKey[:]); err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
}
return nil
}
// putKeyForCID puts the given message key in the datastore for a specified CID.
func (s *secretStore) putKeyForCID(ctx context.Context, messageCID cid.Cid, messageKey *messageKey) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if !messageCID.Defined() {
return nil
}
err := s.datastore.Put(ctx, dsKeyForMessageKeyByCID(messageCID), messageKey[:])
if err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
return nil
}
// OpenEnvelopePayload opens the payload of a message envelope and returns the
// decrypted message in its EncryptedMessage form.
// It also performs post decryption actions such as updating message key cache.
func (s *secretStore) OpenEnvelopePayload(ctx context.Context, msgEnvelope *protocoltypes.MessageEnvelope, msgHeaders *protocoltypes.MessageHeaders, groupPublicKey crypto.PubKey, ownDevicePublicKey crypto.PubKey, msgCID cid.Cid) (*protocoltypes.EncryptedMessage, error) {
s.messageMutex.Lock()
defer s.messageMutex.Unlock()
msgBytes, decryptionCtx, err := s.openPayload(ctx, msgCID, groupPublicKey, msgEnvelope.Message, msgHeaders)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoDecryptPayload.Wrap(err)
}
if err := s.postDecryptActions(ctx, decryptionCtx, groupPublicKey, ownDevicePublicKey, msgHeaders); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
var msg protocoltypes.EncryptedMessage
err = proto.Unmarshal(msgBytes, &msg)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return &msg, nil
}
// openPayload opens the payload of a message envelope and returns the
// decrypted message.
// It retrieves the message key from the keystore or the cache to decrypt
// the message.
func (s *secretStore) openPayload(ctx context.Context, msgCID cid.Cid, groupPublicKey crypto.PubKey, payload []byte, msgHeaders *protocoltypes.MessageHeaders) ([]byte, *decryptionContext, error) {
if s == nil {
return nil, nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
var (
err error
decryptionCtx = &decryptionContext{
cid: msgCID,
newlyDecrypted: true,
}
publicKey crypto.PubKey
)
if decryptionCtx.messageKey, err = s.getKeyForCID(ctx, msgCID); err == nil {
decryptionCtx.newlyDecrypted = false
} else {
publicKey, err = crypto.UnmarshalEd25519PublicKey(msgHeaders.DevicePk)
if err != nil {
return nil, nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
decryptionCtx.messageKey, err = s.getPrecomputedMessageKey(ctx, groupPublicKey, publicKey, msgHeaders.Counter)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
}
return s.openPayloadWithMessageKey(decryptionCtx, publicKey, payload, msgHeaders)
}
// openPayloadWithMessageKey opens the payload of a message envelope with the
// given key and returns the decrypted message with the decryptionContext
// struct.
func (s *secretStore) openPayloadWithMessageKey(decryptionCtx *decryptionContext, devicePublicKey crypto.PubKey, payload []byte, headers *protocoltypes.MessageHeaders) ([]byte, *decryptionContext, error) {
msg, ok := secretbox.Open(nil, payload, uint64AsNonce(headers.Counter), (*[32]byte)(decryptionCtx.messageKey))
if !ok {
return nil, nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(fmt.Errorf("secret box failed to open message payload"))
}
if decryptionCtx.newlyDecrypted {
if ok, err := devicePublicKey.Verify(msg, headers.Sig); !ok {
return nil, nil, errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
} else if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
}
// Message was newly decrypted, we can save the message key and derive
// future keys if necessary.
return msg, decryptionCtx, nil
}
// getKeyForCID retrieves the message key for the given message CID.
func (s *secretStore) getKeyForCID(ctx context.Context, msgCID cid.Cid) (*messageKey, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if !msgCID.Defined() {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("undefined message CID"))
}
msgKey, err := s.datastore.Get(ctx, dsKeyForMessageKeyByCID(msgCID))
if err == datastore.ErrNotFound {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
msgKeyArray, err := cryptoutil.KeySliceToArray(msgKey)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return (*messageKey)(msgKeyArray), nil
}
// putDeviceChainKey stores the chain key for the given group and device.
func (s *secretStore) putDeviceChainKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
deviceChainKeyBytes, err := proto.Marshal(deviceChainKey)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
datastoreKey, err := dsKeyForCurrentChainKey(groupPublicKey, devicePublicKey)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
err = s.datastore.Put(ctx, datastoreKey, deviceChainKeyBytes)
if err != nil {
return errcode.ErrCode_ErrMessageKeyPersistencePut.Wrap(err)
}
return nil
}
// SealEnvelope encrypts the given payload and returns it as an envelope to be
// published on the group's store.
// It retrieves the device's chain key from the keystore to encrypt the payload
// using symmetric encryption. The payload is signed using the device's long
// term private key for the target group. It also updates the chain key and
// stores the next message key in the cache.
func (s *secretStore) SealEnvelope(ctx context.Context, group *protocoltypes.Group, messagePayload []byte) ([]byte, error) {
if s == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if s.deviceKeystore == nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(fmt.Errorf("message keystore is opened in read-only mode"))
}
if group == nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("group cannot be nil"))
}
localMemberDevice, err := s.deviceKeystore.memberDeviceForGroup(group)
if err != nil {
return nil, errcode.ErrCode_ErrGroupMemberUnknownGroupID.Wrap(err)
}
groupPublicKey, err := group.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
s.messageMutex.Lock()
defer s.messageMutex.Unlock()
deviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, localMemberDevice.Device())
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to get device chainkey: %w", err))
}
env, err := sealEnvelope(messagePayload, deviceChainKey, localMemberDevice.device, group)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoEncrypt.Wrap(fmt.Errorf("unable to seal envelope: %w", err))
}
if err := s.deriveDeviceChainKey(ctx, group, localMemberDevice.Device()); err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return env, nil
}
// deriveDeviceChainKey derives the chain key value from the current one.
// It also updates the device chain key in the keystore.
func (s *secretStore) deriveDeviceChainKey(ctx context.Context, group *protocoltypes.Group, devicePublicKey crypto.PubKey) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if devicePublicKey == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("device public key cannot be nil"))
}
groupPublicKey, err := group.GetPubKey()
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
deviceChainKey, err := s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey)
if err != nil {
return errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
if err = s.updateCurrentKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
return errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return nil
}
// updateCurrentKey updates the current device chain key in the keystore if the
// given device secret has a higher counter.
func (s *secretStore) updateCurrentKey(ctx context.Context, groupPublicKey crypto.PubKey, devicePublicKey crypto.PubKey, deviceChainKey *protocoltypes.DeviceChainKey) error {
if s == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
currentDeviceChainKey, err := s.getDeviceChainKeyForGroupAndDevice(ctx, groupPublicKey, devicePublicKey)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
// FIXME: counter is set randomly and can overflow to 0
if deviceChainKey.Counter < currentDeviceChainKey.Counter {
return nil
}
if err = s.putDeviceChainKey(ctx, groupPublicKey, devicePublicKey, deviceChainKey); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
return nil
}
// OutOfStoreMessageOpen opens the given OutOfStoreMessage and returns the
// decrypted payload.
// The signature is verified against the given groupPublicKey.
// It derives the next message key and stores it in the cache, but it doesn't
// update the device's chain key.
func (s *secretStore) OutOfStoreMessageOpen(ctx context.Context, envelope *protocoltypes.OutOfStoreMessage, groupPublicKey crypto.PubKey) ([]byte, bool, error) {
if s == nil {
return nil, false, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("calling method of a non instantiated message keystore"))
}
if envelope == nil {
return nil, false, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("envelope cannot be nil"))
}
if groupPublicKey == nil {
return nil, false, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("group public key cannot be nil"))
}
devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(envelope.DevicePk)
if err != nil {
return nil, false, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
c := cid.Undef
if len(envelope.Cid) > 0 {
_, c, err = cid.CidFromBytes(envelope.Cid)
if err != nil {
return nil, false, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
}
s.messageMutex.Lock()
defer s.messageMutex.Unlock()
decryptionCtx := &decryptionContext{newlyDecrypted: true}
if decryptionCtx.messageKey, err = s.getKeyForCID(ctx, c); err == nil {
decryptionCtx.newlyDecrypted = false
} else {
decryptionCtx.messageKey, err = s.getPrecomputedMessageKey(ctx, groupPublicKey, devicePublicKey, envelope.Counter)
if err != nil {
return nil, false, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
}
clear, decryptionCtx, err := s.openPayloadWithMessageKey(decryptionCtx, devicePublicKey, envelope.EncryptedPayload, &protocoltypes.MessageHeaders{
Counter: envelope.Counter,
DevicePk: envelope.DevicePk,
Sig: envelope.Sig,
})
if err != nil {
return nil, false, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
if ok, err := devicePublicKey.Verify(clear, envelope.Sig); !ok {
return nil, false, errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(fmt.Errorf("unable to verify message signature"))
} else if err != nil {
return nil, false, errcode.ErrCode_ErrCryptoSignatureVerification.Wrap(err)
}
if _, err = s.preComputeNextKey(ctx, groupPublicKey, devicePublicKey); err != nil {
return nil, false, errcode.ErrCode_ErrInternal.Wrap(err)
}
return clear, decryptionCtx.newlyDecrypted, nil
}
// OutOfStoreGetGroupPublicKeyByGroupReference returns the group public key
// associated with the given out of store group reference (e.g. push
// notification payload).
func (s *secretStore) OutOfStoreGetGroupPublicKeyByGroupReference(ctx context.Context, ref []byte) (crypto.PubKey, error) {
s.messageMutex.RLock()
pk, err := s.datastore.Get(ctx, dsKeyForOutOfStoreMessageGroupHint(ref))
s.messageMutex.RUnlock()
if err != nil {
return nil, errcode.ErrCode_ErrNotFound.Wrap(err)
}
groupPublicKey, err := crypto.UnmarshalEd25519PublicKey(pk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return groupPublicKey, nil
}
// UpdateOutOfStoreGroupReferences updates the out of store (e.g. push
// notification payload) group references for the given devicePublicKey and
// groupPublicKey in the keystore. It creates the references for the
// given range [first + precomputeOutOfStoreGroupRefsCount] and
// [first - precomputeOutOfStoreGroupRefsCount] and deletes out of range
// references.
func (s *secretStore) UpdateOutOfStoreGroupReferences(ctx context.Context, devicePublicKey []byte, first uint64, group *protocoltypes.Group) error {
s.messageMutex.Lock()
defer s.messageMutex.Unlock()
refsExisting := []uint64(nil)
refsToCreate := []uint64(nil)
currentFirst, currentLast, err := s.firstLastCachedGroupRefsForMember(ctx, devicePublicKey, group)
if err == nil {
for i := currentFirst; i != currentLast; i++ {
refsExisting = append(refsExisting, i)
}
}
// keep previous refs
last := first + s.precomputeOutOfStoreGroupRefsCount
first -= s.precomputeOutOfStoreGroupRefsCount
for i := first; i != last; i++ {
found := false
// Ignore refs that should be kept
for j := 0; j < len(refsExisting); j++ {
if refsExisting[j] == i {
refsExisting[j] = refsExisting[len(refsExisting)-1]
refsExisting = refsExisting[:len(refsExisting)-1]
found = true
break
}
}
if !found {
refsToCreate = append(refsToCreate, i)
}
}
// Remove useless old refs
for i := 0; i < len(refsExisting); i++ {
ref, err := createOutOfStoreGroupReference(group, devicePublicKey, refsExisting[i])
if err != nil {
s.logger.Error("creating existing out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
continue
}
if err := s.datastore.Delete(ctx, dsKeyForOutOfStoreMessageGroupHint(ref)); err != nil {
s.logger.Error("deleting existing out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
continue
}
}
// Add new refs
for i := 0; i < len(refsToCreate); i++ {
ref, err := createOutOfStoreGroupReference(group, devicePublicKey, refsToCreate[i])
if err != nil {
s.logger.Error("creating new out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
continue
}
if err := s.datastore.Put(ctx, dsKeyForOutOfStoreMessageGroupHint(ref), group.GetPublicKey()); err != nil {
s.logger.Error("putting new out of store group reference failed", logutil.PrivateBinary("ref", ref), zap.Error(err))
continue
}
}
// Update first/last
if err := s.putFirstLastCachedGroupRefsForMember(ctx, first, last, devicePublicKey, group); err != nil {
s.logger.Error("putting first/last out of store group reference failed", zap.Error(err))
}
return nil
}
// firstLastCachedGroupRefsForMember returns the first and last cached group
// references counter for the given devicePublicKey and group.
func (s *secretStore) firstLastCachedGroupRefsForMember(ctx context.Context, devicePublicKeyBytes []byte, group *protocoltypes.Group) (uint64, uint64, error) {
key := dsKeyForOutOfStoreFirstLastCounters(group.GetPublicKey(), devicePublicKeyBytes)
// No mutex here
bytes, err := s.datastore.Get(ctx, key)
if err != nil {
return 0, 0, errcode.ErrCode_ErrDBRead.Wrap(err)
}
ret := protocoltypes.FirstLastCounters{}
if err := proto.Unmarshal(bytes, &ret); err != nil {
return 0, 0, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return ret.First, ret.Last, nil
}
// putFirstLastCachedGroupRefsForMember puts the first and last cached group
// references counter for the given devicePK and groupPK.
func (s *secretStore) putFirstLastCachedGroupRefsForMember(ctx context.Context, first uint64, last uint64, devicePublicKey []byte, group *protocoltypes.Group) error {
key := dsKeyForOutOfStoreFirstLastCounters(group.GetPublicKey(), devicePublicKey)
fistLast := protocoltypes.FirstLastCounters{
First: first,
Last: last,
}
bytes, err := proto.Marshal(&fistLast)
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
// Not mutex here
return s.datastore.Put(ctx, key, bytes)
}
func sealPayload(payload []byte, ds *protocoltypes.DeviceChainKey, devicePrivateKey crypto.PrivKey, g *protocoltypes.Group) ([]byte, []byte, error) {
var (
msgKey [32]byte
err error
)
sig, err := devicePrivateKey.Sign(payload)
if err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
if _, msgKey, err = deriveNextKeys(ds.ChainKey, nil, g.GetPublicKey()); err != nil {
return nil, nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return secretbox.Seal(nil, payload, uint64AsNonce(ds.Counter+1), &msgKey), sig, nil
}
func sealEnvelope(messagePayload []byte, deviceChainKey *protocoltypes.DeviceChainKey, devicePrivateKey crypto.PrivKey, g *protocoltypes.Group) ([]byte, error) {
encryptedPayload, sig, err := sealPayload(messagePayload, deviceChainKey, devicePrivateKey, g)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoEncrypt.Wrap(err)
}
devicePublicKeyRaw, err := devicePrivateKey.GetPublic().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
h := &protocoltypes.MessageHeaders{
Counter: deviceChainKey.Counter + 1,
DevicePk: devicePublicKeyRaw,
Sig: sig,
}
headers, err := proto.Marshal(h)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
nonce, err := cryptoutil.GenerateNonce()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoNonceGeneration.Wrap(err)
}
encryptedHeaders := secretbox.Seal(nil, headers, nonce, g.GetSharedSecret())
env, err := proto.Marshal(&protocoltypes.MessageEnvelope{
MessageHeaders: encryptedHeaders,
Message: encryptedPayload,
Nonce: nonce[:],
})
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
return env, nil
}
// nolint:unparam
func deriveNextKeys(chainKeyValue []byte, salt []byte, groupID []byte) ([]byte, messageKey, error) {
var (
nextMsg [32]byte
err error
)
// Salt length must be equal to hash length (64 bytes for sha256)
hash := sha256.New
// Generate Pseudo Random Key using chainKeyValue as IKM and salt
prk := hkdf.Extract(hash, chainKeyValue, salt)
if len(prk) == 0 {
return nil, nextMsg, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to instantiate pseudo random key"))
}
// Expand using extracted prk and groupID as info (kind of namespace)
kdf := hkdf.Expand(hash, prk, groupID)
// Generate next KDF and message keys
nextCK, err := io.ReadAll(io.LimitReader(kdf, 32))
if err != nil {
return nil, nextMsg, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
nextMsgSlice, err := io.ReadAll(io.LimitReader(kdf, 32))
if err != nil {
return nil, nextMsg, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
copy(nextMsg[:], nextMsgSlice)
return nextCK, nextMsg, nil
}
func uint64AsNonce(val uint64) *[24]byte {
var nonce [24]byte
binary.BigEndian.PutUint64(nonce[:], val)
return &nonce
}
================================================
FILE: pkg/secretstore/secret_store_messages_test.go
================================================
package secretstore_test
import (
"context"
"fmt"
"os"
"path"
"testing"
"time"
cid "github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
)
func addDummyMemberInMetadataStore(ctx context.Context, t testing.TB, ms *weshnet.MetadataStore, g *protocoltypes.Group, memberPK crypto.PubKey, join bool) crypto.PubKey {
t.Helper()
secretStore, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, secretStore)
md, err := secretStore.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
if join {
_, err = weshnet.MetadataStoreAddDeviceToGroup(ctx, ms, g, md)
assert.NoError(t, err)
}
deviceChainKeyToSend, err := secretStore.GetShareableChainKey(ctx, g, memberPK)
assert.NoError(t, err)
_, err = weshnet.MetadataStoreSendSecret(ctx, ms, g, md, memberPK, deviceChainKeyToSend)
assert.NoError(t, err)
return md.Device()
}
func Test_EncryptMessageEnvelope(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, _, err := weshnet.NewGroupMultiMember()
assert.NoError(t, err)
secretStore1, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, secretStore1)
t.Cleanup(func() {
_ = secretStore1.Close()
})
omd1, err := secretStore1.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
gc1 := weshnet.NewContextGroup(g, nil, nil, secretStore1, omd1, nil)
deviceChainKey1For1, err := secretStore1.GetShareableChainKey(ctx, g, gc1.MemberPubKey())
assert.NoError(t, err)
err = secretStore1.RegisterChainKey(ctx, g, gc1.DevicePubKey(), deviceChainKey1For1)
assert.NoError(t, err)
secretStore2, err := secretstore.NewInMemSecretStore(nil)
assert.NoError(t, err)
assert.NotNil(t, secretStore2)
t.Cleanup(func() {
_ = secretStore2.Close()
})
omd2, err := secretStore2.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
payloadRef1, err := proto.Marshal(&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")})
assert.NoError(t, err)
deviceChainKey1For2, err := secretStore1.GetShareableChainKey(ctx, g, omd2.Member())
assert.NoError(t, err)
deviceChainKey2For2, err := secretStore2.GetShareableChainKey(ctx, g, omd2.Member())
assert.NoError(t, err)
err = secretStore2.RegisterChainKey(ctx, g, omd2.Device(), deviceChainKey2For2)
assert.NoError(t, err)
err = secretStore2.RegisterChainKey(ctx, g, omd1.Device(), deviceChainKey1For2)
assert.NoError(t, err)
env1, err := secretStore1.SealEnvelope(ctx, g, payloadRef1)
assert.NoError(t, err)
headers, payloadClr1, err := openEnvelope(ctx, t, secretStore2, g, omd2.Device(), env1, cid.Undef)
assert.NoError(t, err)
devRaw, err := omd1.Device().Raw()
assert.Equal(t, headers.DevicePk, devRaw)
payloadClrlBytes, err := proto.Marshal(payloadClr1)
assert.NoError(t, err)
assert.Equal(t, payloadRef1, payloadClrlBytes)
}
func testMessageKeyHolderCatchUp(t *testing.T, expectedNewDevices int, isSlow bool) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if isSlow {
testutil.FilterSpeed(t, testutil.Slow)
}
dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderCatchUp")
defer os.RemoveAll(dir)
peers, _, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
defer cleanup()
peer := peers[0]
peer.GC.ActivateGroupContext(nil)
secretStore1 := peer.SecretStore
ms1 := peer.GC.MetadataStore()
groupPublicKey, err := peer.GC.Group().GetPubKey()
assert.NoError(t, err)
devicesPK := make([]crypto.PubKey, expectedNewDevices)
for i := 0; i < expectedNewDevices; i++ {
devicesPK[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
}
for i, devicePublicKey := range devicesPK {
select {
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for device secret")
case <-peer.GC.WaitForDeviceAdded(ctx, devicePublicKey):
}
if !assert.True(t, secretStore1.IsChainKeyKnownForDevice(ctx, groupPublicKey, devicePublicKey)) {
t.Fatalf("failed at iteration %d", i)
}
}
}
func TestMessageKeyHolderCatchUp(t *testing.T) {
for _, testCase := range []struct {
expectedNewDevices int
slow bool
}{
{
expectedNewDevices: 2,
slow: false,
},
{
expectedNewDevices: 10,
slow: true,
},
} {
testMessageKeyHolderCatchUp(t, testCase.expectedNewDevices, testCase.slow)
}
}
func testMessageKeyHolderSubscription(t *testing.T, expectedNewDevices int, isSlow bool) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if isSlow {
testutil.FilterSpeed(t, testutil.Slow)
}
dir := path.Join(os.TempDir(), fmt.Sprintf("%d", os.Getpid()), "MessageKeyHolderSubscription")
defer os.RemoveAll(dir)
peers, groupPrivateKey, cleanup := weshnet.CreatePeersWithGroupTest(ctx, t, dir, 1, 1)
defer cleanup()
peer := peers[0]
peer.GC.ActivateGroupContext(nil)
secretStore1 := peer.SecretStore
ms1 := peer.GC.MetadataStore()
devicesPK := make([]crypto.PubKey, expectedNewDevices)
for i := 0; i < expectedNewDevices; i++ {
devicesPK[i] = addDummyMemberInMetadataStore(ctx, t, ms1, peer.GC.Group(), peer.GC.MemberPubKey(), true)
}
for i, devicePublicKey := range devicesPK {
select {
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for device secret")
case <-peer.GC.WaitForDeviceAdded(ctx, devicePublicKey):
}
if !assert.True(t, secretStore1.IsChainKeyKnownForDevice(ctx, groupPrivateKey.GetPublic(), devicePublicKey)) {
t.Fatalf("failed at iteration %d", i)
}
}
}
func TestMessageKeyHolderSubscription(t *testing.T) {
for _, testCase := range []struct {
expectedNewDevices int
slow bool
}{
{
expectedNewDevices: 2,
slow: false,
},
{
expectedNewDevices: 10,
slow: true,
},
} {
testMessageKeyHolderSubscription(t, testCase.expectedNewDevices, testCase.slow)
}
}
// openEnvelope opens a MessageEnvelope and returns the decrypted message.
// It performs all the necessary steps to decrypt the message.
func openEnvelope(ctx context.Context, t testing.TB, secretStore secretstore.SecretStore, g *protocoltypes.Group, ownPK crypto.PubKey, data []byte, id cid.Cid) (*protocoltypes.MessageHeaders, *protocoltypes.EncryptedMessage, error) {
t.Helper()
assert.NotNil(t, secretStore)
assert.NotNil(t, g)
env, headers, err := secretStore.OpenEnvelopeHeaders(data, g)
assert.NoError(t, err)
gPK, err := g.GetPubKey()
assert.NoError(t, err)
msg, err := secretStore.OpenEnvelopePayload(ctx, env, headers, gPK, ownPK, id)
assert.NoError(t, err)
return headers, msg, nil
}
================================================
FILE: pkg/secretstore/secret_store_test.go
================================================
package secretstore
import (
"context"
crand "crypto/rand"
"encoding/hex"
"fmt"
"testing"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func Test_PushGroupReferences(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, _, err := protocoltypes.NewGroupMultiMember()
require.NoError(t, err)
otherSecretStore, err := newInMemSecretStore(nil)
require.NoError(t, err)
t.Cleanup(func() {
_ = otherSecretStore.Close()
})
ownSecretStore, err := newInMemSecretStore(nil)
require.NoError(t, err)
t.Cleanup(func() {
_ = ownSecretStore.Close()
})
otherMemberDevice, err := otherSecretStore.GetOwnMemberDeviceForGroup(g)
require.NoError(t, err)
otherDevicePK, err := otherMemberDevice.Device().Raw()
require.NoError(t, err)
deviceChainKey, err := newDeviceChainKey()
require.NoError(t, err)
// test with the deviceChainKey counter
updateAndTestPushGroupReferences(ctx, ownSecretStore, otherDevicePK, deviceChainKey.Counter, g, t)
// do the same test with a new device chain key counter,
// so we can test if old references are deleted
updateAndTestPushGroupReferences(ctx, ownSecretStore, otherDevicePK, deviceChainKey.Counter+10, g, t)
}
func updateAndTestPushGroupReferences(ctx context.Context, secretStore *secretStore, devicePK []byte, counter uint64, g *protocoltypes.Group, t *testing.T) {
// update the push group references
err := secretStore.UpdateOutOfStoreGroupReferences(ctx, devicePK, counter, g)
require.NoError(t, err)
// test that the push group references are updated
// refs start counter - 100 to counter + 100
start := counter - PrecomputeOutOfStoreGroupRefsCount
end := counter + PrecomputeOutOfStoreGroupRefsCount
for i := start; i < end; i++ {
// compute the push group reference
pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, i)
require.NoError(t, err)
_, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
require.NoError(t, err, fmt.Sprintf("started at %d, failed as %d", start, i))
}
// test boundary conditions
// before the start counter
{
before := counter - PrecomputeOutOfStoreGroupRefsCount - 1
pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, before)
require.NoError(t, err)
_, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
require.Error(t, err)
}
// after the end counter
{
end := counter + PrecomputeOutOfStoreGroupRefsCount + 1
pushGroupRef, err := createOutOfStoreGroupReference(g, devicePK, end)
require.NoError(t, err)
_, err = secretStore.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, pushGroupRef)
require.Error(t, err)
}
}
func Test_SealOutOfStoreMessageEnvelope_OpenOutOfStoreMessage(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, _, err := protocoltypes.NewGroupMultiMember()
require.NoError(t, err)
accUnrelated, err := newInMemSecretStore(nil)
require.NoError(t, err)
require.NotNil(t, accUnrelated)
t.Cleanup(func() {
_ = accUnrelated.Close()
})
err = accUnrelated.PutGroup(ctx, g)
require.NoError(t, err)
acc1, err := newInMemSecretStore(nil)
require.NoError(t, err)
t.Cleanup(func() {
_ = acc1.Close()
})
acc2, err := newInMemSecretStore(nil)
require.NoError(t, err)
t.Cleanup(func() {
_ = acc1.Close()
})
memberDevice1ForGroup, err := acc1.GetOwnMemberDeviceForGroup(g)
require.NoError(t, err)
memberDevice2ForGroup, err := acc2.GetOwnMemberDeviceForGroup(g)
require.NoError(t, err)
deviceChainKey1For2, err := acc1.GetShareableChainKey(ctx, g, memberDevice2ForGroup.Member())
require.NoError(t, err)
testPayload := []byte("test payload")
err = acc2.RegisterChainKey(ctx, g, memberDevice1ForGroup.Device(), deviceChainKey1For2)
require.NoError(t, err)
envEncrypted, err := acc1.SealEnvelope(ctx, g, testPayload)
require.NoError(t, err)
env, headers, err := ((*secretStore)(nil)).OpenEnvelopeHeaders(envEncrypted, g)
require.NoError(t, err)
outOfStoreEnv, err := (*secretStore)(nil).SealOutOfStoreMessageEnvelope(cid.Undef, env, headers, g)
require.NoError(t, err)
groupPublicKey, err := acc2.OutOfStoreGetGroupPublicKeyByGroupReference(ctx, outOfStoreEnv.GroupReference)
require.NoError(t, err)
outOfStoreMessage, err := accUnrelated.decryptOutOfStoreMessageEnv(ctx, outOfStoreEnv, groupPublicKey)
require.NoError(t, err)
payload, newlyDecrypted, err := acc2.OutOfStoreMessageOpen(ctx, outOfStoreMessage, groupPublicKey)
require.NoError(t, err)
require.True(t, newlyDecrypted)
require.Equal(t, testPayload, payload)
}
func Test_OutOfStoreDeserialize(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
secretStore1, err := NewSecretStore(datastore.NewMapDatastore(), nil)
require.NoError(t, err)
t.Cleanup(func() { _ = secretStore1.Close() })
secretStore2, err := NewSecretStore(datastore.NewMapDatastore(), nil)
require.NoError(t, err)
t.Cleanup(func() { _ = secretStore2.Close() })
group, _, err := protocoltypes.NewGroupMultiMember()
require.NoError(t, err)
require.NoError(t, secretStore1.PutGroup(ctx, group))
require.NoError(t, secretStore2.PutGroup(ctx, group))
memberDevice1, err := secretStore1.GetOwnMemberDeviceForGroup(group)
require.NoError(t, err)
memberDevice2, err := secretStore2.GetOwnMemberDeviceForGroup(group)
require.NoError(t, err)
chainKey1For2, err := secretStore1.GetShareableChainKey(ctx, group, memberDevice2.Member())
require.NoError(t, err)
chainKey2For1, err := secretStore2.GetShareableChainKey(ctx, group, memberDevice1.Member())
require.NoError(t, err)
require.NoError(t, secretStore1.RegisterChainKey(ctx, group, memberDevice2.Device(), chainKey2For1))
require.NoError(t, secretStore2.RegisterChainKey(ctx, group, memberDevice1.Device(), chainKey1For2))
testPayload := []byte("test payload")
env, err := secretStore1.SealEnvelope(ctx, group, testPayload)
require.NoError(t, err)
envHeaders, msgHeaders, err := secretStore1.OpenEnvelopeHeaders(env, group)
require.NoError(t, err)
dummyCID, err := cid.Parse("QmNR2n4zywCV61MeMLB6JwPueAPqheqpfiA4fLPMxouEmQ")
require.NoError(t, err)
device1Raw, err := memberDevice1.Device().Raw()
require.NoError(t, err)
outOfStoreMessageEnvelope, err := secretStore1.SealOutOfStoreMessageEnvelope(dummyCID, envHeaders, msgHeaders, group)
require.NoError(t, err)
outOfStoreMessageEnvelopeBytes, err := proto.Marshal(outOfStoreMessageEnvelope)
require.NoError(t, err)
// Attempting to decrypt the message without a relay
{
openedOutOfStoreMessage, groupFound, clearPayload, alreadyDecrypted, err := secretStore2.OpenOutOfStoreMessage(ctx, outOfStoreMessageEnvelopeBytes)
require.NoError(t, err)
require.Equal(t, testPayload, clearPayload)
require.Equal(t, device1Raw, openedOutOfStoreMessage.DevicePk)
require.Equal(t, dummyCID.Bytes(), openedOutOfStoreMessage.Cid)
require.Equal(t, group.PublicKey, groupFound.PublicKey)
require.False(t, alreadyDecrypted)
}
}
func Test_EncryptMessageEnvelopeAndDerive(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
g, _, err := protocoltypes.NewGroupMultiMember()
assert.NoError(t, err)
mkh1, err := newInMemSecretStore(nil)
assert.NoError(t, err)
t.Cleanup(func() {
_ = mkh1.Close()
})
mkh2, err := newInMemSecretStore(nil)
assert.NoError(t, err)
t.Cleanup(func() {
_ = mkh1.Close()
})
omd1, err := mkh1.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
omd2, err := mkh2.GetOwnMemberDeviceForGroup(g)
assert.NoError(t, err)
gPK, err := g.GetPubKey()
assert.NoError(t, err)
gc1DevicePubKey := omd1.Device()
ds1For1Encrypted, err := mkh1.GetShareableChainKey(ctx, g, omd1.Member())
assert.NoError(t, err)
ds1For2Encrypted, err := mkh1.GetShareableChainKey(ctx, g, omd2.Member())
assert.NoError(t, err)
ds2For2Encrypted, err := mkh2.GetShareableChainKey(ctx, g, omd2.Member())
assert.NoError(t, err)
err = mkh1.RegisterChainKey(ctx, g, omd1.Device(), ds1For1Encrypted)
assert.NoError(t, err)
err = mkh2.RegisterChainKey(ctx, g, omd2.Device(), ds2For2Encrypted)
assert.NoError(t, err)
err = mkh2.RegisterChainKey(ctx, g, omd1.Device(), ds1For2Encrypted)
assert.NoError(t, err)
ds1, err := mkh1.getOwnDeviceChainKeyForGroup(ctx, g)
assert.NoError(t, err)
initialCounter := ds1.Counter
for i := 0; i < 1000; i++ {
payloadRef, err := proto.Marshal(&protocoltypes.EncryptedMessage{Plaintext: []byte("Test payload 1")})
assert.NoError(t, err)
envEncrypted, err := mkh1.SealEnvelope(ctx, g, payloadRef)
assert.NoError(t, err)
ds, err := mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, gc1DevicePubKey)
if !assert.NoError(t, err) {
t.Fatalf("failed at i = %d", i)
}
assert.Equal(t, ds.Counter, initialCounter+uint64(i+1))
env, headers, err := ((*secretStore)(nil)).OpenEnvelopeHeaders(envEncrypted, g)
if !assert.NoError(t, err) {
t.Fatalf("failed at i = %d", i)
}
payloadClr, err := mkh2.OpenEnvelopePayload(ctx, env, headers, gPK, omd2.Device(), cid.Undef)
if !assert.NoError(t, err) {
t.Fatalf("failed at i = %d", i)
}
if assert.NotNil(t, headers) && assert.NotNil(t, payloadClr) {
devRaw, err := omd1.Device().Raw()
assert.NoError(t, err)
assert.Equal(t, headers.DevicePk, devRaw)
payloadClrBytes, err := proto.Marshal(payloadClr)
assert.NoError(t, err)
assert.Equal(t, payloadRef, payloadClrBytes)
} else {
break
}
}
}
func mustDeviceChainKey(t testing.TB) func(ds *protocoltypes.DeviceChainKey, err error) *protocoltypes.DeviceChainKey {
return func(ds *protocoltypes.DeviceChainKey, err error) *protocoltypes.DeviceChainKey {
t.Helper()
if err != nil {
t.Fatal(err)
}
return ds
}
}
func mustMessageHeaders(t testing.TB, omd OwnMemberDevice, counter uint64, payload []byte) *protocoltypes.MessageHeaders {
t.Helper()
pkB, err := omd.Device().Raw()
if err != nil {
t.Fatal(err)
}
sig, err := omd.DeviceSign(payload)
if err != nil {
t.Fatal(err)
}
return &protocoltypes.MessageHeaders{
Counter: counter,
DevicePk: pkB,
Sig: sig,
}
}
func Test_EncryptMessagePayload(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
group, _, err := protocoltypes.NewGroupMultiMember()
assert.NoError(t, err)
mkh1, err := newInMemSecretStore(nil)
assert.NoError(t, err)
t.Cleanup(func() {
mkh1.Close()
})
mkh2, err := newInMemSecretStore(nil)
assert.NoError(t, err)
t.Cleanup(func() {
mkh2.Close()
})
omd1, err := mkh1.GetOwnMemberDeviceForGroup(group)
assert.NoError(t, err)
omd2, err := mkh2.GetOwnMemberDeviceForGroup(group)
assert.NoError(t, err)
encryptedDS1For1, err := mkh1.GetShareableChainKey(ctx, group, omd1.Member())
assert.NoError(t, err)
encryptedDS1For2, err := mkh1.GetShareableChainKey(ctx, group, omd2.Member())
assert.NoError(t, err)
encryptedDS2For2, err := mkh2.GetShareableChainKey(ctx, group, omd2.Member())
assert.NoError(t, err)
gc1DevicePubKey := omd1.Device()
gc2DevicePubKey := omd2.Device()
err = mkh1.RegisterChainKey(ctx, group, gc1DevicePubKey, encryptedDS1For1)
assert.NoError(t, err)
err = mkh2.RegisterChainKey(ctx, group, gc2DevicePubKey, encryptedDS2For2)
assert.NoError(t, err)
ds1, err := mkh1.getOwnDeviceChainKeyForGroup(ctx, group)
assert.NoError(t, err)
initialCounter := ds1.Counter
firstDeviceChainKey := append([]byte(nil), ds1.ChainKey...)
payloadRef1 := []byte("ok, this is the first test")
payloadRef2 := []byte("so, this is a second test")
payloadRef3 := []byte("this will be posted many times")
err = mkh2.RegisterChainKey(ctx, group, omd1.Device(), encryptedDS1For2)
assert.NoError(t, err)
gPK, err := group.GetPubKey()
assert.NoError(t, err)
assert.Equal(t, mustDeviceChainKey(t)(mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())).ChainKey, firstDeviceChainKey)
payloadEnc1, _, err := sealPayload(payloadRef1, mustDeviceChainKey(t)(mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())), omd1.(*ownMemberDevice).device, group)
assert.NoError(t, err)
// secret is derived by sealEnvelope
err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
assert.NoError(t, err)
assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc1))
// Messages are encrypted with DeviceChainKey.Counter
// uint64 overflows to 0, which is the expected behaviour
// Test with a wrong counter value
payloadClr1, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
assert.Error(t, err)
assert.Nil(t, decryptInfo)
assert.Equal(t, "", string(payloadClr1))
// Test with a valid counter value, but no CID (so no cache)
payloadClr1, decryptInfo, err = mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc1, mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
assert.NoError(t, err)
assert.Equal(t, string(payloadRef1), string(payloadClr1))
err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
assert.NoError(t, err)
ds, err := mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
assert.NoError(t, err)
assert.Equal(t, ds.Counter, initialCounter+1)
assert.NotEqual(t, ds.ChainKey, firstDeviceChainKey)
payloadEnc2, _, err := sealPayload(payloadRef1, ds, omd1.(*ownMemberDevice).device, group)
assert.NoError(t, err)
err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
assert.NoError(t, err)
// Ensure that encrypted message is not the same as the first message
assert.NotEqual(t, hex.EncodeToString(payloadRef1), hex.EncodeToString(payloadEnc2))
assert.NotEqual(t, hex.EncodeToString(payloadEnc1), hex.EncodeToString(payloadEnc2))
payloadClr2, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
assert.NoError(t, err)
err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+2, payloadRef1))
assert.NoError(t, err)
assert.Equal(t, string(payloadRef1), string(payloadClr2))
// Make sure that a message without a CID can't be decrypted twice
payloadClr2, decryptInfo, err = mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc2, mustMessageHeaders(t, omd1, initialCounter+1, payloadRef1))
assert.Error(t, err)
assert.Equal(t, "", string(payloadClr2))
ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
assert.NoError(t, err)
// Make sure that a message a CID can be decrypted twice
payloadEnc3, _, err := sealPayload(payloadRef2, ds, omd1.(*ownMemberDevice).device, group)
assert.NoError(t, err)
err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
assert.NoError(t, err)
dummyCID1, err := cid.Parse("QmbdQXQh9B2bWZgZJqfbjNPV5jGN2owbQ3vjeYsaDaCDqU")
assert.NoError(t, err)
dummyCID2, err := cid.Parse("Qmf8oj9wbfu73prNAA1cRQVDqA52gD5B3ApnYQQjcjffH4")
assert.NoError(t, err)
// Not decrypted message yet, wrong counter value
payloadClr3, decryptInfo, err := mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+2, payloadRef2))
assert.Error(t, err)
assert.Equal(t, "", string(payloadClr3))
payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
assert.NoError(t, err)
assert.Equal(t, string(payloadRef2), string(payloadClr3))
err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
assert.NoError(t, err)
payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
assert.NoError(t, err)
assert.Equal(t, string(payloadRef2), string(payloadClr3))
err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
assert.NoError(t, err)
// Wrong CID
payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID2, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+3, payloadRef2))
assert.Error(t, err)
assert.Equal(t, "", string(payloadClr3))
// Reused CID, wrong counter value
payloadClr3, decryptInfo, err = mkh2.openPayload(ctx, dummyCID1, gPK, payloadEnc3, mustMessageHeaders(t, omd1, initialCounter+4, payloadRef2))
assert.Error(t, err)
assert.Equal(t, "", string(payloadClr3))
massExpected := uint64(200)
// Test appending 200 messages, to ensure new secrets are generated correctly
for i := uint64(0); i < massExpected; i++ {
ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
assert.NoError(t, err)
payloadEnc, _, err := sealPayload(payloadRef3, ds, omd1.(*ownMemberDevice).device, group)
assert.NoError(t, err)
err = mkh1.deriveDeviceChainKey(ctx, group, omd1.Device())
assert.NoError(t, err)
ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
assert.NoError(t, err)
counter := ds.Counter
payloadClr, decryptInfo, err := mkh2.openPayload(ctx, cid.Undef, gPK, payloadEnc, mustMessageHeaders(t, omd1, counter, payloadRef3))
if !assert.NoError(t, err) {
t.Fatalf("failed at i = %d", i)
}
err = mkh2.postDecryptActions(ctx, decryptInfo, gPK, omd2.Device(), mustMessageHeaders(t, omd1, counter, payloadRef3))
assert.NoError(t, err)
assert.Equal(t, string(payloadRef3), string(payloadClr))
}
ds, err = mkh1.getDeviceChainKeyForGroupAndDevice(ctx, gPK, omd1.Device())
assert.NoError(t, err)
assert.Equal(t, initialCounter+massExpected+3, ds.Counter)
}
func TestGetGroupForContact(t *testing.T) {
privateKey, _, err := crypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err)
group, err := getGroupForContact(privateKey)
require.NoError(t, err)
require.Equal(t, group.GroupType, protocoltypes.GroupType_GroupTypeContact)
require.Equal(t, len(group.PublicKey), 32)
require.Equal(t, len(group.Secret), 32)
}
func TestGetKeysForGroupOfContact(t *testing.T) {
privateKey, _, err := crypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err)
groupPrivateKey, groupSecretPrivateKey, err := getKeysForGroupOfContact(privateKey)
require.NoError(t, err)
require.NotNil(t, groupPrivateKey)
require.NotNil(t, groupSecretPrivateKey)
require.False(t, groupPrivateKey.Equals(groupSecretPrivateKey))
}
================================================
FILE: pkg/testutil/doc.go
================================================
// Package testutil contains testing helpers (logging, slow skipping).
package testutil
================================================
FILE: pkg/testutil/example_test.go
================================================
package testutil_test
================================================
FILE: pkg/testutil/filters.go
================================================
package testutil
import (
"testing"
"google.golang.org/protobuf/proto"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func TestFilterGroupMetadataPayloadSent(t *testing.T, events <-chan *protocoltypes.GroupMetadataEvent) []*protocoltypes.GroupMetadataPayloadSent {
t.Helper()
out := []*protocoltypes.GroupMetadataPayloadSent(nil)
for evt := range events {
if evt == nil {
continue
}
if evt.Metadata.EventType != protocoltypes.EventType_EventTypeGroupMetadataPayloadSent {
continue
}
m := &protocoltypes.GroupMetadataPayloadSent{}
if err := proto.Unmarshal(evt.Event, m); err != nil {
continue
}
out = append(out, m)
}
return out
}
================================================
FILE: pkg/testutil/logging.go
================================================
package testutil
import (
"flag"
"fmt"
"os"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"moul.io/zapring"
"berty.tech/weshnet/v2/pkg/logutil"
)
const defaultLoggingFilters = "info+:bty.test* error+:*,-ipfs*,-*.tyber"
var (
logFilters = flag.String("log-filters", defaultLoggingFilters, "log namespaces")
logFile = flag.String("log-file", "", "log to file")
logFormat = flag.String("log-format", "color", "json, console, color")
loggerInstance *zap.Logger
loggerCleanup func()
loggerInitOnce sync.Once
loggerRing *zapring.Core
)
func Logger(t testing.TB) (*zap.Logger, func()) {
t.Helper()
loggerInstance, _, loggerCleanup := LoggerWithRing(t)
return loggerInstance, loggerCleanup
}
func LoggerWithRing(t testing.TB) (*zap.Logger, *zapring.Core, func()) {
t.Helper()
loggerInitOnce.Do(func() {
if val := os.Getenv("BERTY_LOGFILTERS"); val != "" {
*logFilters = val
}
if val := os.Getenv("BERTY_LOGFILE"); val != "" {
*logFile = val
}
if val := os.Getenv("BERTY_LOGFORMAT"); val != "" {
*logFormat = val
}
*logFilters = strings.ReplaceAll(*logFilters, ":default:", defaultLoggingFilters)
var err error
loggerRing = zapring.New(10 * 1024 * 1024)
loggerInstance, loggerCleanup, err = logutil.NewLogger(
logutil.NewStdStream(*logFilters, *logFormat, *logFile),
logutil.NewRingStream(*logFilters, *logFormat, loggerRing),
)
if !assert.NoError(t, err) {
loggerInstance = zap.NewNop()
loggerCleanup = func() {}
}
})
return loggerInstance, loggerRing, loggerCleanup
}
func LogTree(t *testing.T, log string, indent int, title bool, args ...any) {
t.Helper()
if os.Getenv("SHOW_LOG_TREES") != "1" {
return
}
if len(args) > 0 {
log = fmt.Sprintf(log, args...)
}
if !title {
log = "└── " + log
}
for i := 0; i < indent; i++ {
log = "│ " + log
}
t.Log(log)
}
================================================
FILE: pkg/testutil/require.go
================================================
package testutil
import (
"io"
"testing"
"github.com/stretchr/testify/require"
)
func Close(t *testing.T, closer io.Closer) {
t.Helper()
require.NoError(t, closer.Close())
}
================================================
FILE: pkg/testutil/skip.go
================================================
package testutil
import (
"fmt"
"os"
"strings"
"testing"
)
// Stability level enum
type Stability string
const (
Stable Stability = "stable"
Flappy Stability = "flappy"
Broken Stability = "broken"
AnyStability Stability = "any"
)
// Speed level enum
type Speed string
const (
Fast Speed = "fast"
Slow Speed = "slow"
AnySpeed Speed = "any"
)
// RacePolicy enum
type RacePolicy string
const (
SkipIfRace RacePolicy = "skip-if-race"
RunIfRace RacePolicy = "run-if-race"
)
// Default levels
const (
defaultStabilityFilter Stability = Stable
defaultSpeedFilter Speed = AnySpeed
)
var (
enabledStability = map[Stability]bool{}
enabledSpeed = map[Speed]bool{}
envParsed = false
)
func parseEnv() {
// Get stability filters
stabFilter := os.Getenv("TEST_STABILITY")
if stabFilter == "" {
stabFilter = string(defaultStabilityFilter)
}
for _, level := range strings.Split(stabFilter, ",") {
switch Stability(level) {
case Stable, Flappy, Broken:
enabledStability[Stability(level)] = true
case AnyStability:
enabledStability[Stable] = true
enabledStability[Flappy] = true
enabledStability[Broken] = true
default:
panic(fmt.Sprintf("invalid stability level: %q", level))
}
}
// Get speed filters
speedFilter := os.Getenv("TEST_SPEED")
if speedFilter == "" {
speedFilter = string(defaultSpeedFilter)
}
for _, level := range strings.Split(speedFilter, ",") {
switch Speed(level) {
case Slow, Fast:
enabledSpeed[Speed(level)] = true
case AnySpeed:
enabledSpeed[Slow] = true
enabledSpeed[Fast] = true
default:
panic(fmt.Sprintf("invalid speed level: %q", level))
}
}
envParsed = true
}
func FilterStability(t *testing.T, stability Stability) {
t.Helper()
if !envParsed {
parseEnv()
}
if !enabledStability[stability] {
t.Skipf("skip test with %q stability", stability)
}
}
func FilterSpeed(t *testing.T, speed Speed) {
t.Helper()
if !envParsed {
parseEnv()
}
if !enabledSpeed[speed] {
t.Skipf("skip test with %q speed", speed)
}
}
func FilterStabilityAndSpeed(t *testing.T, stability Stability, speed Speed) {
FilterStability(t, stability)
FilterSpeed(t, speed)
}
================================================
FILE: pkg/testutil/skip_norace.go
================================================
//go:build !race
package testutil
import "testing"
func FilterRace(t *testing.T, race RacePolicy) {
t.Helper()
if race == RunIfRace {
t.Skip("skipping, this test can only run with the '-race' flag")
}
}
================================================
FILE: pkg/testutil/skip_race.go
================================================
//go:build race
package testutil
import "testing"
func FilterRace(t *testing.T, race RacePolicy) {
t.Helper()
if race == SkipIfRace {
t.Skip("skipping, this test can only run without the '-race' flag")
}
}
================================================
FILE: pkg/testutil/skip_test.go
================================================
package testutil_test
import (
"testing"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestFilterRace(t *testing.T) {
t.Run("always-run", func(t *testing.T) {})
t.Run("skip-if-race", func(t *testing.T) {
testutil.FilterRace(t, testutil.SkipIfRace)
})
t.Run("run-if-race", func(t *testing.T) {
testutil.FilterRace(t, testutil.RunIfRace)
})
t.Run("always-skip", func(t *testing.T) {
t.Skip()
})
}
================================================
FILE: pkg/tinder/driver.go
================================================
package tinder
import (
"context"
"fmt"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/peer"
)
var ErrNotSupported = fmt.Errorf("not supported")
var _ discovery.Discovery = (IDriver)(nil)
type IDriver interface {
Name() string
Subscribe(ctx context.Context, topic string, opts ...discovery.Option) (<-chan peer.AddrInfo, error)
Unregister(ctx context.Context, topic string, opts ...discovery.Option) error
// discovery
Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error)
FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error)
}
================================================
FILE: pkg/tinder/driver_discovery.go
================================================
package tinder
import (
"context"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/routing"
disc_routing "github.com/libp2p/go-libp2p/p2p/discovery/routing"
)
type DiscoveryDriver struct {
name string
discovery.Discovery
}
func NewRoutingDiscoveryDriver(name string, routing routing.Routing) IDriver {
disc := disc_routing.NewRoutingDiscovery(routing)
return NewDiscoveryDriver(name, disc)
}
func NewDiscoveryDriver(name string, disc discovery.Discovery) IDriver {
return &DiscoveryDriver{name, disc}
}
// discovery advertise
func (d *DiscoveryDriver) Advertise(ctx context.Context, topic string, opts ...discovery.Option) (time.Duration, error) {
return d.Discovery.Advertise(ctx, topic, opts...)
}
// discovery find peers
func (d *DiscoveryDriver) FindPeers(ctx context.Context, topic string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
return d.Discovery.FindPeers(ctx, topic, opts...)
}
func (d *DiscoveryDriver) Subscribe(_ context.Context, _ string, _ ...discovery.Option) (<-chan peer.AddrInfo, error) {
return nil, ErrNotSupported
}
func (d *DiscoveryDriver) Unregister(_ context.Context, _ string, _ ...discovery.Option) error {
return ErrNotSupported
}
func (d *DiscoveryDriver) Name() string {
return d.name
}
================================================
FILE: pkg/tinder/driver_localdiscovery.go
================================================
package tinder
import (
"container/list"
"context"
"encoding/hex"
"fmt"
"math/rand"
"slices"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
protocol "github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"go.uber.org/zap"
nearby "berty.tech/weshnet/v2/pkg/androidnearby"
ble "berty.tech/weshnet/v2/pkg/ble-driver"
"berty.tech/weshnet/v2/pkg/logutil"
mc "berty.tech/weshnet/v2/pkg/multipeer-connectivity-driver"
"berty.tech/weshnet/v2/pkg/protoio"
)
const (
// LocalDiscoveryName is the name of the localdiscovery driver
LocalDiscoveryName = "localdisc"
recProtocolID = protocol.ID("wesh/p2p/localrecord")
minTTL = 7200 * time.Second
maxLimit = 1000
)
type LocalDiscovery struct {
rootctx context.Context
rootcancel context.CancelFunc
h host.Host
logger *zap.Logger
recs map[string] /* topic */ time.Time
muRecs sync.RWMutex
caches map[string] /* topic */ *linkedCache
muCaches sync.RWMutex
}
type linkedCache struct {
sync.Locker
recs map[peer.ID]*recCache
queue *list.List
cond *sync.Cond
}
type recCache struct {
topic string
peer *peer.AddrInfo
expire time.Time
}
func newLinkedCache() *linkedCache {
locker := sync.Mutex{}
return &linkedCache{
queue: list.New(),
recs: make(map[peer.ID]*recCache),
Locker: &locker,
cond: sync.NewCond(&locker),
}
}
func NewLocalDiscovery(logger *zap.Logger, host host.Host, _ *rand.Rand) (*LocalDiscovery, error) {
ctx, cancel := context.WithCancel(context.Background())
ld := &LocalDiscovery{
rootctx: ctx,
rootcancel: cancel,
logger: logger.Named("localdisc"),
h: host,
recs: make(map[string]time.Time),
caches: make(map[string]*linkedCache),
}
host.SetStreamHandler(recProtocolID, ld.handleStream)
if err := ld.monitorConnection(ctx); err != nil {
return nil, fmt.Errorf("unable to monitor connection: %w", err)
}
return ld, nil
}
func (ld *LocalDiscovery) Close() error {
ld.rootcancel()
return nil
}
func (ld *LocalDiscovery) Advertise(ctx context.Context, cid string, opts ...discovery.Option) (time.Duration, error) {
ld.logger.Debug("advertise record", logutil.PrivateString("ns", cid))
// Get options
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return minTTL, err
}
limit := options.Limit
if limit == 0 || limit > maxLimit {
limit = maxLimit
}
ttl := max(options.Ttl, minTTL)
expire := time.Now().Add(ttl)
ld.muRecs.Lock()
_, exist := ld.recs[cid]
if !exist && len(ld.recs) > limit {
ld.muRecs.Unlock()
return minTTL, fmt.Errorf("unable to add record, reached limit of %d", limit)
}
ld.recs[cid] = expire
ld.muRecs.Unlock()
ld.logger.Debug("advertise", zap.String("ns", hex.EncodeToString([]byte(cid))))
// send it to already connected proximity peers
records := []*Record{{Cid: cid, Expire: expire.Unix()}}
ld.sendRecordsToProximityPeers(ctx, &Records{Records: records})
return ttl, nil
}
func (ld *LocalDiscovery) FindPeers(_ context.Context, cid string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
// Get options
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return nil, err
}
limit := options.Limit
if limit == 0 || limit > maxLimit {
limit = maxLimit
}
ld.muCaches.RLock()
defer ld.muCaches.RUnlock()
var out chan peer.AddrInfo
if cache, ok := ld.caches[cid]; ok {
cache.Lock()
size := min(len(cache.recs), limit)
out = make(chan peer.AddrInfo, size) // make the channel
for _, rec := range cache.recs {
out <- *rec.peer
size--
if size == 0 {
break
}
}
cache.Unlock()
} else {
out = make(chan peer.AddrInfo) // make the channel
}
close(out)
return out, nil
}
func (ld *LocalDiscovery) Subscribe(ctx context.Context, cid string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
ld.logger.Debug("starting subscribe", logutil.PrivateString("ns", cid))
cpeer := make(chan peer.AddrInfo)
// Get options
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
close(cpeer)
return cpeer, err
}
limit := options.Limit
if limit == 0 || limit > maxLimit {
limit = maxLimit
}
ld.muCaches.Lock()
cache, ok := ld.caches[cid]
if !ok {
cache = newLinkedCache()
ld.caches[cid] = cache
}
ld.muCaches.Unlock()
ctx, cancel := context.WithCancel(ctx)
go func() {
<-ctx.Done()
cancel()
cache.cond.Broadcast()
}()
cache.Lock()
current := cache.queue.Front()
cache.Unlock()
counter := 0
go func() {
cache.Lock()
for ctx.Err() == nil && counter <= limit {
if current == nil {
// unlock the mutex
// wait for new elements in the list
cache.cond.Wait()
current = cache.queue.Back()
continue
}
next := current.Next()
rec := current.Value.(*recCache)
if time.Now().After(rec.expire) {
ld.logger.Debug("receiving expired record",
logutil.PrivateString("ns", cid),
zap.Duration("since", time.Since(rec.expire)))
delete(cache.recs, rec.peer.ID)
cache.queue.Remove(current)
} else {
ld.logger.Debug("receiving record", logutil.PrivateString("ns", cid))
select {
case cpeer <- *rec.peer:
counter++
case <-ctx.Done():
}
}
// move our pointer forward
current = next
}
close(cpeer)
cache.Unlock()
ld.logger.Debug("find peers ended", logutil.PrivateString("ns", cid), zap.Error(ctx.Err()))
}()
return cpeer, nil
}
func (ld *LocalDiscovery) getLocalReccord() *Records {
records := []*Record{}
now := time.Now()
ld.muRecs.Lock()
for cid, expire := range ld.recs {
// if expired remove from cache
if now.After(expire) {
delete(ld.recs, cid)
continue
}
records = append(records, &Record{
Cid: cid,
Expire: expire.Unix(),
})
}
ld.muRecs.Unlock()
return &Records{Records: records}
}
func (ld *LocalDiscovery) Unregister(_ context.Context, cid string, _ ...discovery.Option) error {
ld.muRecs.Lock()
delete(ld.recs, cid)
ld.muRecs.Unlock()
return nil
}
func (ld *LocalDiscovery) sendRecordsToProximityPeers(ctx context.Context, records *Records) {
conns := ld.h.Network().Conns()
wg := sync.WaitGroup{}
for _, c := range conns {
if manet.IsPrivateAddr(c.RemoteMultiaddr()) || isProximityProtocol(c.RemoteMultiaddr()) {
wg.Add(1)
go func(c network.Conn) {
ld.logger.Debug("sending records to peer", zap.Stringer("peer", c.RemotePeer()))
if err := ld.sendRecordsTo(ctx, c.RemotePeer(), records); err != nil {
ld.logger.Warn("unable to send records to newly connected peer",
zap.Error(err), zap.Stringer("peer", c.RemotePeer()))
}
wg.Done()
}(c)
}
}
wg.Wait()
}
// Called when is a stream is opened by a remote peer
// Receive remote peer cache and put it in our local cache
func (ld *LocalDiscovery) handleStream(s network.Stream) {
defer s.Reset() // nolint:errcheck
reader := protoio.NewDelimitedReader(s, 2048)
records := Records{}
if err := reader.ReadMsg(&records); err != nil {
ld.logger.Error("handleStream receive an invalid local record", zap.Error(err))
return
}
info := peer.AddrInfo{
ID: s.Conn().RemotePeer(),
Addrs: []ma.Multiaddr{s.Conn().RemoteMultiaddr()},
}
// fill the remote cache
for _, record := range records.Records {
expire := time.Unix(record.Expire, 0)
ld.logger.Debug("saving remote record in cache",
logutil.PrivateString("remoteID", s.Conn().RemotePeer().String()),
logutil.PrivateString("CID", record.Cid),
zap.Time("expire", expire))
ld.muCaches.Lock()
cache, ok := ld.caches[record.Cid]
if !ok {
cache = newLinkedCache()
ld.caches[record.Cid] = cache
}
ld.muCaches.Unlock()
rec := &recCache{
peer: &info,
topic: record.Cid,
expire: expire,
}
// update the given cache record and signal to other routine that we got an update
cache.Lock()
if cacheRec, ok := cache.recs[info.ID]; ok {
cacheRec.peer = &info
cacheRec.expire = expire
} else {
cache.recs[info.ID] = rec
cache.queue.PushBack(rec)
}
cache.cond.Broadcast()
cache.Unlock()
}
}
func (ld *LocalDiscovery) sendRecordsTo(ctx context.Context, p peer.ID, records *Records) error {
s, err := ld.h.NewStream(ctx, p, recProtocolID)
if err != nil {
return fmt.Errorf("unable to create stream: %w", err)
}
defer s.Close()
pbw := protoio.NewDelimitedWriter(s)
if err := pbw.WriteMsg(records); err != nil {
return fmt.Errorf("write error: %w", err)
}
return nil
}
func isProximityProtocol(addr ma.Multiaddr) bool {
for _, p := range addr.Protocols() {
switch p.Code {
case ble.ProtocolCode, mc.ProtocolCode, nearby.ProtocolCode:
return true
default:
}
}
return false
}
func (ld *LocalDiscovery) handleConnection(ctx context.Context, p peer.ID) {
if p == ld.h.ID() {
return
}
// check if we use a proximity addrs with this peer
conns := ld.h.Network().ConnsToPeer(p)
for _, conn := range conns {
if manet.IsPrivateAddr(conn.RemoteMultiaddr()) || isProximityProtocol(conn.RemoteMultiaddr()) {
go func() {
records := ld.getLocalReccord()
if err := ld.sendRecordsTo(ctx, p, records); err != nil {
ld.logger.Warn("unable to send local record",
logutil.PrivateString("peer", p.String()),
zap.Int("records", len(records.Records)),
zap.Error(err))
} else {
ld.logger.Info("send topics to local peer", logutil.PrivateString("peer", conn.RemotePeer().String()))
}
}()
return
}
}
}
func (ld *LocalDiscovery) monitorConnection(ctx context.Context) error {
sub, err := ld.h.EventBus().Subscribe([]any{
new(event.EvtPeerConnectednessChanged),
new(event.EvtPeerProtocolsUpdated),
}, eventbus.Name("weshnet/tinder/monitor-connection"))
if err != nil {
return fmt.Errorf("unable to subscribe to `EvtPeerConnectednessChanged`: %w", err)
}
// check already connected peers
for _, p := range ld.h.Peerstore().Peers() {
if ld.h.Network().Connectedness(p) == network.Connected {
ld.handleConnection(ctx, p)
}
}
go func() {
defer sub.Close()
for {
var e any
select {
case e = <-sub.Out():
case <-ctx.Done():
return
}
switch evt := e.(type) {
case event.EvtPeerConnectednessChanged:
// send record to connected peer only
if evt.Connectedness == network.Connected {
ld.handleConnection(ctx, evt.Peer)
}
case event.EvtPeerProtocolsUpdated:
if slices.Contains(evt.Added, recProtocolID) {
ld.handleConnection(ctx, evt.Peer)
}
}
}
}()
return nil
}
func (ld *LocalDiscovery) Name() string {
return LocalDiscoveryName
}
================================================
FILE: pkg/tinder/driver_localdiscovery_test.go
================================================
package tinder
import (
"context"
"math/rand"
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestServiceLocalDiscorvery(t *testing.T) {
ctx := context.Background()
mn := mocknet.New()
defer mn.Close()
logger, cleanup := testutil.Logger(t)
defer cleanup()
p1 := genLocalPeer(t, mn)
p2 := genLocalPeer(t, mn)
err := mn.LinkAll()
require.NoError(t, err)
disc1, err := NewLocalDiscovery(logger, p1, rand.New(rand.NewSource(rand.Int63())))
require.NoError(t, err)
disc2, err := NewLocalDiscovery(logger, p2, rand.New(rand.NewSource(rand.Int63())))
require.NoError(t, err)
s1, err := NewService(p1, logger, disc1)
require.NoError(t, err)
s2, err := NewService(p2, logger, disc2)
require.NoError(t, err)
const topic = "test_topic"
s1.StartAdvertises(ctx, topic)
// try a first lookup, should find nothing
{
out := s2.FindPeers(ctx, topic)
peers := testPeersChanToSlice(t, out)
require.Len(t, peers, 0, "no peer should be available")
}
{
// start a subscribe and wait for connection
sub := s2.Subscribe(topic)
defer sub.Close()
err = mn.ConnectAllButSelf()
require.NoError(t, err)
p, err := testWaitForPeers(t, sub.Out(), time.Second*5)
require.NoError(t, err)
require.Equal(t, p1.ID(), p.ID)
require.Equal(t, p1.Addrs(), p.Addrs)
}
// try a lookup again, this time we should have some peers
{
out := s2.FindPeers(ctx, topic)
p, err := testWaitForPeers(t, out, time.Second*5)
require.NoError(t, err)
require.Equal(t, p1.ID(), p.ID)
require.Equal(t, p1.Addrs(), p.Addrs)
}
}
func TestServiceLocalDiscorveryBeforeProtocolRegister(t *testing.T) {
const topic = "test_topic"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
logger, cleanup := testutil.Logger(t)
defer cleanup()
p1 := genLocalPeer(t, mn)
p2 := genLocalPeer(t, mn)
err := mn.LinkAll()
require.NoError(t, err)
disc1, err := NewLocalDiscovery(logger, p1, rand.New(rand.NewSource(rand.Int63())))
require.NoError(t, err)
// create service for peer 1
s1, err := NewService(p1, logger, disc1)
require.NoError(t, err)
// start advertising
s1.StartAdvertises(ctx, topic)
// connect both peer BEFORE registering local discovery protocol for peer 2
err = mn.ConnectAllButSelf()
require.NoError(t, err)
// let some time to peers to connect and trigger protocol exchange
time.Sleep(time.Millisecond * 200)
// register p2 local discovery
disc2, err := NewLocalDiscovery(logger, p2, rand.New(rand.NewSource(rand.Int63())))
require.NoError(t, err)
s2, err := NewService(p2, logger, disc2)
require.NoError(t, err)
// start subscribe and wait for connection
sub := s2.Subscribe(topic)
defer sub.Close()
// pull to fetch current peers on the topic
sub.Pull()
select {
case p := <-sub.Out():
require.Equal(t, p.ID, p1.ID())
case <-time.After(time.Second * 5):
require.FailNow(t, "unable to wait for peer on local discovery")
}
}
================================================
FILE: pkg/tinder/driver_mock.go
================================================
package tinder
import (
"context"
"fmt"
"slices"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
)
type MockDriverServer struct {
pc *peersCache
topics map[string] /* topic */ map[peer.ID]time.Time
mx sync.RWMutex
}
func NewMockDriverServer() *MockDriverServer {
return &MockDriverServer{
topics: make(map[string]map[peer.ID]time.Time),
pc: newPeerCache(),
}
}
func (s *MockDriverServer) Advertise(topic string, info peer.AddrInfo, ttl time.Duration) {
s.mx.Lock()
expires, ok := s.topics[topic]
if !ok {
expires = map[peer.ID]time.Time{}
s.topics[topic] = expires
}
expires[info.ID] = time.Now().Add(ttl)
s.mx.Unlock()
s.pc.UpdatePeer(topic, info)
}
func (s *MockDriverServer) FindPeers(topic string, limit int) <-chan peer.AddrInfo {
s.mx.Lock()
defer s.mx.Unlock()
peers := s.pc.GetPeersForTopics(topic)
if len(peers) < limit {
limit = len(peers)
}
expires, ok := s.topics[topic]
if !ok {
expires = map[peer.ID]time.Time{}
s.topics[topic] = expires
}
out := make(chan peer.AddrInfo, limit)
for i := 0; i < limit; i++ {
peer := peers[i]
if expire, ok := expires[peer.ID]; ok {
if time.Now().Before(expire) {
out <- peer
} else {
delete(expires, peer.ID)
}
}
}
close(out)
return out
}
func (s *MockDriverServer) Unregister(ctx context.Context, topic string, p peer.ID) {
s.mx.Lock()
s.pc.RemoveFromCache(ctx, topic, p)
if expires, ok := s.topics[topic]; ok {
delete(expires, p)
}
s.mx.Unlock()
}
func (s *MockDriverServer) Exist(topic string, _ peer.ID) (ok bool) {
peers := s.pc.GetPeersForTopics(topic)
return len(peers) == 1
}
func (s *MockDriverServer) Subscribe(ctx context.Context, topic string, buffsize int) <-chan peer.AddrInfo {
s.mx.Lock()
defer s.mx.Unlock()
start := time.Now()
peers := s.pc.GetPeersForTopics(topic)
knownPeers := make(PeersUpdate)
for _, p := range peers {
knownPeers[p.ID] = start
}
out := make(chan peer.AddrInfo, buffsize)
go func() {
for {
// Wait until `PeersCache` differ from `peerCache` peers status
updated, ok := s.pc.WaitForPeerUpdate(ctx, topic, knownPeers)
if !ok {
break // context has expired
}
// send peers
for _, peer := range s.pc.GetPeers(updated...) {
out <- peer
}
}
// we're done here, close the channel and decrement
close(out)
}()
return out
}
func (s *MockDriverServer) WaitForPeer(topic string, p peer.ID, timeout time.Duration) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
knownPeers := make(PeersUpdate)
for {
// Wait until `PeersCache` differ from `peerCache` peers status
updated, expired := s.pc.WaitForPeerUpdate(ctx, topic, knownPeers)
if !expired {
return fmt.Errorf("timeout while waiting for: %s", p.String())
}
// send peers
if slices.Contains(updated, p) {
return nil
}
}
}
func (s *MockDriverServer) Client(h host.Host) IDriver {
return &MockIDriverClient{h: h, serv: s}
}
var _ IDriver = (*MockIDriverClient)(nil)
type MockIDriverClient struct {
h host.Host
serv *MockDriverServer
}
func (s *MockIDriverClient) Name() string {
return "mock"
}
func (s *MockIDriverClient) FindPeers(_ context.Context, topic string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return nil, err
}
if options.Ttl == 0 {
options.Limit = 1000
}
return s.serv.FindPeers(topic, options.Limit), nil
}
func (s *MockIDriverClient) Advertise(_ context.Context, topic string, opts ...discovery.Option) (time.Duration, error) {
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return 0, err
}
if options.Ttl == 0 {
options.Ttl = time.Second * 10
}
info := s.h.Peerstore().PeerInfo(s.h.ID())
s.serv.Advertise(topic, info, options.Ttl)
return options.Ttl, nil
}
func (s *MockIDriverClient) Subscribe(ctx context.Context, topic string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return nil, err
}
v := options.Other[optionSubscribeBufferSize]
var buffsize int
var ok bool
if buffsize, ok = v.(int); !ok || buffsize == 0 {
buffsize = 16
}
out := s.serv.Subscribe(ctx, topic, buffsize)
return out, nil
}
func (s *MockIDriverClient) Unregister(ctx context.Context, topic string, _ ...discovery.Option) error {
s.serv.Unregister(ctx, topic, s.h.ID())
return nil
}
type discOption string
const (
optionSubscribeBufferSize discOption = "tinder_subsize"
)
func MockBufferSize(size int) discovery.Option {
return func(opts *discovery.Options) error {
if opts.Other == nil {
opts.Other = make(map[any]any)
}
opts.Other[optionSubscribeBufferSize] = size
return nil
}
}
================================================
FILE: pkg/tinder/driver_mock_test.go
================================================
package tinder
import (
"context"
"testing"
"time"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMockAdvertise(t *testing.T) {
const topic = "test_topic'"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
p1, err := mn.GenPeer()
require.NoError(t, err)
server := NewMockDriverServer()
client := server.Client(p1)
info1 := p1.Peerstore().PeerInfo(p1.ID())
require.False(t, server.Exist(topic, info1.ID))
ttl, err := client.Advertise(ctx, topic)
require.NoError(t, err)
require.Greater(t, ttl, time.Duration(0))
require.True(t, server.Exist(topic, info1.ID))
}
func TestMockFindPeers(t *testing.T) {
const topic = "test_topic'"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
p1, err := mn.GenPeer()
require.NoError(t, err)
p2, err := mn.GenPeer()
require.NoError(t, err)
server := NewMockDriverServer()
client1 := server.Client(p1)
client2 := server.Client(p2)
info1 := p1.Peerstore().PeerInfo(p1.ID())
server.Advertise(topic, info1, time.Minute)
for _, client := range []IDriver{client1, client2} {
out, err := client.FindPeers(ctx, topic)
require.NoError(t, err)
var peers []peer.AddrInfo
for p := range out {
peers = append(peers, p)
}
require.Len(t, peers, 1)
assert.Equal(t, info1, peers[0])
}
info2 := p2.Peerstore().PeerInfo(p2.ID())
server.Advertise(topic, info2, time.Minute)
for _, client := range []IDriver{client1, client2} {
out, err := client.FindPeers(ctx, topic)
require.NoError(t, err)
var peers []peer.AddrInfo
for p := range out {
peers = append(peers, p)
}
require.Len(t, peers, 2)
}
}
func TestMockSubscribe(t *testing.T) {
const topic = "test_topic'"
mn := mocknet.New()
defer mn.Close()
p1, err := mn.GenPeer()
require.NoError(t, err)
p2, err := mn.GenPeer()
require.NoError(t, err)
info2 := p1.Peerstore().PeerInfo(p2.ID())
p3, err := mn.GenPeer()
require.NoError(t, err)
info3 := p1.Peerstore().PeerInfo(p3.ID())
server := NewMockDriverServer()
client1 := server.Client(p1)
{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
out, err := client1.Subscribe(ctx, topic, MockBufferSize(2))
require.NoError(t, err)
server.Advertise(topic, info2, time.Minute)
server.Advertise(topic, info3, time.Minute)
peers := map[peer.ID]peer.AddrInfo{}
for i := 0; i < 2; i++ {
peer := <-out
peers[peer.ID] = peer
}
p2, ok := peers[info2.ID]
require.True(t, ok)
require.Equal(t, info2, p2)
p3, ok := peers[info3.ID]
require.True(t, ok)
require.Equal(t, info3, p3)
cancel()
// should be close if context expire
require.Eventually(t, func() bool {
select {
case <-out:
return true
default:
return false
}
}, time.Second, time.Millisecond*10)
}
}
func TestMockUnregister(t *testing.T) {
const topic = "test_topic'"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
p1, err := mn.GenPeer()
require.NoError(t, err)
server := NewMockDriverServer()
client := server.Client(p1)
info1 := p1.Peerstore().PeerInfo(p1.ID())
server.Advertise(topic, info1, time.Minute)
require.True(t, server.Exist(topic, info1.ID))
err = client.Unregister(ctx, topic)
require.NoError(t, err)
require.False(t, server.Exist(topic, info1.ID))
}
================================================
FILE: pkg/tinder/driver_rdvp.go
================================================
// from https://github.com/berty/go-libp2p-rendezvous/blob/implement-spec/discovery.go
package tinder
import (
"context"
"fmt"
"math"
mrand "math/rand"
"sync"
"time"
p2p_rp "github.com/berty/go-libp2p-rendezvous"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
)
type rendezvousDiscovery struct {
logger *zap.Logger
rp p2p_rp.RendezvousPoint
synccls []p2p_rp.RendezvousSyncClient
peerCache map[string]*rpCache
peerCacheMux sync.RWMutex
rng *mrand.Rand
rngMux sync.Mutex
selfID peer.ID
}
type rpCache struct {
recs map[peer.ID]*rpRecord
cookie []byte
mux sync.Mutex
}
type rpRecord struct {
peer peer.AddrInfo
expire int64
}
func NewRendezvousDiscovery(logger *zap.Logger, host host.Host, rdvPeer peer.ID, factory p2p_rp.AddrsFactory, rng *mrand.Rand, emitters ...p2p_rp.RendezvousSyncClient) IDriver {
rp := p2p_rp.NewRendezvousPoint(host, rdvPeer, p2p_rp.ClientWithAddrsFactory(factory))
return &rendezvousDiscovery{
logger: logger.Named("tinder/rdvp"),
rp: rp,
rng: rng,
synccls: emitters,
peerCache: make(map[string]*rpCache),
selfID: host.ID(),
}
}
func (c *rendezvousDiscovery) Advertise(ctx context.Context, topic string, opts ...discovery.Option) (time.Duration, error) {
// Get options
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return 0, err
}
ttl := options.Ttl
var ttlSeconds int
if ttl == 0 {
ttlSeconds = 7200
} else {
ttlSeconds = int(math.Round(ttl.Seconds()))
}
rttl, err := c.rp.Register(ctx, topic, ttlSeconds)
if err != nil {
return 0, err
}
return rttl, nil
}
func (c *rendezvousDiscovery) FindPeers(ctx context.Context, topic string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
// Get options
var options discovery.Options
err := options.Apply(opts...)
if err != nil {
return nil, err
}
const maxLimit = 1000
limit := options.Limit
if limit == 0 || limit > maxLimit {
limit = maxLimit
}
return c.findPeers(ctx, topic, limit)
}
func (c *rendezvousDiscovery) findPeers(ctx context.Context, topic string, limit int) (<-chan peer.AddrInfo, error) {
// Get cached peers
var err error
c.peerCacheMux.RLock()
cache, ok := c.peerCache[topic]
c.peerCacheMux.RUnlock()
if !ok {
c.peerCacheMux.Lock()
cache, ok = c.peerCache[topic]
if !ok {
cache = &rpCache{recs: make(map[peer.ID]*rpRecord)}
c.peerCache[topic] = cache
}
c.peerCacheMux.Unlock()
}
cache.mux.Lock()
defer cache.mux.Unlock()
// Remove all expired entries from cache
currentTime := time.Now().Unix()
newCacheSize := len(cache.recs)
for p := range cache.recs {
rec := cache.recs[p]
if rec.expire < currentTime {
newCacheSize--
delete(cache.recs, p)
}
}
cookie := cache.cookie
// Discover new records if we don't have enough
if newCacheSize < limit {
// TODO: Should we return error even if we have valid cached results?
var regs []p2p_rp.Registration
var newCookie []byte
if regs, newCookie, err = c.rp.Discover(ctx, topic, limit, cookie); err == nil {
for _, reg := range regs {
rec := &rpRecord{peer: reg.Peer, expire: int64(reg.Ttl) + currentTime}
cache.recs[rec.peer.ID] = rec
}
cache.cookie = newCookie
} else {
err = fmt.Errorf("unable to run discover: %w", err)
}
}
// Randomize and fill channel with available records
count := min(limit, len(cache.recs))
chPeer := make(chan peer.AddrInfo, count)
c.rngMux.Lock()
perm := c.rng.Perm(len(cache.recs))[0:count]
c.rngMux.Unlock()
permSet := make(map[int]int)
for i, v := range perm {
permSet[v] = i
}
sendLst := make([]*peer.AddrInfo, count)
iter := 0
for k := range cache.recs {
if sendIndex, ok := permSet[iter]; ok {
sendLst[sendIndex] = &cache.recs[k].peer
}
iter++
}
for _, send := range sendLst {
chPeer <- *send
}
close(chPeer)
return chPeer, err
}
func (c *rendezvousDiscovery) Subscribe(ctx context.Context, topic string, _ ...discovery.Option) (<-chan peer.AddrInfo, error) {
ch, err := c.getSubscribtionForTopic(ctx, topic)
return ch, err
}
func (c *rendezvousDiscovery) Unregister(ctx context.Context, topic string, _ ...discovery.Option) error {
c.peerCacheMux.RLock()
cache, ok := c.peerCache[topic]
if ok {
cache.mux.Lock()
delete(cache.recs, c.selfID)
cache.mux.Unlock()
}
c.peerCacheMux.RUnlock()
return c.rp.Unregister(ctx, topic)
}
func (c *rendezvousDiscovery) Name() string {
return "rdvp"
}
func (c *rendezvousDiscovery) getSubscribtionForTopic(ctx context.Context, topic string) (<-chan peer.AddrInfo, error) {
if len(c.synccls) > 0 {
return c.rp.DiscoverSubscribe(ctx, topic, c.synccls)
}
ch := make(chan peer.AddrInfo, 16)
creg, err := c.rp.DiscoverAsync(ctx, topic)
if err != nil {
return nil, fmt.Errorf("unable to start discovery async: %w", err)
}
go func() {
defer close(ch)
for reg := range creg {
ch <- reg.Peer
}
}()
return ch, nil
}
// nolint:gochecknoinits
func init() {
p2p_rp.DiscoverAsyncInterval = time.Second * 30
}
================================================
FILE: pkg/tinder/driver_service_test.go
================================================
package tinder
import (
"context"
"fmt"
"math/rand"
"testing"
"time"
rendezvous "github.com/berty/go-libp2p-rendezvous"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/testutil"
)
type testMakeDriver = func(t *testing.T, logger *zap.Logger, p host.Host) IDriver
func TestMultipleDriversSubscribe(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
targetRdvp, _ := makeRendezvousService(t, mn)
cases := []struct {
Name string
Makes []testMakeDriver
}{
{"mocked driver", []testMakeDriver{
testMakeMockedDriverFactory(NewMockDriverServer()),
}},
{"localdisc driver", []testMakeDriver{
testMakeLocalDiscoveryDriver,
}},
{"rendezvous driver", []testMakeDriver{
testMakeRendezVousFactory(targetRdvp),
}},
{"mocked+rendezvous driver", []testMakeDriver{
testMakeMockedDriverFactory(NewMockDriverServer()),
testMakeRendezVousFactory(targetRdvp),
}},
{"localdisc+mocked+rendezvous driver", []testMakeDriver{
testMakeLocalDiscoveryDriver,
testMakeMockedDriverFactory(NewMockDriverServer()),
testMakeRendezVousFactory(targetRdvp),
}},
}
for i, tc := range cases {
topic := fmt.Sprintf("test_topic_%d", i)
t.Run(tc.Name, func(t *testing.T) {
testMultipleDriversSubscribe(t, ctx, mn, topic, tc.Makes...)
})
}
}
func testMultipleDriversSubscribe(t *testing.T, ctx context.Context, mn mocknet.Mocknet, topic string, makers ...testMakeDriver) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
var err error
var p1, p2 host.Host
var s1, s2 *Service
{
p1 = genLocalPeer(t, mn)
drivers := []IDriver{}
for _, maker := range makers {
drivers = append(drivers, maker(t, logger, p1))
}
s1, err = NewService(p1, logger, drivers...)
require.NoError(t, err)
}
{
p2 = genLocalPeer(t, mn)
drivers := []IDriver{}
for _, maker := range makers {
drivers = append(drivers, maker(t, logger, p2))
}
s2, err = NewService(p2, logger, drivers...)
require.NoError(t, err)
}
err = mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
// try a first lookup, should find nothing
{
out := s2.FindPeers(ctx, topic)
peers := testPeersChanToSlice(t, out)
require.Len(t, peers, 0, "no peer should be available")
}
// subscribe...
sub := s2.Subscribe(topic)
require.NoError(t, err)
// ...then advertise
err = s1.StartAdvertises(ctx, topic)
require.NoError(t, err)
{
// should find exactly one peer
p, err := testWaitForPeers(t, sub.Out(), time.Second*5)
require.NoError(t, err)
require.Equal(t, p1.ID(), p.ID)
require.Equal(t, p1.Addrs(), p.Addrs)
}
{
// should not have any peers left in the queue
p, err := testWaitForPeers(t, sub.Out(), time.Millisecond*100)
require.Nil(t, p)
require.Error(t, err)
}
// try a lookup again, this time we should have some peers
{
out := s2.FindPeers(ctx, topic)
p, err := testWaitForPeers(t, out, time.Second*5)
require.NoError(t, err)
require.Equal(t, p1.ID(), p.ID)
require.Equal(t, p1.Addrs(), p.Addrs)
// empty the channel, should not any peers left
err = testDrainChannel(t, out, time.Second*5)
require.NoError(t, err)
}
}
func testMakeRendezVousFactory(target peer.ID) testMakeDriver {
rng := rand.New(rand.NewSource(rand.Int63()))
return func(t *testing.T, logger *zap.Logger, p host.Host) IDriver {
t.Helper()
syncClient := rendezvous.NewSyncInMemClient(context.Background(), p)
return NewRendezvousDiscovery(logger, p, target, PrivateAddrsOnlyFactory, rng, syncClient)
}
}
func testMakeMockedDriverFactory(srv *MockDriverServer) testMakeDriver {
return func(t *testing.T, logger *zap.Logger, p host.Host) IDriver {
return srv.Client(p)
}
}
func testMakeDHTDriver(t *testing.T, logger *zap.Logger, p host.Host) IDriver {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
d, err := dht.New(ctx, p)
require.NoError(t, err)
t.Cleanup(func() { d.Close() })
return NewRoutingDiscoveryDriver("dht", d)
}
func testMakeLocalDiscoveryDriver(t *testing.T, logger *zap.Logger, p host.Host) IDriver {
t.Helper()
driver, err := NewLocalDiscovery(logger, p, rand.New(rand.NewSource(rand.Int63())))
require.NoError(t, err, "unable to make local discovery driver")
return driver
}
================================================
FILE: pkg/tinder/filter.go
================================================
package tinder
import (
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
// keep public addr only
func PublicAddrsOnlyFactory(ms []ma.Multiaddr) []ma.Multiaddr {
return ma.FilterAddrs(ms, manet.IsPublicAddr)
}
// keep private addr only
func PrivateAddrsOnlyFactory(ms []ma.Multiaddr) []ma.Multiaddr {
return ma.FilterAddrs(ms, manet.IsPrivateAddr)
}
func AllAddrsFactory(ms []ma.Multiaddr) []ma.Multiaddr { return ms }
================================================
FILE: pkg/tinder/notify_network.go
================================================
package tinder
import (
"context"
"sync"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
ma "github.com/multiformats/go-multiaddr"
"go.uber.org/zap"
"berty.tech/weshnet/v2/internal/notify"
"berty.tech/weshnet/v2/pkg/logutil"
)
type AddrsFilter = bhost.AddrsFactory
type NetworkUpdate struct {
logger *zap.Logger
notify *notify.Notify
locker *sync.Mutex
sub event.Subscription
once sync.Once
currentAddrs []ma.Multiaddr
}
func NewNetworkUpdate(logger *zap.Logger, h host.Host) (*NetworkUpdate, error) {
sub, err := h.EventBus().Subscribe(new(event.EvtLocalAddressesUpdated))
if err != nil {
return nil, err
}
locker := &sync.Mutex{}
nu := &NetworkUpdate{
logger: logger,
sub: sub,
locker: locker,
notify: notify.New(locker),
currentAddrs: h.Network().ListenAddresses(),
}
go nu.subscribeToNetworkUpdate()
nu.logger.Debug("network update subscribe started")
return nu, nil
}
func (n *NetworkUpdate) WaitForUpdate(ctx context.Context, currentAddrs []ma.Multiaddr) (diff []ma.Multiaddr, ok bool) {
n.locker.Lock()
defer n.locker.Unlock()
for {
// check for new/removed addrs
if diff := diffAddrs(currentAddrs, n.currentAddrs); len(diff) > 0 {
return diff, true
}
// wait until context is done or network is updated
if ok := n.notify.Wait(ctx); !ok {
return []ma.Multiaddr{}, false
}
}
}
func (n *NetworkUpdate) GetLastUpdatedAddrs(context.Context) (addrs []ma.Multiaddr) {
n.locker.Lock()
addrs = n.currentAddrs
n.locker.Unlock()
return
}
func (n *NetworkUpdate) subscribeToNetworkUpdate() {
for evt := range n.sub.Out() {
e := evt.(event.EvtLocalAddressesUpdated)
if e.Diffs {
// log diffs
var nadd, ndel int
for _, uaddr := range e.Current {
switch uaddr.Action {
case event.Added:
n.logger.Debug("new addr", logutil.PrivateString("addr", uaddr.Address.String()))
nadd++
case event.Removed:
n.logger.Debug("removed addr", logutil.PrivateString("addr", uaddr.Address.String()))
ndel++
}
}
n.logger.Debug("network update", zap.Int("del", ndel), zap.Int("add", nadd), zap.Int("total", nadd+ndel))
// update current addrs
n.locker.Lock()
n.currentAddrs = getAddrsFromUpdatedAddress(e.Current)
n.notify.Broadcast()
n.locker.Unlock()
}
}
}
func (n *NetworkUpdate) Close() (err error) {
// use once to avoid panic if called twice
n.once.Do(func() {
err = n.sub.Close()
})
return err
}
func diffAddrs(a, b []ma.Multiaddr) []ma.Multiaddr {
diff := []ma.Multiaddr{}
seta := make(map[string]ma.Multiaddr, len(a))
for _, addr := range a {
seta[addr.String()] = addr
}
setb := make(map[string]struct{})
for _, maddr := range b {
key := maddr.String()
if _, found := seta[key]; !found {
delete(seta, key)
diff = append(diff, maddr)
} else {
setb[key] = struct{}{}
}
}
for key, maddr := range seta {
if _, found := setb[key]; !found {
diff = append(diff, maddr)
}
}
return diff
}
func getAddrsFromUpdatedAddress(updated []event.UpdatedAddress) []ma.Multiaddr {
addrs := make([]ma.Multiaddr, len(updated))
for i, uaddr := range updated {
addrs[i] = uaddr.Address
}
return addrs
}
================================================
FILE: pkg/tinder/options.go
================================================
package tinder
type Filter map[string]struct{}
func (f Filter) ShouldFilter(name string) (yes bool) {
if f == nil {
return
}
_, yes = f[name]
return
}
type Options struct {
DriverFilters Filter
}
type Option func(opts *Options) error
func (o *Options) apply(opts ...Option) error {
for _, opt := range opts {
if err := opt(o); err != nil {
return err
}
}
return nil
}
func FilterOutDrivers(drivers ...string) Option {
return func(opts *Options) error {
opts.DriverFilters = map[string]struct{}{}
for _, driver := range drivers {
opts.DriverFilters[driver] = struct{}{}
}
return nil
}
}
================================================
FILE: pkg/tinder/peer_cache.go
================================================
package tinder
import (
"context"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
"berty.tech/weshnet/v2/internal/notify"
)
type PeersUpdate map[peer.ID]time.Time
func (current PeersUpdate) HasUpdate(tu *topicUpdate) []peer.ID {
peers := []peer.ID{}
for p, update := range tu.peerUpdate {
if lastUpdate, ok := current[p]; !ok || update.After(lastUpdate) {
current[p] = update
peers = append(peers, p)
}
}
return peers
}
type topicUpdate struct {
peerUpdate map[peer.ID]time.Time
notify *notify.Notify
}
type peersCache struct {
topics map[string]*topicUpdate
muCache sync.RWMutex
peers map[peer.ID]peer.AddrInfo
muPeers sync.RWMutex
}
func newPeerCache() *peersCache {
return &peersCache{
topics: make(map[string]*topicUpdate),
peers: make(map[peer.ID]peer.AddrInfo),
}
}
func (c *peersCache) UpdatePeer(topic string, p peer.AddrInfo) (isNew bool) {
c.muPeers.Lock()
defer c.muPeers.Unlock()
tu := c.getTopicUpdate(topic)
// update peer update time
tu.notify.L.Lock()
defer tu.notify.L.Unlock()
_, exist := tu.peerUpdate[p.ID]
// do we already know this peer ?
if prev, ok := c.peers[p.ID]; ok {
if combined := mergeAddrInfos(prev, p); combined != nil {
c.peers[p.ID] = *combined
} else if exist {
// we already know this peer, and no change have been provided
return isNew
}
} else {
c.peers[p.ID] = p
}
t := time.Now()
tu.peerUpdate[p.ID] = t
// notify topic that peers has been updated
tu.notify.Broadcast()
return true
}
func (c *peersCache) GetPeers(ids ...peer.ID) (peers []peer.AddrInfo) {
c.muPeers.RLock()
peers = make([]peer.AddrInfo, len(ids))
for i, id := range ids {
peers[i] = c.peers[id]
}
c.muPeers.RUnlock()
return
}
func (c *peersCache) GetPeersForTopics(topic string) (peers []peer.AddrInfo) {
c.muPeers.RLock()
defer c.muPeers.RUnlock()
tu := c.getTopicUpdate(topic)
tu.notify.L.Lock()
defer tu.notify.L.Unlock()
i := 0
peers = make([]peer.AddrInfo, len(tu.peerUpdate))
for peer := range tu.peerUpdate {
peers[i] = c.peers[peer]
i++
}
return
}
func (c *peersCache) WaitForPeerUpdate(ctx context.Context, topic string, current PeersUpdate) (updated []peer.ID, ok bool) {
tu := c.getTopicUpdate(topic)
tu.notify.L.Lock()
for ok = true; ok; {
// check if there are some diff between local state and the current state
if updated = current.HasUpdate(tu); !ok || len(updated) > 0 {
break // we got some update, leave the loop
}
// wait until there is an update on this group or context expire
// unlock notify locker
ok = tu.notify.Wait(ctx)
}
tu.notify.L.Unlock()
return
}
func (c *peersCache) RemoveFromCache(_ context.Context, topic string, p peer.ID) (ok bool) {
c.muCache.Lock()
var tu *topicUpdate
if tu, ok = c.topics[topic]; ok {
if _, ok = tu.peerUpdate[p]; ok {
delete(tu.peerUpdate, p)
}
}
c.muCache.Unlock()
return
}
func (c *peersCache) getTopicUpdate(topic string) *topicUpdate {
c.muCache.Lock()
tu, ok := c.topics[topic]
if !ok {
tu = &topicUpdate{
peerUpdate: make(map[peer.ID]time.Time),
notify: notify.New(&sync.Mutex{}),
}
c.topics[topic] = tu
}
c.muCache.Unlock()
return tu
}
func mergeAddrInfos(prevAi, newAi peer.AddrInfo) *peer.AddrInfo {
combinedAddrs := uniqueAddrs(prevAi.Addrs, newAi.Addrs)
if len(combinedAddrs) > len(prevAi.Addrs) {
combinedAi := &peer.AddrInfo{ID: prevAi.ID, Addrs: combinedAddrs}
return combinedAi
}
return nil
}
// uniqueAddrs merges input address lists, leave only unique addresses
func uniqueAddrs(addrss ...[]ma.Multiaddr) (uniqueAddrs []ma.Multiaddr) {
exists := make(map[string]bool)
for _, addrs := range addrss {
for _, addr := range addrs {
k := string(addr.Bytes())
if exists[k] {
continue
}
exists[k] = true
uniqueAddrs = append(uniqueAddrs, addr)
}
}
return uniqueAddrs
}
================================================
FILE: pkg/tinder/peer_cache_test.go
================================================
package tinder
import (
"context"
"runtime"
"testing"
"time"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPeerCacheUpdatePeer(t *testing.T) {
const topic = "test_topic"
if runtime.GOOS == "windows" {
t.Skip("unittest not consistent on windows, skipping.")
}
peer := peer.AddrInfo{
ID: "hello",
Addrs: []ma.Multiaddr{
ma.StringCast("/ip6/::/tcp/1234"),
},
}
pc := newPeerCache()
t.Run("add new peer", func(t *testing.T) {
pc.UpdatePeer(topic, peer)
tu, ok := pc.topics[topic]
require.True(t, ok)
require.NotNil(t, tu)
ti, ok := tu.peerUpdate[peer.ID]
require.True(t, ok)
assert.True(t, time.Now().After(ti))
speer, ok := pc.peers[peer.ID]
require.True(t, ok)
assert.Equal(t, peer, speer)
})
t.Run("edit peer multiaddrs", func(t *testing.T) {
peer.Addrs = []ma.Multiaddr{ma.StringCast("/ip4/1.2.3.4/tcp/1234")}
pc.UpdatePeer(topic, peer)
speer, ok := pc.peers[peer.ID]
require.True(t, ok)
assert.Len(t, speer.Addrs, 2)
})
}
func TestPeerCacheWaitForUpdate(t *testing.T) {
const topic = "test_topic"
pc := newPeerCache()
pu := make(PeersUpdate)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
out := make(chan []peer.ID)
go func() {
defer cancel()
for {
updated, ok := pc.WaitForPeerUpdate(ctx, topic, pu)
if !ok {
return
}
out <- updated
}
}()
t.Run("should not update on start", func(t *testing.T) {
select {
case <-out:
require.FailNow(t, "should not have received an update")
case <-ctx.Done():
require.FailNow(t, "context should not be expired")
case <-time.After(time.Millisecond * 100):
}
})
p1 := peer.AddrInfo{
ID: "peer1",
Addrs: []ma.Multiaddr{ma.StringCast("/ip4/1.2.3.4/tcp/1234")},
}
t.Run("should correctly update", func(t *testing.T) {
pc.UpdatePeer(topic, p1)
var updated []peer.ID
select {
case <-ctx.Done():
require.NoError(t, ctx.Err())
case updated = <-out:
require.Len(t, updated, 1)
}
ps := pc.GetPeers(updated...)
require.Len(t, ps, 1)
assert.Equal(t, p1, ps[0])
})
t.Run("should not update on same peer", func(t *testing.T) {
pc.UpdatePeer(topic, p1)
select {
case <-out:
require.FailNow(t, "should not have received an update")
case <-ctx.Done():
require.NoError(t, ctx.Err())
case <-time.After(time.Millisecond * 100):
}
})
p2 := peer.AddrInfo{
ID: "peer2",
Addrs: []ma.Multiaddr{ma.StringCast("/ip6/::/tcp/1234")},
}
t.Run("should update on new peer", func(t *testing.T) {
pc.UpdatePeer(topic, p2)
var updated []peer.ID
select {
case <-ctx.Done():
require.NoError(t, ctx.Err())
case updated = <-out:
require.Len(t, updated, 1)
}
ps := pc.GetPeersForTopics(topic)
require.Len(t, ps, 2)
})
}
================================================
FILE: pkg/tinder/records.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: tinder/records.proto
package tinder
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Records struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Records []*Record `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
}
func (x *Records) Reset() {
*x = Records{}
if protoimpl.UnsafeEnabled {
mi := &file_tinder_records_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Records) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Records) ProtoMessage() {}
func (x *Records) ProtoReflect() protoreflect.Message {
mi := &file_tinder_records_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Records.ProtoReflect.Descriptor instead.
func (*Records) Descriptor() ([]byte, []int) {
return file_tinder_records_proto_rawDescGZIP(), []int{0}
}
func (x *Records) GetRecords() []*Record {
if x != nil {
return x.Records
}
return nil
}
type Record struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
Expire int64 `protobuf:"varint,2,opt,name=expire,proto3" json:"expire,omitempty"`
}
func (x *Record) Reset() {
*x = Record{}
if protoimpl.UnsafeEnabled {
mi := &file_tinder_records_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Record) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Record) ProtoMessage() {}
func (x *Record) ProtoReflect() protoreflect.Message {
mi := &file_tinder_records_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Record.ProtoReflect.Descriptor instead.
func (*Record) Descriptor() ([]byte, []int) {
return file_tinder_records_proto_rawDescGZIP(), []int{1}
}
func (x *Record) GetCid() string {
if x != nil {
return x.Cid
}
return ""
}
func (x *Record) GetExpire() int64 {
if x != nil {
return x.Expire
}
return 0
}
var File_tinder_records_proto protoreflect.FileDescriptor
var file_tinder_records_proto_rawDesc = []byte{
0x0a, 0x14, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x33,
0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x72, 0x65, 0x63,
0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x69, 0x6e,
0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f,
0x72, 0x64, 0x73, 0x22, 0x32, 0x0a, 0x06, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a,
0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x42, 0x22, 0x5a, 0x20, 0x62, 0x65, 0x72, 0x74, 0x79,
0x2e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32,
0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (
file_tinder_records_proto_rawDescOnce sync.Once
file_tinder_records_proto_rawDescData = file_tinder_records_proto_rawDesc
)
func file_tinder_records_proto_rawDescGZIP() []byte {
file_tinder_records_proto_rawDescOnce.Do(func() {
file_tinder_records_proto_rawDescData = protoimpl.X.CompressGZIP(file_tinder_records_proto_rawDescData)
})
return file_tinder_records_proto_rawDescData
}
var file_tinder_records_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_tinder_records_proto_goTypes = []any{
(*Records)(nil), // 0: tinder.Records
(*Record)(nil), // 1: tinder.Record
}
var file_tinder_records_proto_depIdxs = []int32{
1, // 0: tinder.Records.records:type_name -> tinder.Record
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_tinder_records_proto_init() }
func file_tinder_records_proto_init() {
if File_tinder_records_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_tinder_records_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*Records); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tinder_records_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*Record); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_tinder_records_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_tinder_records_proto_goTypes,
DependencyIndexes: file_tinder_records_proto_depIdxs,
MessageInfos: file_tinder_records_proto_msgTypes,
}.Build()
File_tinder_records_proto = out.File
file_tinder_records_proto_rawDesc = nil
file_tinder_records_proto_goTypes = nil
file_tinder_records_proto_depIdxs = nil
}
================================================
FILE: pkg/tinder/service.go
================================================
package tinder
import (
"context"
"fmt"
"sync"
"sync/atomic"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
type Service struct {
host host.Host
logger *zap.Logger
drivers []IDriver
networkNotify *NetworkUpdate
topicCounter map[string]*Subscription
muTopics sync.Mutex
// subscribe
peersCache *peersCache
process uint32
}
func NewService(h host.Host, logger *zap.Logger, drivers ...IDriver) (*Service, error) {
nn, err := NewNetworkUpdate(logger, h)
if err != nil {
return nil, fmt.Errorf("unable to init service: %w", err)
}
return &Service{
host: h,
logger: logger.Named("tinder"),
drivers: drivers,
networkNotify: nn,
topicCounter: make(map[string]*Subscription),
peersCache: newPeerCache(),
}, nil
}
func (s *Service) FindPeers(ctx context.Context, topic string) <-chan peer.AddrInfo {
s.muTopics.Lock()
defer s.muTopics.Unlock()
ctx, cancel := context.WithCancel(ctx)
go func() {
if err := s.LookupPeers(ctx, topic); err != nil {
s.logger.Error("lookup failed", logutil.PrivateString("topic", topic), zap.Error(err))
}
cancel()
}()
return s.fadeOut(ctx, topic, 16)
}
// Unregister try to unregister topic on each of his driver
func (s *Service) Unregister(ctx context.Context, topic string) error {
var wg sync.WaitGroup
var success int32
for _, driver := range s.drivers {
wg.Add(1)
go func(driver IDriver) {
if err := driver.Unregister(ctx, topic); err != nil {
s.logger.Debug("unable to advertise", zap.Error(err))
} else {
atomic.AddInt32(&success, 1)
}
wg.Done()
}(driver)
}
wg.Wait()
if success == 0 {
return fmt.Errorf("no driver(s) were available for unregister")
}
return nil
}
func (s *Service) WatchPeers(ctx context.Context, topic string) <-chan peer.AddrInfo {
return s.fadeOut(ctx, topic, 16)
}
func (s *Service) fadeIn(ctx context.Context, topic string, in <-chan peer.AddrInfo) {
s.incProcess()
defer s.decProcess()
for {
select {
case p, ok := <-in:
if !ok {
return
}
if updated := s.peersCache.UpdatePeer(topic, p); updated {
s.logger.Debug("topic updated", zap.String("topic", topic), zap.String("peer", p.String()))
}
case <-ctx.Done():
return
}
}
}
func (s *Service) fadeOut(ctx context.Context, topic string, bufsize int) <-chan peer.AddrInfo {
out := make(chan peer.AddrInfo, bufsize)
go func() {
knownPeers := make(PeersUpdate)
for {
// Wait until `PeersCache` differ from `peerCache` peers status
updated, ok := s.peersCache.WaitForPeerUpdate(ctx, topic, knownPeers)
if !ok {
break
}
s.logger.Debug("got update on peer", zap.String("topic", topic), zap.Int("peers", len(updated)))
for _, peer := range s.peersCache.GetPeers(updated...) {
out <- peer
}
}
// we're done here, close the channel and decrement process
close(out)
}()
return out
}
func (s *Service) Close() error {
return s.networkNotify.Close()
}
func (s *Service) GetProcess() uint32 { return atomic.LoadUint32(&s.process) }
func (s *Service) incProcess() { atomic.AddUint32(&s.process, 1) }
func (s *Service) decProcess() { atomic.AddUint32(&s.process, ^(uint32)(0)) }
================================================
FILE: pkg/tinder/service_adaptater.go
================================================
package tinder
import (
"context"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
var _ discovery.Discovery = (*DiscoveryAdaptater)(nil)
type discoverySubscribtion struct {
sub *Subscription
timer *time.Timer
}
type DiscoveryAdaptater struct {
ctx context.Context
cancel context.CancelFunc
logger *zap.Logger
defaultOpts []Option
service *Service
// watchdogDiscover
watchdogDiscover map[string]*discoverySubscribtion
muDiscover sync.Mutex
// advertise
watchdogAdvertise map[string]*time.Timer
muAdvertiser sync.Mutex
resetInterval time.Duration
ttl time.Duration
closeOnce sync.Once
}
func NewDiscoveryAdaptater(logger *zap.Logger, service *Service, defaultOpts ...Option) *DiscoveryAdaptater {
ctx, cancel := context.WithCancel(context.Background())
return &DiscoveryAdaptater{
ctx: ctx,
cancel: cancel,
logger: logger.Named("disc"),
watchdogDiscover: make(map[string]*discoverySubscribtion),
watchdogAdvertise: make(map[string]*time.Timer),
service: service,
resetInterval: time.Minute * 10,
ttl: time.Minute * 5,
defaultOpts: defaultOpts,
}
}
func (a *DiscoveryAdaptater) FindPeers(_ context.Context, topic string, _ ...discovery.Option) (<-chan peer.AddrInfo, error) {
a.muDiscover.Lock()
defer a.muDiscover.Unlock()
if st, ok := a.watchdogDiscover[topic]; ok {
// already running FindPeers, reset watchdog
if !st.timer.Stop() {
<-st.timer.C
}
st.timer.Reset(a.resetInterval)
// watch again for new peers until the method expire
return st.sub.Out(), nil
}
start := time.Now()
a.logger.Debug("watchdogs looking for peers", logutil.PrivateString("topic", topic))
// filter out local discovery
sub := a.service.Subscribe(topic, a.defaultOpts...)
// pull to fetch previous peers (FindPeers)
go func() {
if err := sub.Pull(); err != nil {
a.logger.Error("unable to pull topic", zap.String("topic", topic), zap.Error(err))
}
}()
// create a new watchdog
timer := time.AfterFunc(a.resetInterval, func() {
a.logger.Debug("findpeers expired",
logutil.PrivateString("topic", topic),
zap.Duration("duration", time.Since(start)))
// watchdog has expired, cancel lookup+topic_watcher
a.muDiscover.Lock()
sub.Close()
delete(a.watchdogDiscover, topic)
a.muDiscover.Unlock()
})
a.watchdogDiscover[topic] = &discoverySubscribtion{
timer: timer,
sub: sub,
}
// watch for new peers until method context expire
return sub.Out(), nil
}
func (a *DiscoveryAdaptater) Advertise(_ context.Context, topic string, _ ...discovery.Option) (time.Duration, error) {
ctx := a.ctx
a.muAdvertiser.Lock()
defer a.muAdvertiser.Unlock()
start := time.Now()
if t, ok := a.watchdogAdvertise[topic]; ok {
// if we already advertise on this topic, reset the watchdog
if !t.Stop() {
<-t.C
}
t.Reset(a.resetInterval)
} else {
wctx, cancel := context.WithCancel(ctx)
// start advertising on this topic
// filter out local discovery
if err := a.service.StartAdvertises(wctx, topic, a.defaultOpts...); err != nil {
a.logger.Error("advertise failed", logutil.PrivateString("topic", topic), zap.Error(err))
cancel()
return time.Minute, err
}
a.logger.Debug("advertise started", logutil.PrivateString("topic", topic))
// create a new watchdog
a.watchdogAdvertise[topic] = time.AfterFunc(a.resetInterval, func() {
// watchdog has expired, cancel advertise
a.muAdvertiser.Lock()
cancel()
a.logger.Debug("advertise expired",
logutil.PrivateString("topic", topic),
zap.Duration("duration", time.Since(start)),
)
delete(a.watchdogAdvertise, topic)
a.muAdvertiser.Unlock()
// unregister from this topic if possible
if err := a.service.Unregister(ctx, topic); err != nil {
a.logger.Debug("unregister failed",
logutil.PrivateString("topic", topic),
zap.Error(err),
)
}
})
}
return a.ttl, nil
}
func (a *DiscoveryAdaptater) Close() error {
a.closeOnce.Do(func() {
a.muDiscover.Lock()
a.cancel()
for _, st := range a.watchdogDiscover {
if !st.timer.Stop() {
<-st.timer.C
}
_ = st.sub.Close()
}
a.muDiscover.Unlock()
a.muAdvertiser.Lock()
for _, t := range a.watchdogAdvertise {
if !t.Stop() {
<-t.C
}
}
a.muAdvertiser.Unlock()
})
return nil
}
================================================
FILE: pkg/tinder/service_advertises.go
================================================
package tinder
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/logutil"
)
const defaultTTL = time.Hour
// StartAdvertises topic on each of service drivers
func (s *Service) StartAdvertises(ctx context.Context, topic string, opts ...Option) error {
if len(s.drivers) == 0 {
return fmt.Errorf("no driver available to advertise")
}
var aopts Options
if err := aopts.apply(opts...); err != nil {
return fmt.Errorf("failed to advertise: %w", err)
}
for _, driver := range s.drivers {
// skip filter driver
if aopts.DriverFilters.ShouldFilter(driver.Name()) {
continue
}
// start background job
go func(driver IDriver) {
if err := s.advertise(ctx, driver, topic); err != nil {
s.logger.Debug("advertise ended", zap.Error(err))
}
}(driver)
}
return nil
}
func (s *Service) advertise(ctx context.Context, d IDriver, topic string) error {
for {
currentAddrs := s.networkNotify.GetLastUpdatedAddrs(ctx)
now := time.Now()
ttl, err := d.Advertise(ctx, topic)
took := time.Since(now)
var deadline time.Duration
if err != nil {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// retry in 30 seconds
deadline = time.Second * 30
} else {
if ttl == 0 {
ttl = defaultTTL
}
deadline = 4 * ttl / 5
}
s.logger.Debug("advertise",
zap.String("driver", d.Name()),
logutil.PrivateString("topic", topic),
zap.Duration("ttl", ttl),
zap.Duration("took", took),
zap.Duration("next", deadline),
zap.Error(err),
)
waitctx, cancel := context.WithTimeout(ctx, deadline)
// wait for network update or waitctx expire
_, ok := s.networkNotify.WaitForUpdate(waitctx, currentAddrs)
cancel()
// filter addrs
if !ok {
select {
// check for parent ctx
case <-ctx.Done():
// main context has expire, stop
return ctx.Err()
default:
// waitContext has expire, continue
}
}
}
}
================================================
FILE: pkg/tinder/service_mocked_test.go
================================================
package tinder
import (
"context"
"fmt"
"testing"
"time"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestMockedServiceSubscribeMultipleDriver(t *testing.T) {
const nPeers = 100
const topic = "test_topic"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
cases := []struct {
NDriver, NPeersPerDriver int
}{
{1, 1},
{1, 10},
{1, 100},
{100, 1},
{10, 10},
}
for _, tc := range cases {
name := fmt.Sprintf("%d_dirvers-%d_peer_per_driver", tc.NDriver, tc.NPeersPerDriver)
t.Run(name, func(t *testing.T) {
rootp, err := mn.GenPeer()
require.NoError(t, err)
clients := make([]IDriver, tc.NDriver*tc.NPeersPerDriver)
drivers := make([]IDriver, tc.NDriver)
for i := 0; i < tc.NDriver; i++ {
srv := NewMockDriverServer()
drivers[i] = srv.Client(rootp)
for j := 0; j < tc.NPeersPerDriver; j++ {
p, err := mn.GenPeer()
require.NoError(t, err)
index := tc.NPeersPerDriver*i + j
clients[index] = srv.Client(p)
}
}
service, err := NewService(rootp, zap.NewNop(), drivers...)
require.NoError(t, err)
for _, client := range clients {
_, err := client.Advertise(ctx, topic)
assert.NoError(t, err)
}
sub := service.Subscribe(topic)
defer sub.Close()
err = sub.Pull()
require.NoError(t, err)
seen := make(map[peer.ID]struct{})
var count int
for count = 0; count < len(clients); count++ {
select {
case p := <-sub.Out():
if _, ok := seen[p.ID]; ok {
require.FailNow(t, "should only receive a peer once, received")
}
seen[p.ID] = struct{}{}
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for peer", "received: %d", count)
}
}
assert.Equal(t, tc.NDriver*tc.NPeersPerDriver, count)
})
}
}
func TestMockedServiceSubscribePull(t *testing.T) {
const topic = "test_topic"
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
srv := NewMockDriverServer()
t.Run("with pull", func(t *testing.T) {
const topic = "test_topic_1"
p1, s1 := newTestMockedService(t, logger, mn, srv)
_, s2 := newTestMockedService(t, logger, mn, srv)
err := s1.StartAdvertises(ctx, topic)
require.NoError(t, err)
err = srv.WaitForPeer(topic, p1.ID(), time.Second)
require.NoError(t, err)
sub := s2.Subscribe(topic)
defer sub.Close()
err = sub.Pull()
require.NoError(t, err)
select {
case p := <-sub.Out():
assert.Equal(t, p1.ID(), p.ID)
assert.Equal(t, p1.Addrs(), p.Addrs)
case <-time.After(time.Second * 2):
require.FailNow(t, "timeout while waiting for peer")
}
})
t.Run("no pull", func(t *testing.T) {
const topic = "test_topic_2"
p1, s1 := newTestMockedService(t, logger, mn, srv)
_, s2 := newTestMockedService(t, logger, mn, srv)
err := s1.StartAdvertises(ctx, topic)
require.NoError(t, err)
err = srv.WaitForPeer(topic, p1.ID(), time.Second)
require.NoError(t, err)
sub := s2.Subscribe(topic)
defer sub.Close()
select {
case <-sub.Out():
require.FailNow(t, "do no expect peers")
case <-time.After(time.Millisecond * 500):
}
})
}
func TestMockedServiceSubscribeDuplicatePeer(t *testing.T) {
const topic = "test_topic"
const NServers = 10
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
servers := make([]*MockDriverServer, NServers)
for i := range servers {
servers[i] = NewMockDriverServer()
}
p1, s1 := newTestMockedService(t, logger, mn, servers...)
_, s2 := newTestMockedService(t, logger, mn, servers...)
err := s1.StartAdvertises(ctx, topic)
require.NoError(t, err)
for _, s := range servers {
err := s.WaitForPeer(topic, p1.ID(), time.Second)
require.NoError(t, err)
}
sub := s2.Subscribe(topic)
defer sub.Close()
err = sub.Pull()
require.NoError(t, err)
var count int
for {
select {
case p := <-sub.Out():
assert.Equal(t, p1.ID(), p.ID)
assert.Equal(t, p1.Addrs(), p.Addrs)
count++
case <-time.After(time.Millisecond * 500):
require.Equal(t, 1, count)
return
}
}
}
func newTestMockedService(t *testing.T, logger *zap.Logger, mn mocknet.Mocknet, srvs ...*MockDriverServer) (host.Host, *Service) {
t.Helper()
h, err := mn.GenPeer()
require.NoError(t, err)
drivers := make([]IDriver, len(srvs))
for i, srv := range srvs {
drivers[i] = srv.Client(h)
}
s, err := NewService(h, logger, drivers...)
require.NoError(t, err)
return h, s
}
================================================
FILE: pkg/tinder/service_subscription.go
================================================
package tinder
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p/core/peer"
"go.uber.org/zap"
)
type Subscription struct {
cancel context.CancelFunc
ctx context.Context
service *Service
topic string
out <-chan peer.AddrInfo
opts []Option
}
func (s *Subscription) Out() <-chan peer.AddrInfo {
return s.out
}
func (s *Subscription) Pull() error {
return s.service.LookupPeers(s.ctx, s.topic, s.opts...)
}
func (s *Subscription) Close() error {
s.cancel()
return nil
}
func (s *Service) Subscribe(topic string, opts ...Option) *Subscription {
ctx, cancel := context.WithCancel(context.Background())
out := s.fadeOut(ctx, topic, 16)
err := s.WatchTopic(ctx, topic, opts...)
if err != nil {
s.logger.Warn("unable to watch topic", zap.String("topic", topic), zap.Error(err))
}
return &Subscription{
service: s,
out: out,
ctx: ctx,
cancel: cancel,
topic: topic,
opts: opts,
}
}
func (s *Service) LookupPeers(ctx context.Context, topic string, opts ...Option) error {
var success int
var aopts Options
if err := aopts.apply(opts...); err != nil {
return fmt.Errorf("unable to apply option: %w", err)
}
for _, d := range s.drivers {
if aopts.DriverFilters.ShouldFilter(d.Name()) {
continue
}
in, err := d.FindPeers(ctx, topic) // find peers should not hang there
switch err {
case nil: // ok
success++
s.logger.Debug("lookup for topic started", zap.String("driver", d.Name()), zap.String("topic", topic))
go s.fadeIn(ctx, topic, in)
case ErrNotSupported: // do nothing
default:
s.logger.Error("lookup failed",
zap.String("driver", d.Name()), zap.String("topic", topic), zap.Error(err))
}
}
if success == 0 {
return fmt.Errorf("no driver(s) were available for lookup")
}
return nil
}
func (s *Service) WatchTopic(ctx context.Context, topic string, opts ...Option) (err error) {
var success int
var aopts Options
if err := aopts.apply(opts...); err != nil {
return fmt.Errorf("unable to apply option: %w", err)
}
for _, d := range s.drivers {
if aopts.DriverFilters.ShouldFilter(d.Name()) {
continue
}
s.logger.Debug("start subscribe", zap.String("driver", d.Name()), zap.String("topic", topic))
in, err := d.Subscribe(ctx, topic)
switch err {
case nil: // ok, start fadin
success++
s.logger.Debug("watching for topic update", zap.String("driver", d.Name()), zap.String("topic", topic))
go s.fadeIn(ctx, topic, in)
case ErrNotSupported: // not, supported skipping
default:
s.logger.Error("unable to subscribe on topic",
zap.String("driver", d.Name()), zap.String("topic", topic), zap.Error(err))
}
}
if success == 0 {
err = fmt.Errorf("no driver(s) were available for subscribe")
}
return err
}
================================================
FILE: pkg/tinder/testing_test.go
================================================
package tinder
import (
"context"
"fmt"
"testing"
"time"
rendezvous "github.com/berty/go-libp2p-rendezvous"
dbrdvp "github.com/berty/go-libp2p-rendezvous/db/sqlite"
p2putil "github.com/libp2p/go-libp2p-testing/netutil"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
)
var (
ErrChannelNotEmpty = fmt.Errorf("channel not empty")
ErrChannelTimeout = fmt.Errorf("waiting for channel: timeout")
)
func makeRendezvousService(t *testing.T, mn mocknet.Mocknet) (target peer.ID, svc *rendezvous.RendezvousService) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
peer, err := mn.GenPeer()
require.NoError(t, err)
pubsubsync, err := rendezvous.NewSyncInMemProvider(peer)
require.NoError(t, err)
dbi, err := dbrdvp.OpenDB(ctx, ":memory:")
require.NoError(t, err)
t.Cleanup(func() { _ = dbi.Close() })
return peer.ID(), rendezvous.NewRendezvousService(peer, dbi, pubsubsync)
}
func testWaitForPeers(t *testing.T, out <-chan peer.AddrInfo, timeout time.Duration) (*peer.AddrInfo, error) {
t.Helper()
select {
case p := <-out:
return &p, nil
case <-time.After(timeout):
return nil, fmt.Errorf("timeout while waiting for peer")
}
}
func testDrainChannel(t *testing.T, out <-chan peer.AddrInfo, timeout time.Duration) error {
t.Helper()
for {
select {
case _, ok := <-out:
if !ok {
return nil // ok
}
return fmt.Errorf("channel wasn't empty")
case <-time.After(timeout):
return fmt.Errorf("timeout while waiting for peer")
}
}
}
func testPeersChanToSlice(t *testing.T, out <-chan peer.AddrInfo) (peers []*peer.AddrInfo) {
t.Helper()
peers = []*peer.AddrInfo{}
for p := range out {
peers = append(peers, &p)
}
return
}
func genLocalPeer(t *testing.T, mn mocknet.Mocknet) host.Host {
sk, err := p2putil.RandTestBogusPrivateKey()
require.NoError(t, err)
a, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
require.NoError(t, err)
h, err := mn.AddPeer(sk, a)
require.NoError(t, err)
return h
}
================================================
FILE: pkg/tyber/context.go
================================================
package tyber
import (
"context"
"strconv"
"time"
"github.com/gofrs/uuid"
"google.golang.org/grpc/metadata"
)
type traceIDKeyType string
const (
traceIDKey traceIDKeyType = "TyberTraceID"
noTraceID string = "no_trace_id"
uuidFallback string = "409123fa-4dd5-11eb-a4a1-675173c25b22"
)
var (
NewSessionID = newID
NewTraceID = newID
)
func ContextWithTraceID(ctx context.Context) (context.Context, bool) {
if eid := GetTraceIDFromContext(ctx); eid != noTraceID {
return ctx, false
}
if md, ok := metadata.FromIncomingContext(ctx); ok {
if vals := md.Get(string(traceIDKey)); len(vals) != 0 {
return ContextWithConstantTraceID(ctx, vals[0]), false
}
}
return ContextWithConstantTraceID(ctx, NewTraceID()), true
}
func ContextWithConstantTraceID(ctx context.Context, traceID string) context.Context {
md, ok := metadata.FromOutgoingContext(ctx)
if ok {
md = md.Copy()
} else {
md = metadata.New(nil)
}
md.Set(string(traceIDKey), traceID)
return metadata.NewOutgoingContext(context.WithValue(ctx, traceIDKey, traceID), md)
}
func GetTraceIDFromContext(ctx context.Context) string {
if val, ok := ctx.Value(traceIDKey).(string); ok {
return val
}
return noTraceID
}
func ContextWithoutTraceID(ctx context.Context) context.Context {
return ContextWithConstantTraceID(ctx, noTraceID)
}
func newID() string {
uid, err := uuid.NewV4()
// If error while reading random, fallback on uuid v5
if err != nil {
ns, err := uuid.FromString(uuidFallback)
if err != nil {
panic(err) // Should never happen
}
n := strconv.FormatInt(time.Now().UnixNano(), 10)
uid = uuid.NewV5(ns, n)
}
return uid.String()
}
================================================
FILE: pkg/tyber/format.go
================================================
package tyber
import (
"context"
"encoding/json"
"fmt"
"slices"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type Detail struct {
Name string `json:"name"`
Description string `json:"description"`
}
func safeJSONMarshal(v any) string {
bs, err := json.MarshalIndent(v, "", " ")
if err != nil {
return fmt.Sprintf(`"%s"`, err.Error())
}
return string(bs)
}
func JSONDetail(name string, val any) Detail {
return Detail{Name: name, Description: safeJSONMarshal(val)}
}
func WithJSONDetail(name string, val any) StepMutator {
return func(s Step) Step {
s.Details = append(s.Details, JSONDetail(name, val))
return s
}
}
func WithError(err error) StepMutator {
return func(s Step) Step {
s.Details = append(s.Details, Detail{Name: "Error", Description: err.Error()})
return s
}
}
type LogType string
const (
TraceType LogType = "trace"
StepType LogType = "step"
EventType LogType = "event"
SubscribeType LogType = "subcribe"
)
var KnownLogTypes = []LogType{TraceType, StepType, EventType, SubscribeType}
func (lt LogType) IsKnown() bool {
return slices.Contains(KnownLogTypes, lt)
}
type StatusType string
const (
Running StatusType = "running"
Succeeded StatusType = "succeeded"
Failed StatusType = "failed"
)
type Trace struct {
TraceID string `json:"traceID"`
}
type Event struct {
Details []Detail `json:"details"`
}
func FormatTraceLogFields(ctx context.Context) []zapcore.Field {
return []zapcore.Field{
zap.String("tyberLogType", string(TraceType)),
zap.Any("trace", Trace{
TraceID: GetTraceIDFromContext(ctx),
}),
}
}
func FormatEventLogFields(_ context.Context, details []Detail) []zapcore.Field {
return []zapcore.Field{
zap.String("tyberLogType", string(EventType)),
zap.Any("event", Event{
Details: details,
}),
}
}
func ZapFieldsToDetails(fields ...zap.Field) []Detail {
dets := make([]Detail, len(fields))
for i, field := range fields {
dets[i] = Detail{Name: field.Key, Description: field.String}
}
return dets
}
================================================
FILE: pkg/tyber/ipfs.go
================================================
package tyber
import (
ipfscid "github.com/ipfs/go-cid"
)
func WithCIDDetail(name string, cidBytes []byte) StepMutator {
cid, err := ipfscid.Cast(cidBytes)
if err != nil {
return func(s Step) Step { return s }
}
return func(s Step) Step {
s.Details = append(s.Details, Detail{Name: name, Description: cid.String()})
return s
}
}
================================================
FILE: pkg/tyber/log.go
================================================
package tyber
import (
"context"
"go.uber.org/zap"
)
const tyberLogNS = "tyber"
func LogError(ctx context.Context, logger *zap.Logger, text string, err error, mutators ...StepMutator) error {
if logger == nil {
return err
}
logger.Named(tyberLogNS).Error(
text,
FormatStepLogFields(ctx, []Detail{{Name: "Error", Description: err.Error()}}, mutators...)...,
)
// returning the input error for better usage syntax
return err
}
func LogFatalError(ctx context.Context, logger *zap.Logger, text string, err error, mutators ...StepMutator) error {
return LogError(ctx, logger, text, err, append(mutators, Fatal)...)
}
func LogTraceEnd(ctx context.Context, logger *zap.Logger, text string, mutators ...StepMutator) {
logger.Named(tyberLogNS).Debug(text, FormatStepLogFields(ctx, []Detail{}, append(mutators, EndTrace)...)...)
}
func LogTraceStart(ctx context.Context, logger *zap.Logger, text string) {
logger.Named(tyberLogNS).Debug(text, FormatTraceLogFields(ctx)...)
}
func LogStep(ctx context.Context, logger *zap.Logger, text string, mutators ...StepMutator) {
logger.Named(tyberLogNS).Debug(text, FormatStepLogFields(ctx, []Detail{}, mutators...)...)
}
================================================
FILE: pkg/tyber/section.go
================================================
package tyber
import (
"context"
"go.uber.org/zap"
)
func Section(ctx context.Context, logger *zap.Logger, name string) (context.Context, bool, func(error, string, ...StepMutator)) {
ctx, newTrace := ContextWithTraceID(ctx)
if newTrace {
LogTraceStart(ctx, logger, name)
} else {
LogStep(ctx, logger, name)
}
return ctx, newTrace, func(err error, rename string, muts ...StepMutator) {
if err != nil {
errorName := "Error while " + name
if rename != "" {
errorName = rename
}
if newTrace {
_ = LogFatalError(ctx, logger, errorName, err, muts...)
} else {
_ = LogError(ctx, logger, errorName, err, muts...)
}
} else {
successName := name + " succeeded"
if rename != "" {
successName = rename
}
if newTrace {
LogTraceEnd(ctx, logger, successName, muts...)
} else {
LogStep(ctx, logger, successName, muts...)
}
}
}
}
func SimpleSection(ctx context.Context, logger *zap.Logger, name string) func(error, ...StepMutator) {
_, _, end := Section(ctx, logger, name)
return func(err error, muts ...StepMutator) { end(err, "", muts...) }
}
================================================
FILE: pkg/tyber/step.go
================================================
package tyber
import (
"context"
"runtime/debug"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// types
type Step struct {
ParentTraceID string `json:"parentTraceID"`
Details []Detail `json:"details"`
Status StatusType `json:"status"`
EndTrace bool `json:"endTrace"`
UpdateTraceName string `json:"updateTraceName"`
ForceReopen bool `json:"forceReopen"`
}
type StepMutator = func(Step) Step
// zap format
func FormatStepLogFields(ctx context.Context, details []Detail, mutators ...StepMutator) []zapcore.Field {
s := Step{
ParentTraceID: GetTraceIDFromContext(ctx),
Status: Succeeded,
Details: details,
EndTrace: false,
ForceReopen: false,
}
for _, m := range mutators {
s = m(s)
}
// Add debug if a there is no parent trace ID
if s.ParentTraceID == noTraceID {
s.Details = append(s.Details, Detail{Name: "StackTrace", Description: string(debug.Stack())})
}
return []zapcore.Field{
zap.String("tyberLogType", string(StepType)),
zap.Any("step", s),
}
}
// constant mutators
func ForceReopen(s Step) Step {
s.ForceReopen = true
return s
}
func EndTrace(s Step) Step {
s.EndTrace = true
return s
}
func Fatal(s Step) Step {
s.EndTrace = true
s.Status = Failed
return s
}
// variable mutators
func Status(st StatusType) StepMutator {
return func(s Step) Step {
s.Status = st
return s
}
}
func UpdateTraceName(newTitle string) StepMutator {
return func(s Step) Step {
s.UpdateTraceName = newTitle
return s
}
}
func WithDetail(name string, description string) StepMutator {
return func(s Step) Step {
s.Details = append(s.Details, Detail{Name: name, Description: description})
return s
}
}
================================================
FILE: pkg/tyber/subscribe.go
================================================
package tyber
import (
"context"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type Subscribe struct {
TargetStepName string `json:"targetStepName"`
TargetDetails []Detail `json:"targetDetails"`
StepToAdd Step `json:"stepToAdd"`
}
func FormatSubscribeLogFields(ctx context.Context, targetName string, targetDetails []Detail, stepToAddMutators ...StepMutator) []zapcore.Field {
sta := Step{
ParentTraceID: GetTraceIDFromContext(ctx),
Status: Succeeded,
}
for _, m := range stepToAddMutators {
sta = m(sta)
}
return []zapcore.Field{
zap.String("tyberLogType", string(SubscribeType)),
zap.Any("subscribe", Subscribe{
TargetStepName: targetName,
TargetDetails: targetDetails,
StepToAdd: sta,
}),
}
}
================================================
FILE: pkg/username/android.go
================================================
//go:build android
package username
/*
#include
#include
#include
// Could be improved using Android Java API
// https://medium.com/capital-one-tech/how-to-get-an-android-device-nickname-d5eab12f4ced
const char* GetDeviceName() {
char model[PROP_VALUE_MAX + 1];
int len = __system_property_get("ro.product.model", model);
char *name = malloc(len + 1);
memcpy(name, model, len);
name[len] = 0;
return name;
}
*/
import "C"
import "unsafe"
const defaultUsername = "android#1337"
func getUsername() string {
cstring := C.GetDeviceName()
username := C.GoString(cstring)
C.free(unsafe.Pointer(cstring))
return username
}
================================================
FILE: pkg/username/example_test.go
================================================
package username_test
================================================
FILE: pkg/username/ios.go
================================================
//go:build ios && !catalyst
package username
/*
#cgo CFLAGS: -x objective-c
#cgo darwin LDFLAGS: -framework Foundation -framework UIKit
#import
#import
const char* GetDeviceName() {
NSString *deviceName = [[UIDevice currentDevice] name];
char *copy = strdup([deviceName UTF8String]);
return copy;
}
*/
import "C"
import "unsafe"
const defaultUsername = "ios#1337"
func getUsername() string {
cstring := C.GetDeviceName()
username := C.GoString(cstring)
C.free(unsafe.Pointer(cstring))
return username
}
================================================
FILE: pkg/username/others.go
================================================
//go:build (!android && !ios) || (ios && catalyst)
package username
import "os/user"
const defaultUsername = "anon#1337"
func getUsername() string {
user, err := user.Current()
if err != nil || user == nil {
return ""
}
return user.Name
}
================================================
FILE: pkg/username/username.go
================================================
package username
import "strings"
func GetUsername() string {
username := getUsername()
trimed := strings.TrimSpace(username)
if trimed != "" {
return trimed
}
return defaultUsername
}
================================================
FILE: pkg/verifiablecredstypes/bertyverifiablecreds.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc (unknown)
// source: verifiablecredstypes/bertyverifiablecreds.proto
package verifiablecredstypes
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type FlowType int32
const (
FlowType_FlowTypeUndefined FlowType = 0
// FlowTypeCode asks users a code sent on a side channel
FlowType_FlowTypeCode FlowType = 1
// FlowTypeAuth currently unimplemented
FlowType_FlowTypeAuth FlowType = 2
// FlowTypeProof currently unimplemented
FlowType_FlowTypeProof FlowType = 3
)
// Enum value maps for FlowType.
var (
FlowType_name = map[int32]string{
0: "FlowTypeUndefined",
1: "FlowTypeCode",
2: "FlowTypeAuth",
3: "FlowTypeProof",
}
FlowType_value = map[string]int32{
"FlowTypeUndefined": 0,
"FlowTypeCode": 1,
"FlowTypeAuth": 2,
"FlowTypeProof": 3,
}
)
func (x FlowType) Enum() *FlowType {
p := new(FlowType)
*p = x
return p
}
func (x FlowType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (FlowType) Descriptor() protoreflect.EnumDescriptor {
return file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes[0].Descriptor()
}
func (FlowType) Type() protoreflect.EnumType {
return &file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes[0]
}
func (x FlowType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use FlowType.Descriptor instead.
func (FlowType) EnumDescriptor() ([]byte, []int) {
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP(), []int{0}
}
type CodeStrategy int32
const (
CodeStrategy_CodeStrategyUndefined CodeStrategy = 0
// CodeStrategy6Digits currently unimplemented
CodeStrategy_CodeStrategy6Digits CodeStrategy = 1
// CodeStrategy10Chars currently unimplemented
CodeStrategy_CodeStrategy10Chars CodeStrategy = 2
// CodeStrategyMocked6Zeroes must only be used in testing
CodeStrategy_CodeStrategyMocked6Zeroes CodeStrategy = 999
)
// Enum value maps for CodeStrategy.
var (
CodeStrategy_name = map[int32]string{
0: "CodeStrategyUndefined",
1: "CodeStrategy6Digits",
2: "CodeStrategy10Chars",
999: "CodeStrategyMocked6Zeroes",
}
CodeStrategy_value = map[string]int32{
"CodeStrategyUndefined": 0,
"CodeStrategy6Digits": 1,
"CodeStrategy10Chars": 2,
"CodeStrategyMocked6Zeroes": 999,
}
)
func (x CodeStrategy) Enum() *CodeStrategy {
p := new(CodeStrategy)
*p = x
return p
}
func (x CodeStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (CodeStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes[1].Descriptor()
}
func (CodeStrategy) Type() protoreflect.EnumType {
return &file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes[1]
}
func (x CodeStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use CodeStrategy.Descriptor instead.
func (CodeStrategy) EnumDescriptor() ([]byte, []int) {
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP(), []int{1}
}
// StateChallenge serialized and signed state used when requesting a challenge
type StateChallenge struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Timestamp []byte `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
BertyLink string `protobuf:"bytes,3,opt,name=berty_link,json=bertyLink,proto3" json:"berty_link,omitempty"`
RedirectUri string `protobuf:"bytes,4,opt,name=redirect_uri,json=redirectUri,proto3" json:"redirect_uri,omitempty"`
State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *StateChallenge) Reset() {
*x = StateChallenge{}
if protoimpl.UnsafeEnabled {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StateChallenge) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateChallenge) ProtoMessage() {}
func (x *StateChallenge) ProtoReflect() protoreflect.Message {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateChallenge.ProtoReflect.Descriptor instead.
func (*StateChallenge) Descriptor() ([]byte, []int) {
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP(), []int{0}
}
func (x *StateChallenge) GetTimestamp() []byte {
if x != nil {
return x.Timestamp
}
return nil
}
func (x *StateChallenge) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
func (x *StateChallenge) GetBertyLink() string {
if x != nil {
return x.BertyLink
}
return ""
}
func (x *StateChallenge) GetRedirectUri() string {
if x != nil {
return x.RedirectUri
}
return ""
}
func (x *StateChallenge) GetState() string {
if x != nil {
return x.State
}
return ""
}
// StateCode serialized and signed state used when requesting a code
type StateCode struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Timestamp []byte `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
BertyLink string `protobuf:"bytes,2,opt,name=berty_link,json=bertyLink,proto3" json:"berty_link,omitempty"`
CodeStrategy CodeStrategy `protobuf:"varint,3,opt,name=code_strategy,json=codeStrategy,proto3,enum=weshnet.account.v1.CodeStrategy" json:"code_strategy,omitempty"`
Identifier string `protobuf:"bytes,4,opt,name=identifier,proto3" json:"identifier,omitempty"`
Code string `protobuf:"bytes,5,opt,name=code,proto3" json:"code,omitempty"`
RedirectUri string `protobuf:"bytes,6,opt,name=redirect_uri,json=redirectUri,proto3" json:"redirect_uri,omitempty"`
State string `protobuf:"bytes,7,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *StateCode) Reset() {
*x = StateCode{}
if protoimpl.UnsafeEnabled {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StateCode) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StateCode) ProtoMessage() {}
func (x *StateCode) ProtoReflect() protoreflect.Message {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StateCode.ProtoReflect.Descriptor instead.
func (*StateCode) Descriptor() ([]byte, []int) {
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP(), []int{1}
}
func (x *StateCode) GetTimestamp() []byte {
if x != nil {
return x.Timestamp
}
return nil
}
func (x *StateCode) GetBertyLink() string {
if x != nil {
return x.BertyLink
}
return ""
}
func (x *StateCode) GetCodeStrategy() CodeStrategy {
if x != nil {
return x.CodeStrategy
}
return CodeStrategy_CodeStrategyUndefined
}
func (x *StateCode) GetIdentifier() string {
if x != nil {
return x.Identifier
}
return ""
}
func (x *StateCode) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
func (x *StateCode) GetRedirectUri() string {
if x != nil {
return x.RedirectUri
}
return ""
}
func (x *StateCode) GetState() string {
if x != nil {
return x.State
}
return ""
}
type AccountCryptoChallenge struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Challenge string `protobuf:"bytes,1,opt,name=challenge,proto3" json:"challenge,omitempty"`
}
func (x *AccountCryptoChallenge) Reset() {
*x = AccountCryptoChallenge{}
if protoimpl.UnsafeEnabled {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AccountCryptoChallenge) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AccountCryptoChallenge) ProtoMessage() {}
func (x *AccountCryptoChallenge) ProtoReflect() protoreflect.Message {
mi := &file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AccountCryptoChallenge.ProtoReflect.Descriptor instead.
func (*AccountCryptoChallenge) Descriptor() ([]byte, []int) {
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP(), []int{2}
}
func (x *AccountCryptoChallenge) GetChallenge() string {
if x != nil {
return x.Challenge
}
return ""
}
var File_verifiablecredstypes_bertyverifiablecreds_proto protoreflect.FileDescriptor
var file_verifiablecredstypes_bertyverifiablecreds_proto_rawDesc = []byte{
0x0a, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x63, 0x72, 0x65, 0x64,
0x73, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x62, 0x65, 0x72, 0x74, 0x79, 0x76, 0x65, 0x72, 0x69,
0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x12, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43,
0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
0x62, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x62, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x21, 0x0a, 0x0c, 0x72,
0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x69, 0x12, 0x14,
0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73,
0x74, 0x61, 0x74, 0x65, 0x22, 0xfc, 0x01, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x6f,
0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x6e, 0x6b, 0x12,
0x45, 0x0a, 0x0d, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74,
0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x64, 0x65,
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0c, 0x63, 0x6f, 0x64, 0x65, 0x53, 0x74,
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x66, 0x69, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65,
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0b, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x69, 0x12, 0x14, 0x0a,
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74,
0x61, 0x74, 0x65, 0x22, 0x36, 0x0a, 0x16, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x43, 0x72,
0x79, 0x70, 0x74, 0x6f, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x2a, 0x58, 0x0a, 0x08, 0x46,
0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x46, 0x6c, 0x6f, 0x77, 0x54,
0x79, 0x70, 0x65, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00, 0x12, 0x10,
0x0a, 0x0c, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x10, 0x01,
0x12, 0x10, 0x0a, 0x0c, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x41, 0x75, 0x74, 0x68,
0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x46, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x50, 0x72,
0x6f, 0x6f, 0x66, 0x10, 0x03, 0x2a, 0x7b, 0x0a, 0x0c, 0x43, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x72,
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x72,
0x61, 0x74, 0x65, 0x67, 0x79, 0x55, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x10, 0x00,
0x12, 0x17, 0x0a, 0x13, 0x43, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x36, 0x44, 0x69, 0x67, 0x69, 0x74, 0x73, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x6f, 0x64,
0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x31, 0x30, 0x43, 0x68, 0x61, 0x72, 0x73,
0x10, 0x02, 0x12, 0x1e, 0x0a, 0x19, 0x43, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x4d, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x36, 0x5a, 0x65, 0x72, 0x6f, 0x65, 0x73, 0x10,
0xe7, 0x07, 0x42, 0x30, 0x5a, 0x2e, 0x62, 0x65, 0x72, 0x74, 0x79, 0x2e, 0x74, 0x65, 0x63, 0x68,
0x2f, 0x77, 0x65, 0x73, 0x68, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x63, 0x72, 0x65, 0x64, 0x73, 0x74,
0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescOnce sync.Once
file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescData = file_verifiablecredstypes_bertyverifiablecreds_proto_rawDesc
)
func file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescGZIP() []byte {
file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescOnce.Do(func() {
file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescData = protoimpl.X.CompressGZIP(file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescData)
})
return file_verifiablecredstypes_bertyverifiablecreds_proto_rawDescData
}
var file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_verifiablecredstypes_bertyverifiablecreds_proto_goTypes = []any{
(FlowType)(0), // 0: weshnet.account.v1.FlowType
(CodeStrategy)(0), // 1: weshnet.account.v1.CodeStrategy
(*StateChallenge)(nil), // 2: weshnet.account.v1.StateChallenge
(*StateCode)(nil), // 3: weshnet.account.v1.StateCode
(*AccountCryptoChallenge)(nil), // 4: weshnet.account.v1.AccountCryptoChallenge
}
var file_verifiablecredstypes_bertyverifiablecreds_proto_depIdxs = []int32{
1, // 0: weshnet.account.v1.StateCode.code_strategy:type_name -> weshnet.account.v1.CodeStrategy
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_verifiablecredstypes_bertyverifiablecreds_proto_init() }
func file_verifiablecredstypes_bertyverifiablecreds_proto_init() {
if File_verifiablecredstypes_bertyverifiablecreds_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*StateChallenge); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*StateCode); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*AccountCryptoChallenge); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_verifiablecredstypes_bertyverifiablecreds_proto_rawDesc,
NumEnums: 2,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_verifiablecredstypes_bertyverifiablecreds_proto_goTypes,
DependencyIndexes: file_verifiablecredstypes_bertyverifiablecreds_proto_depIdxs,
EnumInfos: file_verifiablecredstypes_bertyverifiablecreds_proto_enumTypes,
MessageInfos: file_verifiablecredstypes_bertyverifiablecreds_proto_msgTypes,
}.Build()
File_verifiablecredstypes_bertyverifiablecreds_proto = out.File
file_verifiablecredstypes_bertyverifiablecreds_proto_rawDesc = nil
file_verifiablecredstypes_bertyverifiablecreds_proto_goTypes = nil
file_verifiablecredstypes_bertyverifiablecreds_proto_depIdxs = nil
}
================================================
FILE: scenario_test.go
================================================
package weshnet_test
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"os"
"sync"
"sync/atomic"
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
weshnet "berty.tech/weshnet/v2"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
)
type testCase struct {
Name string
NumberOfClient int
ConnectFunc weshnet.ConnectTestingProtocolFunc
Speed testutil.Speed
Stability testutil.Stability
Timeout time.Duration
}
type testFunc func(context.Context, *testing.T, ...*weshnet.TestingProtocol)
// Tests
func TestScenario_CreateMultiMemberGroup(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"3 clients/connectInLine", 3, weshnet.ConnectInLine, testutil.Fast, testutil.Flappy, time.Second * 10},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 20},
{"5 clients/connectInLine", 5, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 20},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 60},
{"8 clients/connectInLine", 8, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 60},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 90},
{"10 clients/connectInLine", 10, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 90},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
createMultiMemberGroup(ctx, t, tps...)
})
}
func TestScenario_MessageMultiMemberGroup(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"3 clients/connectInLine", 3, weshnet.ConnectInLine, testutil.Fast, testutil.Flappy, time.Second * 10},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 20},
{"5 clients/connectInLine", 5, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 20},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 40},
{"8 clients/connectInLine", 8, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 40},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 90},
{"10 clients/connectInLine", 10, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 90},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
// Create MultiMember Group
groupID := createMultiMemberGroup(ctx, t, tps...)
// Each member sends 3 messages on MultiMember Group
messages := []string{"test1", "test2", "test3"}
sendMessageOnGroup(ctx, t, tps, tps, groupID, messages)
})
}
func TestScenario_GroupDeviceStatusOnMultiMemberGroup(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 10},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 20},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 60},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 90},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
// Create MultiMember Group
groupID := createMultiMemberGroup(ctx, t, tps...)
testGroupDeviceStatus(ctx, t, groupID, tps...)
})
}
func testGroupDeviceStatus(ctx context.Context, t *testing.T, groupID []byte, tps ...*weshnet.TestingProtocol) {
ntps := len(tps)
// Get group device status
{
testutil.LogTree(t, "Get Group Device Status", 1, true)
start := time.Now()
wg := sync.WaitGroup{}
statusReceivedLock := sync.Mutex{}
statusReceived := make([]map[string]struct{}, ntps)
wg.Add(ntps)
nSuccess := int64(0)
for i := range tps {
go func(i int) {
tp := tps[i]
defer wg.Done()
statusReceived[i] = map[string]struct{}{}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
sub, inErr := tp.Client.GroupDeviceStatus(ctx, &protocoltypes.GroupDeviceStatus_Request{
GroupPk: groupID,
})
if inErr != nil {
assert.NoError(t, inErr, fmt.Sprintf("error for client %d", i))
return
}
for {
evt, inErr := sub.Recv()
if inErr != nil {
if inErr != io.EOF {
assert.NoError(t, inErr, fmt.Sprintf("error for client %d", i))
}
break
}
assert.Equal(t, evt.Type, protocoltypes.GroupDeviceStatus_TypePeerConnected)
connected := &protocoltypes.GroupDeviceStatus_Reply_PeerConnected{}
err := proto.Unmarshal(evt.Event, connected)
assert.NoError(t, err, fmt.Sprintf("Unmarshal error for client %d", i))
statusReceivedLock.Lock()
statusReceived[i][connected.PeerId] = struct{}{}
done := len(statusReceived[i]) == ntps-1
statusReceivedLock.Unlock()
if done {
n := atomic.AddInt64(&nSuccess, 1)
got := fmt.Sprintf("%d/%d", n, ntps)
tps[i].Opts.Logger.Debug("received all group device status", zap.String("ok", got))
return
}
}
}(i)
}
wg.Wait()
statusReceivedLock.Lock()
ok := true
for i := range statusReceived {
if !assert.Equal(t, ntps-1, len(statusReceived[i]), fmt.Sprintf("mismatch for client %d", i)) {
ok = false
}
}
require.True(t, ok)
statusReceivedLock.Unlock()
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
}
//
//func TestScenario_MessageMultiMemberGroup2(t *testing.T) {
// cases := []testCase{
// {"2 clients/connectAll", 2, ConnectAll, testutil.Fast, testutil.Stable, time.Second * 60},
// }
//
// testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*TestingProtocol) {
// // Create MultiMember Group
// groupID := createMultiMemberGroup(ctx, t, tps...)
//
// const messageCount = 100
// // Each member sends 3 messages on MultiMember Group
// messages := make([]string, messageCount)
// for i := 0; i < messageCount; i++ {
// messages[i] = fmt.Sprintf("test%d", i)
// }
//
// sendMessageOnGroup(ctx, t, tps, tps, groupID, messages)
// })
//}
func TestScenario_MessageSeveralMultiMemberGroups(t *testing.T) {
const ngroup = 3
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"3 clients/connectInLine", 3, weshnet.ConnectInLine, testutil.Fast, testutil.Flappy, time.Second * 20},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 60},
{"5 clients/connectInLine", 5, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 60},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 180},
{"8 clients/connectInLine", 8, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 180},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 300},
{"10 clients/connectInLine", 10, weshnet.ConnectInLine, testutil.Slow, testutil.Flappy, time.Second * 300},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
for i := 0; i < ngroup; i++ {
t.Logf("===== MultiMember Group #%d =====", i+1)
// Create MultiMember Group
groupID := createMultiMemberGroup(ctx, t, tps...)
// Each member sends 3 messages on MultiMember Group
messages := []string{"test1", "test2", "test3"}
sendMessageOnGroup(ctx, t, tps, tps, groupID, messages)
}
})
}
func TestScenario_AddContact(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 30},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 40},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 60},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
addAsContact(ctx, t, tps, tps)
})
}
func TestScenario_MessageContactGroup(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Flappy, time.Second * 20},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Flappy, time.Second * 30},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 40},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 60},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
// Add accounts as contacts
addAsContact(ctx, t, tps, tps)
// Send messages between all accounts on contact groups
messages := []string{"test1", "test2", "test3"}
sendMessageToContact(ctx, t, messages, tps)
})
}
func TestScenario_MessageAccountGroup(t *testing.T) {
cases := []testCase{
{"1 client/connectAll", 1, weshnet.ConnectAll, testutil.Fast, testutil.Stable, time.Second * 10},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
// Get account config
config, err := tps[0].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config)
// Send messages on account group
messages := []string{"test1", "test2", "test3"}
sendMessageOnGroup(ctx, t, tps, tps, config.AccountGroupPk, messages)
})
}
func TestScenario_MessageAccountGroup_NonMocked(t *testing.T) {
cases := []testCase{
{"1 client/connectAll", 1, weshnet.ConnectAll, testutil.Fast, testutil.Stable, time.Second * 10},
}
testingScenarioNonMocked(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
// Get account config
config, err := tps[0].Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config)
// Send messages on account group
messages := []string{"test1", "test2", "test3"}
sendMessageOnGroup(ctx, t, tps, tps, config.AccountGroupPk, messages)
})
}
func TestScenario_MessageAccountAndMultiMemberGroups(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Broken, time.Second * 10},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Broken, time.Second * 10},
{"3 clients/connectInLine", 3, weshnet.ConnectInLine, testutil.Fast, testutil.Broken, time.Second * 10},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 20},
{"5 clients/connectInLine", 5, weshnet.ConnectInLine, testutil.Slow, testutil.Broken, time.Second * 20},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 30},
{"8 clients/connectInLine", 8, weshnet.ConnectInLine, testutil.Slow, testutil.Broken, time.Second * 30},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 40},
{"10 clients/connectInLine", 10, weshnet.ConnectInLine, testutil.Slow, testutil.Broken, time.Second * 40},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
t.Log("===== Send Messages on MultiMember Group =====")
// Create MultiMember Group
mmGroup := createMultiMemberGroup(ctx, t, tps...)
// Each member sends 3 messages on MultiMember Group
messages := []string{"test1", "test2", "test3"}
sendMessageOnGroup(ctx, t, tps, tps, mmGroup, messages)
t.Log("===== Send Messages on Account Group =====")
// Send messages on account groups
for _, account := range tps {
// Get account config
config, err := account.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config)
// Send messages on account group
messages = []string{"account1", "account2", "account3"}
sendMessageOnGroup(ctx, t, []*weshnet.TestingProtocol{account}, []*weshnet.TestingProtocol{account}, config.AccountGroupPk, messages)
}
t.Log("===== Send Messages again on MultiMember Group =====")
// Each member sends 3 messages on MultiMember Group
messages = []string{"test4", "test5", "test6"}
sendMessageOnGroup(ctx, t, tps, tps, mmGroup, messages)
})
}
func TestScenario_MessageAccountAndContactGroups(t *testing.T) {
cases := []testCase{
{"2 clients/connectAll", 2, weshnet.ConnectAll, testutil.Fast, testutil.Broken, time.Second * 10},
{"3 clients/connectAll", 3, weshnet.ConnectAll, testutil.Fast, testutil.Broken, time.Second * 10},
{"5 clients/connectAll", 5, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 20},
{"8 clients/connectAll", 8, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 30},
{"10 clients/connectAll", 10, weshnet.ConnectAll, testutil.Slow, testutil.Broken, time.Second * 40},
}
testingScenario(t, cases, func(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) {
t.Log("===== Send Messages on Contact Group =====")
// Add accounts as contacts
addAsContact(ctx, t, tps, tps)
// Send messages between all accounts on contact groups
messages := []string{"contact1", "contact2", "contact3"}
sendMessageToContact(ctx, t, messages, tps)
t.Log("===== Send Messages on Account Group =====")
// Send messages on account groups
for _, account := range tps {
// Get account config
config, err := account.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, config)
// Send messages on account group
messages = []string{"account1", "account2", "account3"}
sendMessageOnGroup(ctx, t, []*weshnet.TestingProtocol{account}, []*weshnet.TestingProtocol{account}, config.AccountGroupPk, messages)
}
t.Log("===== Send Messages again on Contact Group =====")
// Send messages between all accounts on contact groups
messages = []string{"contact4", "contact5", "contact6"}
sendMessageToContact(ctx, t, messages, tps)
})
}
// Helpers
func testingScenario(t *testing.T, tcs []testCase, tf testFunc) {
if os.Getenv("WITH_GOLEAK") == "1" {
defer goleak.VerifyNone(t,
goleak.IgnoreTopFunction("github.com/syndtr/goleveldb/leveldb.(*DB).mpoolDrain"), // inherited from one of the imports (init)
goleak.IgnoreTopFunction("github.com/ipfs/go-log/writer.(*MirrorWriter).logRoutine"), // inherited from one of the imports (init)
goleak.IgnoreTopFunction("github.com/jbenet/goprocess/periodic.callOnTicker.func1"), // inherited from github.com/ipfs/kubo/core.NewNode
goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), // inherited from github.com/ipfs/kubo/core.NewNode)
goleak.IgnoreTopFunction("github.com/desertbit/timer.timerRoutine"), // inherited from github.com/ipfs/kubo/core.NewNode)
goleak.IgnoreTopFunction("go.opentelemetry.io/otel/instrumentation/grpctrace.wrapClientStream.func1"),
goleak.IgnoreTopFunction("go.opentelemetry.io/otel/instrumentation/grpctrace.StreamClientInterceptor.func1.1"),
)
}
for _, tc := range tcs {
t.Run(tc.Name, func(t *testing.T) {
testutil.FilterStabilityAndSpeed(t, tc.Stability, tc.Speed)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
opts := weshnet.TestingOpts{
Mocknet: mn,
Logger: logger,
ConnectFunc: tc.ConnectFunc,
}
tps, cleanup := weshnet.NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, tc.NumberOfClient)
defer cleanup()
var cctx context.Context
if tc.Timeout > 0 {
cctx, cancel = context.WithTimeout(ctx, tc.Timeout)
} else {
cctx, cancel = context.WithCancel(ctx)
}
tf(cctx, t, tps...)
cancel()
})
}
}
func testingScenarioNonMocked(t *testing.T, tcs []testCase, tf testFunc) {
if os.Getenv("WITH_GOLEAK") == "1" {
defer goleak.VerifyNone(t,
goleak.IgnoreTopFunction("github.com/syndtr/goleveldb/leveldb.(*DB).mpoolDrain"), // inherited from one of the imports (init)
goleak.IgnoreTopFunction("github.com/ipfs/go-log/writer.(*MirrorWriter).logRoutine"), // inherited from one of the imports (init)
goleak.IgnoreTopFunction("github.com/jbenet/goprocess/periodic.callOnTicker.func1"), // inherited from github.com/ipfs/kubo/core.NewNode
goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), // inherited from github.com/ipfs/kubo/core.NewNode)
goleak.IgnoreTopFunction("github.com/desertbit/timer.timerRoutine"), // inherited from github.com/ipfs/kubo/core.NewNode)
goleak.IgnoreTopFunction("go.opentelemetry.io/otel/instrumentation/grpctrace.wrapClientStream.func1"),
goleak.IgnoreTopFunction("go.opentelemetry.io/otel/instrumentation/grpctrace.StreamClientInterceptor.func1.1"),
)
}
for _, tc := range tcs {
t.Run(tc.Name, func(t *testing.T) {
testutil.FilterStabilityAndSpeed(t, tc.Stability, tc.Speed)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger, cleanup := testutil.Logger(t)
defer cleanup()
mn := mocknet.New()
defer mn.Close()
opts := weshnet.TestingOpts{
Mocknet: mn,
Logger: logger,
ConnectFunc: tc.ConnectFunc,
}
tps, cleanup := weshnet.NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, tc.NumberOfClient)
defer cleanup()
var cctx context.Context
if tc.Timeout > 0 {
cctx, cancel = context.WithTimeout(ctx, tc.Timeout)
} else {
cctx, cancel = context.WithCancel(ctx)
}
tf(cctx, t, tps...)
cancel()
})
}
}
func createMultiMemberGroup(ctx context.Context, t *testing.T, tps ...*weshnet.TestingProtocol) (groupID []byte) {
return weshnet.CreateMultiMemberGroupInstance(ctx, t, tps...).PublicKey
}
func addAsContact(ctx context.Context, t *testing.T, senders, receivers []*weshnet.TestingProtocol) {
testutil.LogTree(t, "Add Senders/Receivers as Contact", 0, true)
start := time.Now()
var sendDuration, receiveDuration, acceptDuration, activateDuration time.Duration
for i, sender := range senders {
for _, receiver := range receivers {
substart := time.Now()
// Get sender/receiver configs
senderCfg, err := sender.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, senderCfg)
receiverCfg, err := receiver.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
require.NotNil(t, receiverCfg)
// Setup receiver's shareable contact
var receiverRDVSeed []byte
crf, err := receiver.Client.ContactRequestReference(ctx, &protocoltypes.ContactRequestReference_Request{})
if err != nil || !crf.Enabled || len(crf.PublicRendezvousSeed) == 0 {
_, err = receiver.Client.ContactRequestEnable(ctx, &protocoltypes.ContactRequestEnable_Request{})
require.NoError(t, err)
receiverRDV, err := receiver.Client.ContactRequestResetReference(ctx, &protocoltypes.ContactRequestResetReference_Request{})
require.NoError(t, err)
require.NotNil(t, receiverRDV)
receiverRDVSeed = receiverRDV.PublicRendezvousSeed
} else {
receiverRDVSeed = crf.PublicRendezvousSeed
}
receiverSharableContact := &protocoltypes.ShareableContact{
Pk: receiverCfg.AccountPk,
PublicRendezvousSeed: receiverRDVSeed,
}
// Sender sends contact request
_, err = sender.Client.ContactRequestSend(ctx, &protocoltypes.ContactRequestSend_Request{
Contact: receiverSharableContact,
})
// Check if sender and receiver are the same account, should return the right error and skip
if bytes.Equal(senderCfg.AccountPk, receiverCfg.AccountPk) {
require.Equal(t, errcode.LastCode(err), errcode.ErrCode_ErrContactRequestSameAccount)
continue
}
// Check if contact request was already sent, should return right error and skip
receiverWasSender := false
for j := 0; j < i; j++ {
if senders[j] == receiver {
receiverWasSender = true
}
}
senderWasReceiver := false
if receiverWasSender {
for _, r := range receivers {
if r == sender {
senderWasReceiver = true
}
}
}
if receiverWasSender && senderWasReceiver {
require.Equal(t, errcode.LastCode(err), errcode.ErrCode_ErrContactRequestContactAlreadyAdded)
continue
}
// No other error should occur
require.NoError(t, err)
sendDuration += time.Since(substart)
substart = time.Now()
// Receiver subscribes to handle incoming contact request
subCtx, subCancel := context.WithCancel(ctx)
subReceiver, err := receiver.Client.GroupMetadataList(subCtx, &protocoltypes.GroupMetadataList_Request{
GroupPk: receiverCfg.AccountGroupPk,
})
require.NoError(t, err)
found := false
// Receiver waits for valid contact request coming from sender
for {
evt, err := subReceiver.Recv()
if err == io.EOF || subReceiver.Context().Err() != nil {
break
}
require.NoError(t, err)
if evt == nil || evt.Metadata.EventType != protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived {
continue
}
req := &protocoltypes.AccountContactRequestIncomingReceived{}
err = proto.Unmarshal(evt.Event, req)
require.NoError(t, err)
if bytes.Equal(senderCfg.AccountPk, req.ContactPk) {
found = true
break
}
}
subCancel()
require.True(t, found)
receiveDuration += time.Since(substart)
substart = time.Now()
// Receiver accepts contact request
_, err = receiver.Client.ContactRequestAccept(ctx, &protocoltypes.ContactRequestAccept_Request{
ContactPk: senderCfg.AccountPk,
})
require.NoError(t, err)
acceptDuration += time.Since(substart)
substart = time.Now()
// Both receiver and sender activate the contact group
grpInfo, err := sender.Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
ContactPk: receiverCfg.AccountPk,
})
require.NoError(t, err)
_, err = sender.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: grpInfo.Group.PublicKey,
})
require.NoError(t, err)
grpInfo2, err := receiver.Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
ContactPk: senderCfg.AccountPk,
})
require.NoError(t, err)
require.Equal(t, grpInfo.Group.PublicKey, grpInfo2.Group.PublicKey)
_, err = receiver.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: grpInfo2.Group.PublicKey,
})
require.NoError(t, err)
activateDuration += time.Since(substart)
}
}
testutil.LogTree(t, "Send Contact Requests", 1, true)
testutil.LogTree(t, "duration: %s", 1, false, sendDuration)
testutil.LogTree(t, "Receive Contact Requests", 1, true)
testutil.LogTree(t, "duration: %s", 1, false, receiveDuration)
testutil.LogTree(t, "Accept Contact Requests", 1, true)
testutil.LogTree(t, "duration: %s", 1, false, acceptDuration)
testutil.LogTree(t, "Activate Contact Groups", 1, true)
testutil.LogTree(t, "duration: %s", 1, false, activateDuration)
testutil.LogTree(t, "duration: %s", 0, false, time.Since(start))
}
func getContactGroup(ctx context.Context, t *testing.T, source *weshnet.TestingProtocol, contact *weshnet.TestingProtocol) *protocoltypes.GroupInfo_Reply {
// Get contact group
contactGroup, err := source.Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
ContactPk: getAccountPubKey(t, contact),
})
require.NoError(t, err)
require.NotNil(t, contactGroup)
return contactGroup
}
func sendMessageToContact(ctx context.Context, t *testing.T, messages []string, tps []*weshnet.TestingProtocol) {
for _, sender := range tps {
for _, receiver := range tps {
// Don't try to send messages to itself using contact group
if sender == receiver {
continue
}
// Get contact group
contactGroup := getContactGroup(ctx, t, sender, receiver)
// Send messages on contact group
sendMessageOnGroup(ctx, t, []*weshnet.TestingProtocol{sender}, []*weshnet.TestingProtocol{receiver}, contactGroup.Group.PublicKey, messages)
}
}
}
func sendMessageOnGroup(ctx context.Context, t *testing.T, senders, receivers []*weshnet.TestingProtocol, groupPK []byte, messages []string) {
testutil.LogTree(t, "Send, Receive and List Messages", 0, true)
start := time.Now()
// Setup expectedMessages map
expectedMessages := map[string]struct{}{}
expectedMessagesCount := len(messages) * len(senders)
expectedMessagesLock := sync.Mutex{}
for _, message := range messages {
for _, sender := range senders {
expectedMessage := getAccountB64PubKey(t, sender) + " - " + message
expectedMessages[expectedMessage] = struct{}{}
}
}
// Setup map to check expected messages reception
subReceivedMessages := map[string]map[string]bool{}
subReceivedMessagesCount := map[string]int{}
listReceivedMessages := map[string]map[string]bool{}
listReceivedMessagesCount := map[string]int{}
for _, receiver := range receivers {
subReceiverMap := map[string]bool{}
listReceiverMap := map[string]bool{}
for expectedMessage := range expectedMessages {
subReceiverMap[expectedMessage] = false
listReceiverMap[expectedMessage] = false
}
receiverID := getAccountB64PubKey(t, receiver)
subReceivedMessages[receiverID] = subReceiverMap
listReceivedMessages[receiverID] = listReceiverMap
subReceivedMessagesCount[receiverID] = 0
listReceivedMessagesCount[receiverID] = 0
}
receivedMessagesLock := sync.Mutex{}
// Senders send all expected messages
{
testutil.LogTree(t, "Senders Send Messages", 1, true)
start := time.Now()
for _, sender := range senders {
senderID := getAccountB64PubKey(t, sender)
for _, message := range messages {
_, err := sender.Client.AppMessageSend(ctx, &protocoltypes.AppMessageSend_Request{
GroupPk: groupPK,
Payload: []byte(senderID + " - " + message),
})
require.NoError(t, err)
}
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Receivers receive all expected messages
{
testutil.LogTree(t, "Receivers Receive Messages (subscription)", 1, true)
start := time.Now()
var wg sync.WaitGroup
wg.Add(len(receivers))
for _, receiver := range receivers {
// Subscribe receivers to wait for incoming messages
go func(receiver *weshnet.TestingProtocol) {
subCtx, subCancel := context.WithCancel(ctx)
defer subCancel()
defer wg.Done()
sub, err := receiver.Client.GroupMessageList(subCtx, &protocoltypes.GroupMessageList_Request{
GroupPk: groupPK,
})
if !assert.NoError(t, err) {
return
}
receiverID := getAccountB64PubKey(t, receiver)
for {
if subCtx.Err() != nil {
return
}
// Receive message
res, err := sub.Recv()
if err == io.EOF {
return
}
if !assert.NoError(t, err) {
continue
}
// Check if received message was expected
expectedMessagesLock.Lock()
_, expected := expectedMessages[string(res.Message)]
expectedMessagesLock.Unlock()
if !expected {
continue
}
// Check if message was already received
receivedMessagesLock.Lock()
alreadyReceived := subReceivedMessages[receiverID][string(res.Message)]
if alreadyReceived {
receivedMessagesLock.Unlock()
continue
}
// Mark message as received
subReceivedMessages[receiverID][string(res.Message)] = true
subReceivedMessagesCount[receiverID]++
// Return if all expected messages were received
if subReceivedMessagesCount[receiverID] == expectedMessagesCount {
receivedMessagesLock.Unlock()
return
}
receivedMessagesLock.Unlock()
}
}(receiver)
}
// Wait that all receivers received messages
wg.Wait()
// Check if everything is ok
for _, receiver := range receivers {
receiverID := getAccountB64PubKey(t, receiver)
assert.Equal(t, expectedMessagesCount, subReceivedMessagesCount[receiverID])
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Receivers list all expected messages
{
testutil.LogTree(t, "Receivers List Messages (store)", 1, true)
start := time.Now()
var wg sync.WaitGroup
wg.Add(len(receivers))
for _, receiver := range receivers {
// Subscribe receivers to wait for incoming messages
go func(receiver *weshnet.TestingProtocol) {
subCtx, subCancel := context.WithCancel(ctx)
defer subCancel()
defer wg.Done()
req := protocoltypes.GroupMessageList_Request{
GroupPk: groupPK,
UntilNow: true,
}
ml, err := receiver.Client.GroupMessageList(subCtx, &req)
if !assert.NoError(t, err) {
return
}
receiverID := getAccountB64PubKey(t, receiver)
for {
if subCtx.Err() != nil {
return
}
// Receive message
res, err := ml.Recv()
if err == io.EOF {
return
}
if !assert.NoError(t, err) {
continue
}
// Check if received message was expected
expectedMessagesLock.Lock()
_, expected := expectedMessages[string(res.Message)]
expectedMessagesLock.Unlock()
if !expected {
continue
}
// Check if message was already received
receivedMessagesLock.Lock()
alreadyReceived := listReceivedMessages[receiverID][string(res.Message)]
if alreadyReceived {
receivedMessagesLock.Unlock()
continue
}
// Mark message as received
listReceivedMessages[receiverID][string(res.Message)] = true
listReceivedMessagesCount[receiverID]++
// Return if all expected messages were received
if listReceivedMessagesCount[receiverID] == expectedMessagesCount {
receivedMessagesLock.Unlock()
return
}
receivedMessagesLock.Unlock()
}
}(receiver)
}
// Wait that all receivers listed messages
wg.Wait()
// Check if everything is ok
for _, receiver := range receivers {
receiverID := getAccountB64PubKey(t, receiver)
assert.Equal(t, expectedMessagesCount, listReceivedMessagesCount[receiverID])
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
testutil.LogTree(t, "duration: %s", 0, false, time.Since(start))
}
func getAccountPubKey(t *testing.T, tp *weshnet.TestingProtocol) []byte {
t.Helper()
_, accMemberDevice, err := tp.Opts.SecretStore.GetGroupForAccount()
require.NoError(t, err)
publicKeyBytes, err := accMemberDevice.Member().Raw()
require.NoError(t, err)
return publicKeyBytes
}
func getAccountB64PubKey(t *testing.T, tp *weshnet.TestingProtocol) string {
t.Helper()
tpPK := getAccountPubKey(t, tp)
return base64.StdEncoding.EncodeToString(tpPK)
}
================================================
FILE: service.go
================================================
package weshnet
import (
"context"
"encoding/hex"
"fmt"
mrand "math/rand"
"path/filepath"
"sync"
"time"
"unsafe"
"github.com/dgraph-io/badger/v2/options"
ds "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
badger "github.com/ipfs/go-ds-badger2"
coreiface "github.com/ipfs/kubo/core/coreiface"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peerstore"
backoff "github.com/libp2p/go-libp2p/p2p/discovery/backoff"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/multierr"
"go.uber.org/zap"
"moul.io/srand"
"berty.tech/go-orbit-db/baseorbitdb"
"berty.tech/go-orbit-db/iface"
"berty.tech/go-orbit-db/pubsub/directchannel"
"berty.tech/go-orbit-db/pubsub/pubsubraw"
"berty.tech/weshnet/v2/internal/bertyversion"
"berty.tech/weshnet/v2/internal/datastoreutil"
"berty.tech/weshnet/v2/pkg/bertyvcissuer"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
ipfs_mobile "berty.tech/weshnet/v2/pkg/ipfsutil/mobile"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/rendezvous"
"berty.tech/weshnet/v2/pkg/secretstore"
tinder "berty.tech/weshnet/v2/pkg/tinder"
"berty.tech/weshnet/v2/pkg/tyber"
)
var _ Service = (*service)(nil)
// Service is the main Berty Protocol interface
type Service interface {
protocoltypes.ProtocolServiceServer
Close() error
Status() Status
IpfsCoreAPI() coreiface.CoreAPI
}
type service struct {
// variables
ctx context.Context
ctxCancel context.CancelFunc
logger *zap.Logger
ipfsCoreAPI ipfsutil.ExtendedCoreAPI
odb *WeshOrbitDB
accountGroupCtx *GroupContext
openedGroups map[string]*GroupContext
lock sync.RWMutex
close func() error
startedAt time.Time
host host.Host
grpcInsecure bool
refreshprocess map[string]context.CancelFunc
muRefreshprocess sync.RWMutex
swiper *Swiper
peerStatusManager *ConnectednessManager
accountEventBus event.Bus
contactRequestsManager *contactRequestsManager
vcClient *bertyvcissuer.Client
secretStore secretstore.SecretStore
protocoltypes.UnimplementedProtocolServiceServer
}
// Opts contains optional configuration flags for building a new Client
type Opts struct {
Logger *zap.Logger
IpfsCoreAPI ipfsutil.ExtendedCoreAPI
DatastoreDir string
RootDatastore ds.Batching
OrbitDB *WeshOrbitDB
TinderService *tinder.Service
Host host.Host
PubSub *pubsub.PubSub
GRPCInsecureMode bool
LocalOnly bool
close func() error
SecretStore secretstore.SecretStore
PrometheusRegister prometheus.Registerer
// P2PStaticRelays is only used if IpfsCoreAPI is nil
P2PStaticRelays []string
// P2PRdvpMaddrs is only used if TinderService is nil
P2PRdvpMaddrs []string
// These are used if OrbitDB is nil.
GroupMetadataStoreType string
GroupMessageStoreType string
}
func (opts *Opts) applyPushDefaults() {
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
if opts.PrometheusRegister == nil {
opts.PrometheusRegister = prometheus.DefaultRegisterer
}
}
func (opts *Opts) applyDefaultsGetDatastore() error {
if opts.RootDatastore == nil {
if opts.DatastoreDir == "" || opts.DatastoreDir == InMemoryDirectory {
opts.RootDatastore = ds_sync.MutexWrap(ds.NewMapDatastore())
} else {
bopts := badger.DefaultOptions
bopts.ValueLogLoadingMode = options.FileIO
ds, err := badger.NewDatastore(opts.DatastoreDir, &bopts)
if err != nil {
return fmt.Errorf("unable to init badger datastore: %w", err)
}
opts.RootDatastore = ds
oldClose := opts.close
opts.close = func() error {
var err error
if oldClose != nil {
err = oldClose()
}
if dserr := ds.Close(); dserr != nil {
err = multierr.Append(err, fmt.Errorf("unable to close datastore: %w", dserr))
}
return err
}
}
}
return nil
}
func (opts *Opts) applyDefaults(ctx context.Context) error {
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
rng := mrand.New(mrand.NewSource(srand.MustSecure())) // nolint:gosec // we need to use math/rand here, but it is seeded from crypto/rand
if err := opts.applyDefaultsGetDatastore(); err != nil {
return err
}
opts.applyPushDefaults()
if opts.SecretStore == nil {
secretStore, err := secretstore.NewSecretStore(opts.RootDatastore, &secretstore.NewSecretStoreOptions{
Logger: opts.Logger,
})
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
opts.SecretStore = secretStore
}
if opts.P2PRdvpMaddrs == nil {
opts.P2PRdvpMaddrs = []string{ipfsutil.DefaultP2PRdvpMaddr}
}
var mnode *ipfs_mobile.IpfsMobile
if opts.IpfsCoreAPI == nil {
dsync := opts.RootDatastore
if dsync == nil {
dsync = ds_sync.MutexWrap(ds.NewMapDatastore())
}
repo, err := ipfsutil.CreateMockedRepo(dsync)
if err != nil {
return err
}
mrepo := ipfs_mobile.NewRepoMobile(opts.DatastoreDir, repo)
// NewIPFSMobile will apply defaults for P2PStaticRelays
mnode, err = ipfsutil.NewIPFSMobile(ctx, mrepo, &ipfsutil.MobileOptions{
Logger: opts.Logger,
P2PStaticRelays: opts.P2PStaticRelays,
PeerStorePeers: opts.P2PRdvpMaddrs,
})
if err != nil {
return err
}
opts.IpfsCoreAPI, err = ipfsutil.NewExtendedCoreAPIFromNode(mnode.IpfsNode)
if err != nil {
return err
}
opts.Host = mnode.PeerHost()
oldClose := opts.close
opts.close = func() error {
if oldClose != nil {
_ = oldClose()
}
return mnode.Close()
}
}
if opts.Host == nil {
opts.Host = opts.IpfsCoreAPI
}
// setup default tinder service
if opts.TinderService == nil {
drivers := []tinder.IDriver{}
// setup loac disc
localdisc, err := tinder.NewLocalDiscovery(opts.Logger, opts.Host, rng)
if err != nil {
return fmt.Errorf("unable to setup tinder localdiscovery: %w", err)
}
drivers = append(drivers, localdisc)
// rdvp driver. Imitate berty configIPFSRouting
// https://github.com/berty/berty/blob/5a8b9cb8524c1287ab2533a9e186ac8bde7f2b57/go/internal/initutil/ipfs.go#L684
rdvpeers, err := ipfsutil.ParseAndResolveMaddrs(ctx, opts.Logger, opts.P2PRdvpMaddrs)
if err != nil {
return fmt.Errorf("unable to resolve maddrs: %w", err)
}
addrsFactory := tinder.PublicAddrsOnlyFactory
if len(rdvpeers) > 0 {
for _, peer := range rdvpeers {
opts.Host.Peerstore().AddAddrs(peer.ID, peer.Addrs, peerstore.PermanentAddrTTL)
emitterclient := rendezvous.NewEmitterClient(&rendezvous.EmitterClientOptions{
Logger: opts.Logger,
})
// mqttclient := rendezvous.NewMQTTClient(logger, baseopts)
udisc := tinder.NewRendezvousDiscovery(opts.Logger, opts.Host, peer.ID, addrsFactory, rng, emitterclient)
drivers = append(drivers, udisc)
}
}
if mnode != nil {
dhtdisc := tinder.NewRoutingDiscoveryDriver("dht", mnode.DHT)
drivers = append(drivers, dhtdisc)
}
opts.TinderService, err = tinder.NewService(opts.Host, opts.Logger, drivers...)
if err != nil {
return fmt.Errorf("unable to setup tinder service: %w", err)
}
}
if opts.PubSub == nil {
var err error
popts := []pubsub.Option{
pubsub.WithMessageSigning(true),
pubsub.WithPeerExchange(true),
}
backoffstrat := backoff.NewExponentialBackoff(
time.Second*10, time.Hour,
backoff.FullJitter,
time.Second, 10.0, 0, rng)
cacheSize := 100
dialTimeout := time.Second * 20
backoffconnector := func(host host.Host) (*backoff.BackoffConnector, error) {
return backoff.NewBackoffConnector(host, cacheSize, dialTimeout, backoffstrat)
}
adaptater := tinder.NewDiscoveryAdaptater(opts.Logger.Named("disc"), opts.TinderService)
popts = append(popts, pubsub.WithDiscovery(adaptater, pubsub.WithDiscoverConnector(backoffconnector)))
// pubsub.DiscoveryPollInterval = m.Node.Protocol.PollInterval
ps, err := pubsub.NewGossipSub(ctx, opts.Host, popts...)
if err != nil {
return fmt.Errorf("unable to init gossipsub: %w", err)
}
// @NOTE(gfanton): we need to force cast here until our fix is push
// upstream on the original go-libp2p-pubsub
// see: https://github.com/gfanton/go-libp2p-pubsub/commit/8f4fd394f8dfcb3a5eb724a03f9e4e1e33194cbd
opts.PubSub = (*pubsub.PubSub)(unsafe.Pointer(ps))
}
if opts.OrbitDB == nil {
orbitDirectory := InMemoryDirectory
if opts.DatastoreDir != InMemoryDirectory {
orbitDirectory = filepath.Join(opts.DatastoreDir, NamespaceOrbitDBDirectory)
}
pubsub := pubsubraw.NewPubSub(opts.PubSub, opts.Host.ID(), opts.Logger, nil)
odbOpts := &NewOrbitDBOptions{
NewOrbitDBOptions: baseorbitdb.NewOrbitDBOptions{
Directory: &orbitDirectory,
PubSub: pubsub,
Logger: opts.Logger,
},
PrometheusRegister: opts.PrometheusRegister,
Datastore: datastoreutil.NewNamespacedDatastore(opts.RootDatastore, ds.NewKey(NamespaceOrbitDBDatastore)),
SecretStore: opts.SecretStore,
GroupMetadataStoreType: opts.GroupMetadataStoreType,
GroupMessageStoreType: opts.GroupMessageStoreType,
}
if opts.Host != nil {
odbOpts.DirectChannelFactory = directchannel.InitDirectChannelFactory(opts.Logger, opts.Host)
}
odb, err := NewWeshOrbitDB(ctx, opts.IpfsCoreAPI, odbOpts)
if err != nil {
return err
}
oldClose := opts.close
opts.close = func() error {
if oldClose != nil {
_ = oldClose()
}
return odb.Close()
}
opts.OrbitDB = odb
}
return nil
}
// NewService initializes a new Service using the opts.
// If opts.RootDatastore is nil and opts.DatastoreDir is "" or InMemoryDirectory, then set
// opts.RootDatastore to an in-memory data store. Otherwise, if opts.RootDatastore is nil then set
// opts.RootDatastore to a persistent data store at opts.DatastoreDir .
func NewService(opts Opts) (_ Service, err error) {
ctx, cancel := context.WithCancel(context.Background())
if err := opts.applyDefaults(ctx); err != nil {
cancel()
return nil, errcode.ErrCode_TODO.Wrap(err)
}
opts.Logger = opts.Logger.Named("pt")
ctx, _, endSection := tyber.Section(tyber.ContextWithoutTraceID(ctx), opts.Logger, fmt.Sprintf("Initializing ProtocolService version %s", bertyversion.Version))
defer func() { endSection(err, "") }()
accountEventBus := eventbus.NewBus(
eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(opts.PrometheusRegister))))
dbOpts := &iface.CreateDBOptions{
EventBus: accountEventBus,
LocalOnly: &opts.LocalOnly,
}
accountGroupCtx, err := opts.OrbitDB.openAccountGroup(ctx, dbOpts, opts.IpfsCoreAPI)
if err != nil {
cancel()
return nil, errcode.ErrCode_TODO.Wrap(err)
}
opts.Logger.Debug("Opened account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "AccountGroup", Description: accountGroupCtx.group.String()}})...)
var contactRequestsManager *contactRequestsManager
var swiper *Swiper
if opts.TinderService != nil {
swiper = NewSwiper(opts.Logger, opts.TinderService, opts.OrbitDB.rotationInterval)
opts.Logger.Debug("Tinder swiper is enabled", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
if contactRequestsManager, err = newContactRequestsManager(swiper, accountGroupCtx.metadataStore, opts.IpfsCoreAPI, opts.Logger); err != nil {
cancel()
return nil, errcode.ErrCode_TODO.Wrap(err)
}
} else {
opts.Logger.Warn("No tinder driver provided, incoming and outgoing contact requests won't be enabled", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
}
if err := opts.SecretStore.PutGroup(ctx, accountGroupCtx.Group()); err != nil {
cancel()
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unable to add account group to group datastore, err: %w", err))
}
s := &service{
ctx: ctx,
ctxCancel: cancel,
host: opts.Host,
ipfsCoreAPI: opts.IpfsCoreAPI,
logger: opts.Logger,
odb: opts.OrbitDB,
close: opts.close,
accountGroupCtx: accountGroupCtx,
swiper: swiper,
startedAt: time.Now(),
openedGroups: map[string]*GroupContext{
string(accountGroupCtx.Group().PublicKey): accountGroupCtx,
},
secretStore: opts.SecretStore,
grpcInsecure: opts.GRPCInsecureMode,
refreshprocess: make(map[string]context.CancelFunc),
peerStatusManager: NewConnectednessManager(),
accountEventBus: accountEventBus,
contactRequestsManager: contactRequestsManager,
}
s.startGroupDeviceMonitor()
return s, nil
}
func (s *service) IpfsCoreAPI() coreiface.CoreAPI {
return s.ipfsCoreAPI
}
func (s *service) Close() error {
endSection := tyber.SimpleSection(tyber.ContextWithoutTraceID(s.ctx), s.logger, "Closing ProtocolService")
var err error
pks := []crypto.PubKey{}
// gather public keys
s.lock.Lock()
if s.contactRequestsManager != nil {
s.contactRequestsManager.close()
s.contactRequestsManager = nil
}
for _, gc := range s.openedGroups {
pk, subErr := gc.group.GetPubKey()
if subErr != nil {
err = multierr.Append(err, subErr)
continue
}
pks = append(pks, pk)
}
s.lock.Unlock()
// deactivate all groups
for _, pk := range pks {
derr := s.deactivateGroup(pk)
if derr != nil {
err = multierr.Append(derr, derr)
}
}
err = multierr.Append(err, s.odb.Close())
if s.close != nil {
err = multierr.Append(err, s.close())
}
endSection(err)
s.ctxCancel()
return err
}
func (s *service) startGroupDeviceMonitor() {
if s.host == nil {
return
}
// monitor exchange heads events
subHead, err := s.odb.EventBus().Subscribe(new(baseorbitdb.EventExchangeHeads),
eventbus.Name("weshnet/service/monitor-exchange-heads"))
if err != nil {
s.logger.Error("startGroupDeviceMonitor", zap.Error(errors.Wrap(err, "unable to subscribe odb event")))
return
}
// monitor peer connectednesschanged
subPeer, err := s.host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged),
eventbus.Name("weshnet/service/monitor-peer-connectedness"))
if err != nil {
s.logger.Error("startGroupDeviceMonitor", zap.Error(errors.Wrap(err, "unable to subscribe odb event")))
subHead.Close()
return
}
go func() {
defer subHead.Close()
defer subPeer.Close()
for {
var evt any
select {
case evt = <-subHead.Out():
case evt = <-subPeer.Out():
case <-s.ctx.Done():
return
}
switch e := evt.(type) {
case event.EvtPeerConnectednessChanged:
switch e.Connectedness {
case network.Connected:
s.peerStatusManager.UpdateState(e.Peer, ConnectednessTypeConnected)
case network.NotConnected:
s.peerStatusManager.UpdateState(e.Peer, ConnectednessTypeDisconnected)
}
case baseorbitdb.EventExchangeHeads:
if dpk, ok := s.odb.GetDevicePKForPeerID(e.Peer); ok {
gkey := hex.EncodeToString(dpk.Group.PublicKey)
s.peerStatusManager.AssociatePeer(gkey, e.Peer)
}
}
}
}()
// get status of peers in the peerstore
peers := s.host.Peerstore().Peers()
for _, peer := range peers {
// if we got some connected peer check their status
if s.host.Network().Connectedness(peer) == network.Connected {
s.peerStatusManager.UpdateState(peer, ConnectednessTypeConnected)
}
// if we already have some head exchange with this peer, associate it
if dpk, ok := s.odb.GetDevicePKForPeerID(peer); ok {
gkey := hex.EncodeToString(dpk.Group.PublicKey)
s.peerStatusManager.AssociatePeer(gkey, peer)
}
}
}
// Status contains results of status checks
type Status struct {
DB error
Protocol error
}
func (s *service) Status() Status {
return Status{
Protocol: nil,
}
}
================================================
FILE: service_client.go
================================================
package weshnet
import (
"context"
"fmt"
"io"
"os"
"time"
"go.uber.org/zap"
"google.golang.org/grpc"
"berty.tech/weshnet/v2/pkg/grpcutil"
"berty.tech/weshnet/v2/pkg/ipfsutil"
ipfs_mobile "berty.tech/weshnet/v2/pkg/ipfsutil/mobile"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
const (
defaultLoggingFiltersKey = ":default:"
defaultLoggingFiltersValue = "info+:bty.* error+:*,-ipfs*,-*.tyber"
)
type ServiceClient interface {
protocoltypes.ProtocolServiceClient
io.Closer
}
type ServiceOption func(*Opts) error
// WithLogger sets the given logger
var WithLogger = func(l *zap.Logger) ServiceOption {
return func(s *Opts) error {
s.Logger = l
return nil
}
}
// WithP2PStaticRelays sets the given P2P static relays
var WithP2PStaticRelays = func(p []string) ServiceOption {
return func(s *Opts) error {
s.P2PStaticRelays = p
return nil
}
}
// WithP2PRdvpMaddrs sets the given P2P rendezvous point addresses
var WithP2PRdvpMaddrs = func(p []string) ServiceOption {
return func(s *Opts) error {
s.P2PRdvpMaddrs = p
return nil
}
}
// NewServiceClient initializes a new ServiceClient using the opts.
// If opts.RootDatastore is nil and opts.DatastoreDir is "" or InMemoryDirectory, then set
// opts.RootDatastore to an in-memory data store. Otherwise, if opts.RootDatastore is nil then set
// opts.RootDatastore to a persistent data store at opts.DatastoreDir .
func NewServiceClient(opts Opts) (ServiceClient, error) {
var err error
var cleanupLogger func()
if opts.Logger == nil {
if opts.Logger, cleanupLogger, err = setupDefaultLogger(); err != nil {
return nil, fmt.Errorf("unable to setup logger: %w", err)
}
}
svc, err := NewService(opts)
if err != nil {
return nil, err
}
s := grpc.NewServer()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
c, err := NewClientFromService(ctx, s, svc)
if err != nil {
return nil, fmt.Errorf("unable to create client from server: %w", err)
}
return &serviceClient{
ServiceClient: c,
server: s,
service: svc,
cleanup: cleanupLogger,
}, nil
}
// NewInMemoryServiceClient creates a new in-memory Wesh protocol service and returns a gRPC
// ServiceClient which uses a direct in-memory connection. When finished, you must call Close().
// This creates a new Wesh account where the key store is in memory. (If you don't
// export the data then it is lost when you call Close(). ) The IPFS node, cached data,
// and configuration are also in memory.
func NewInMemoryServiceClient(options ...ServiceOption) (ServiceClient, error) {
var opts Opts
for _, opt := range options {
if err := opt(&opts); err != nil {
return nil, err
}
}
opts.DatastoreDir = InMemoryDirectory
return NewServiceClient(opts)
}
// NewPersistentServiceClient creates a Wesh protocol service using persistent storage files in the
// directory given by the directory path. If the directory doesn't exist, this creates it with files
// of a new Wesh account and peer identity. (If the directory doesn't exist, this will create it only
// if the parent directory exists. Otherwise you must first create the parent directories.) However,
// if the persistent storage files already exist, then this opens them to use the existing Wesh
// account and peer identity. This returns a gRPC ServiceClient which uses a direct in-memory
// connection. When finished, you must call Close().
func NewPersistentServiceClient(path string, options ...ServiceOption) (ServiceClient, error) {
var opts Opts
for _, opt := range options {
if err := opt(&opts); err != nil {
return nil, err
}
}
opts.DatastoreDir = path
repo, err := ipfsutil.LoadRepoFromPath(path)
if err != nil {
return nil, err
}
var cleanupLogger func()
if opts.Logger == nil {
if opts.Logger, cleanupLogger, err = setupDefaultLogger(); err != nil {
return nil, fmt.Errorf("unable to setup logger: %w", err)
}
}
mrepo := ipfs_mobile.NewRepoMobile(path, repo)
mnode, err := ipfsutil.NewIPFSMobile(context.TODO(), mrepo, &ipfsutil.MobileOptions{
Logger: opts.Logger,
P2PStaticRelays: opts.P2PStaticRelays,
PeerStorePeers: opts.P2PRdvpMaddrs,
})
if err != nil {
return nil, err
}
opts.IpfsCoreAPI, err = ipfsutil.NewExtendedCoreAPIFromNode(mnode.IpfsNode)
if err != nil {
return nil, err
}
cl, err := NewServiceClient(opts)
if err != nil {
return nil, err
}
return &persistentServiceClient{
ServiceClient: cl,
cleanup: cleanupLogger,
}, nil
}
const ClientBufferSize = 4 * 1024 * 1024
type serviceClient struct {
ServiceClient // inehrit from client
service Service
server *grpc.Server
cleanup func()
}
type persistentServiceClient struct {
ServiceClient
cleanup func()
}
func (p *persistentServiceClient) Close() error {
err := p.ServiceClient.Close()
if p.cleanup != nil {
p.cleanup()
}
return err
}
func (c *serviceClient) Close() (err error) {
c.server.GracefulStop() // gracefully stop grpc server
_ = c.ServiceClient.Close() // close client and discard error
err = c.service.Close()
if c.cleanup != nil {
c.cleanup()
}
return // return real service error
}
type client struct {
protocoltypes.ProtocolServiceClient
l *grpcutil.BufListener
cc *grpc.ClientConn
}
func (c *client) Close() error {
err := c.cc.Close()
_ = c.l.Close()
return err
}
func NewClientFromService(ctx context.Context, s *grpc.Server, svc Service, opts ...grpc.DialOption) (ServiceClient, error) {
bl := grpcutil.NewBufListener(ClientBufferSize)
cc, err := bl.NewClientConn(ctx, opts...)
if err != nil {
return nil, err
}
protocoltypes.RegisterProtocolServiceServer(s, svc)
go func() {
// we dont need to log the error
_ = s.Serve(bl)
}()
return &client{
ProtocolServiceClient: protocoltypes.NewProtocolServiceClient(cc),
cc: cc,
l: bl,
}, nil
}
func setupDefaultLogger() (logger *zap.Logger, cleanup func(), err error) {
// setup log from env
if logfilter := os.Getenv("WESHNET_LOG_FILTER"); logfilter != "" {
if logfilter == defaultLoggingFiltersKey {
logfilter = defaultLoggingFiltersValue
}
s := logutil.NewStdStream(logfilter, "color", os.Stderr.Name())
return logutil.NewLogger(s)
}
return zap.NewNop(), func() {}, nil
}
================================================
FILE: service_group.go
================================================
package weshnet
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
func (s *service) getContactGroup(key crypto.PubKey) (*protocoltypes.Group, error) {
group, err := s.secretStore.GetGroupForContact(key)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
return group, nil
}
func (s *service) getGroupForPK(ctx context.Context, pk crypto.PubKey) (*protocoltypes.Group, error) {
group, err := s.secretStore.FetchGroupByPublicKey(ctx, pk)
if err == nil {
return group, nil
} else if !errcode.Is(err, errcode.ErrCode_ErrMissingMapKey) {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
accountGroup := s.getAccountGroup()
if accountGroup == nil {
return nil, errcode.ErrCode_ErrGroupMissing
}
if err = reindexGroupDatastore(ctx, s.secretStore, accountGroup.metadataStore); err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
group, err = s.secretStore.FetchGroupByPublicKey(ctx, pk)
if err == nil {
return group, nil
} else if errcode.Is(err, errcode.ErrCode_ErrMissingMapKey) {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unknown group specified"))
}
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
func (s *service) deactivateGroup(pk crypto.PubKey) error {
id, err := pk.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
cg, err := s.GetContextGroupForID(id)
if err != nil || cg == nil {
// @FIXME(gfanton): should return an error code
return nil
}
s.lock.Lock()
defer s.lock.Unlock()
err = cg.Close()
if err != nil {
s.logger.Error("unable to close group context", zap.Error(err))
}
delete(s.openedGroups, string(id))
if cg.group.GroupType == protocoltypes.GroupType_GroupTypeAccount {
s.accountGroupCtx = nil
}
return nil
}
func (s *service) activateGroup(ctx context.Context, pk crypto.PubKey, localOnly bool) error {
id, err := pk.Raw()
if err != nil {
return errcode.ErrCode_ErrSerialization.Wrap(err)
}
_, err = s.GetContextGroupForID(id)
if err != nil && err != errcode.ErrCode_ErrGroupUnknown {
return err
}
g, err := s.getGroupForPK(ctx, pk)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
s.lock.Lock()
defer s.lock.Unlock()
// @WIP(gfanton): do we need to use contactPK
var contactPK crypto.PubKey
switch g.GroupType {
case protocoltypes.GroupType_GroupTypeMultiMember:
// nothing to get here, simply continue, open and activate the group
case protocoltypes.GroupType_GroupTypeContact:
if s.accountGroupCtx == nil {
return errcode.ErrCode_ErrGroupActivate.Wrap(fmt.Errorf("accountGroupCtx is deactivated"))
}
contact := s.accountGroupCtx.metadataStore.GetContactFromGroupPK(id)
if contact != nil {
contactPK, err = contact.GetPubKey()
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
}
case protocoltypes.GroupType_GroupTypeAccount:
localOnly = true
if s.accountGroupCtx, err = s.odb.openAccountGroup(ctx, &iface.CreateDBOptions{EventBus: s.accountEventBus, LocalOnly: &localOnly}, s.ipfsCoreAPI); err != nil {
return err
}
s.openedGroups[string(id)] = s.accountGroupCtx
// reinitialize contactRequestsManager
if s.contactRequestsManager != nil {
s.contactRequestsManager.close()
if s.contactRequestsManager, err = newContactRequestsManager(s.swiper, s.accountGroupCtx.metadataStore, s.ipfsCoreAPI, s.logger); err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
}
return nil
default:
return errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("unknown group type"))
}
dbOpts := &iface.CreateDBOptions{LocalOnly: &localOnly}
gc, err := s.odb.OpenGroup(ctx, g, dbOpts)
if err != nil {
return errcode.ErrCode_ErrGroupOpen.Wrap(err)
}
if err = gc.ActivateGroupContext(contactPK); err != nil {
gc.Close()
return errcode.ErrCode_ErrGroupActivate.Wrap(err)
}
s.openedGroups[string(id)] = gc
gc.TagGroupContextPeers(s.ipfsCoreAPI, 42)
return nil
}
func (s *service) GetContextGroupForID(id []byte) (*GroupContext, error) {
if len(id) == 0 {
return nil, errcode.ErrCode_ErrInternal.Wrap(fmt.Errorf("no group id provided"))
}
s.lock.RLock()
defer s.lock.RUnlock()
cg, ok := s.openedGroups[string(id)]
if ok {
return cg, nil
}
return nil, errcode.ErrCode_ErrGroupUnknown
}
func reindexGroupDatastore(ctx context.Context, secretStore secretstore.SecretStore, m *MetadataStore) error {
if secretStore == nil {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("missing device keystore"))
}
for _, g := range m.ListMultiMemberGroups() {
if err := secretStore.PutGroup(ctx, g); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
for _, contact := range m.ListContactsByStatus(
protocoltypes.ContactState_ContactStateToRequest,
protocoltypes.ContactState_ContactStateReceived,
protocoltypes.ContactState_ContactStateAdded,
protocoltypes.ContactState_ContactStateRemoved,
protocoltypes.ContactState_ContactStateDiscarded,
protocoltypes.ContactState_ContactStateBlocked,
) {
cPK, err := contact.GetPubKey()
if err != nil {
return errcode.ErrCode_TODO.Wrap(err)
}
group, err := secretStore.GetGroupForContact(cPK)
if err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
if err := secretStore.PutGroup(ctx, group); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
func (s *service) getAccountGroup() *GroupContext {
s.lock.Lock()
defer s.lock.Unlock()
return s.accountGroupCtx
}
================================================
FILE: store_message.go
================================================
package weshnet
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"sync"
"github.com/ipfs/go-cid"
coreiface "github.com/ipfs/kubo/core/coreiface"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/go-ipfs-log/identityprovider"
ipliface "berty.tech/go-ipfs-log/iface"
"berty.tech/go-orbit-db/address"
"berty.tech/go-orbit-db/iface"
"berty.tech/go-orbit-db/stores"
"berty.tech/go-orbit-db/stores/basestore"
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/tyber"
)
// FIXME: replace cache by a circular buffer to avoid an attack by RAM saturation
type MessageStore struct {
basestore.BaseStore
eventBus event.Bus
emitters struct {
groupMessage event.Emitter
groupCacheMessage event.Emitter
}
secretStore secretstore.SecretStore
currentDevicePublicKey crypto.PubKey
currentDevicePublicKeyRaw []byte
group *protocoltypes.Group
groupPublicKey crypto.PubKey
logger *zap.Logger
deviceCaches map[string]*groupCache
muDeviceCaches sync.RWMutex
messagesQueue *simpleMessageQueue
ctx context.Context
cancel context.CancelFunc
}
func (m *MessageStore) setLogger(l *zap.Logger) {
if l == nil {
return
}
m.logger = l.With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.group.PublicKey))))
}
func (m *MessageStore) openMessage(ctx context.Context, e ipfslog.Entry) (*protocoltypes.GroupMessageEvent, error) {
if e == nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
op, err := operation.ParseOperation(e)
if err != nil {
m.logger.Error("unable to parse operation", zap.Error(err))
return nil, err
}
env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(headers.DevicePk)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if !m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey) {
if err := m.addToMessageQueue(ctx, e); err != nil {
m.logger.Error("unable to add message to cache", zap.Error(err))
}
return nil, fmt.Errorf("no secret for device")
}
return m.processMessage(ctx, &messageItem{
op: op,
env: env,
headers: headers,
hash: e.GetHash(),
})
}
type groupCache struct {
self, hasKnownChainKey bool
locker sync.Locker
queue *priorityMessageQueue
}
func (m *MessageStore) CacheSizeForDevicePK(devicePK []byte) (size int, ok bool) {
m.muDeviceCaches.RLock()
var device *groupCache
if device, ok = m.deviceCaches[string(devicePK)]; ok {
size = device.queue.Size()
}
m.muDeviceCaches.RUnlock()
return
}
func (m *MessageStore) ProcessMessageQueueForDevicePK(ctx context.Context, devicePK []byte) {
m.muDeviceCaches.Lock()
if device, ok := m.deviceCaches[string(devicePK)]; ok {
devicePublicKey, errDevice := crypto.UnmarshalEd25519PublicKey(devicePK)
if errDevice != nil {
m.logger.Error("unable to process message, unmarshal of device pk failed", logutil.PrivateBinary("devicepk", devicePK))
} else if device.hasKnownChainKey = m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey); !device.hasKnownChainKey {
m.logger.Error("unable to process message, no secret found for device pk", logutil.PrivateBinary("devicepk", devicePK))
} else if next := device.queue.Next(); next != nil {
// let's try processing one message from the queue.
// if it succeeds, the whole queue should be added for processing.
m.messagesQueue.Add(next)
}
}
m.muDeviceCaches.Unlock()
}
func (m *MessageStore) processMessage(ctx context.Context, message *messageItem) (*protocoltypes.GroupMessageEvent, error) {
// process message
msg, err := m.secretStore.OpenEnvelopePayload(ctx, message.env, message.headers, m.groupPublicKey, m.currentDevicePublicKey, message.hash)
if err != nil {
return nil, fmt.Errorf("unable to open the envelope: %w", err)
}
err = m.secretStore.UpdateOutOfStoreGroupReferences(ctx, message.headers.DevicePk, message.headers.Counter, m.group)
if err != nil {
m.logger.Error("unable to update push group references", zap.Error(err))
}
entry := message.op.GetEntry()
eventContext := newEventContext(entry.GetHash(), entry.GetNext(), m.group)
return &protocoltypes.GroupMessageEvent{
EventContext: eventContext,
Headers: message.headers,
Message: msg.GetPlaintext(),
}, nil
}
func (m *MessageStore) processMessageLoop(ctx context.Context, tracer *messageMetricsTracer) {
for {
// wait for next message
message, ok := m.messagesQueue.WaitForItem(ctx)
if !ok {
// context expired, return
return
}
// get or create a device cache for the device from which we received the message.
device, hasKnownChainKey := m.getOrCreateDeviceCache(ctx, message, tracer)
if device == nil {
// unknown device, lets keep moving
continue
} else if !hasKnownChainKey {
// we dont know the chain key yet, add message to the device cache
device.queue.Add(message)
_ = m.emitters.groupCacheMessage.Emit(*message)
continue
}
// actually process the message
evt, err := m.processMessage(ctx, message)
if err != nil {
m.logger.Error("unable to process message", zap.Error(err))
// if we got any error here, put (back) the message into the device queue
// for ex: `too many open files` error
device.queue.Add(message)
_ = m.emitters.groupCacheMessage.Emit(*message)
continue
}
// if we get here we probably can process other messages (if any) in the device queue
m.processDeviceMessagesInQueue(device)
// emit new message event
if err := m.emitters.groupMessage.Emit(evt); err != nil {
m.logger.Warn("unable to emit group message event", zap.Error(err))
}
}
}
func (m *MessageStore) getOrCreateDeviceCache(ctx context.Context, message *messageItem, tracer *messageMetricsTracer) (device *groupCache, hasKnownChainKey bool) {
devicePublicKeyString := string(message.headers.DevicePk)
m.muDeviceCaches.Lock()
defer m.muDeviceCaches.Unlock()
device, ok := m.deviceCaches[devicePublicKeyString]
if !ok {
devicePublicKey, err := crypto.UnmarshalEd25519PublicKey(message.headers.DevicePk)
if err != nil {
m.logger.Error("unable to process message, unmarshal of device pk failed", logutil.PrivateBinary("devicepk", message.headers.DevicePk))
return nil, false
}
hasSecret := m.secretStore.IsChainKeyKnownForDevice(ctx, m.groupPublicKey, devicePublicKey)
device = &groupCache{
self: bytes.Equal(m.currentDevicePublicKeyRaw, message.headers.DevicePk),
queue: newPriorityMessageQueue("undecrypted", tracer),
locker: &sync.RWMutex{},
hasKnownChainKey: hasSecret,
}
m.deviceCaches[devicePublicKeyString] = device
}
return device, device.hasKnownChainKey
}
// process the whole device queue (if any) into to the message queue
func (m *MessageStore) processDeviceMessagesInQueue(device *groupCache) {
_ = device.queue.NextAll(func(next *messageItem) error {
m.messagesQueue.Add(next)
return nil
})
}
func (m *MessageStore) addToMessageQueue(_ context.Context, e ipfslog.Entry) error {
if e == nil {
return errcode.ErrCode_ErrInvalidInput
}
op, err := operation.ParseOperation(e)
if err != nil {
return err
}
env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
if err != nil {
return errcode.ErrCode_ErrCryptoDecrypt.Wrap(err)
}
msg := &messageItem{
hash: e.GetHash(),
env: env,
headers: headers,
op: op,
}
m.messagesQueue.Add(msg)
return nil
}
// FIXME: use iterator instead to reduce resource usage (require go-ipfs-log improvements)
func (m *MessageStore) ListEvents(ctx context.Context, since, until []byte, reverse bool) (<-chan *protocoltypes.GroupMessageEvent, error) {
entries, err := getEntriesInRange(m.OpLog().GetEntries().Reverse().Slice(), since, until)
if err != nil {
return nil, err
}
out := make(chan *protocoltypes.GroupMessageEvent)
go func() {
iterateOverEntries(
entries,
reverse,
func(entry ipliface.IPFSLogEntry) {
message, err := m.openMessage(ctx, entry)
if err != nil {
m.logger.Error("unable to open message", zap.Error(err))
} else {
out <- message
m.logger.Info("message store - sent 1 event from log history")
}
},
)
close(out)
}()
return out, nil
}
func (m *MessageStore) AddMessage(ctx context.Context, payload []byte) (operation.Operation, error) {
ctx, newTrace := tyber.ContextWithTraceID(ctx)
if newTrace {
m.logger.Debug("Sending message to group "+base64.RawURLEncoding.EncodeToString(m.group.PublicKey), tyber.FormatTraceLogFields(ctx)...)
}
m.logger.Debug(
fmt.Sprintf("Adding message to store with payload of %d bytes", len(payload)),
tyber.FormatStepLogFields(
ctx,
[]tyber.Detail{
{Name: "Payload", Description: string(payload)},
},
)...,
)
return messageStoreAddMessage(ctx, m.group, m, payload)
}
func messageStoreAddMessage(ctx context.Context, g *protocoltypes.Group, m *MessageStore, payload []byte) (operation.Operation, error) {
msg := &protocoltypes.EncryptedMessage{
Plaintext: payload,
ProtocolMetadata: &protocoltypes.ProtocolMetadata{},
}
msgBytes, err := proto.Marshal(msg)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
sealedEnvelope, err := m.secretStore.SealEnvelope(ctx, g, msgBytes)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoEncrypt.Wrap(err)
}
m.logger.Debug(
"Message sealed successfully in secretbox envelope",
tyber.FormatStepLogFields(
ctx,
[]tyber.Detail{
{Name: "Cleartext size", Description: fmt.Sprintf("%d bytes", len(msgBytes))},
{Name: "Ciphertext size", Description: fmt.Sprintf("%d bytes", len(sealedEnvelope))},
},
)...,
)
op := operation.NewOperation(nil, "ADD", sealedEnvelope)
e, err := m.AddOperation(ctx, op, nil)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBAppend.Wrap(err)
}
m.logger.Debug(
"Envelope added to orbit-DB log successfully",
tyber.FormatStepLogFields(ctx, []tyber.Detail{})...,
)
op, err = operation.ParseOperation(e)
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBDeserialization.Wrap(err)
}
m.logger.Debug(
"Operation parsed by orbit-DB successfully",
tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "CID", Description: op.GetEntry().GetHash().String()}})...,
)
return op, nil
}
func constructorFactoryGroupMessage(s *WeshOrbitDB, logger *zap.Logger) iface.StoreConstructor {
metricsTracer := newMessageMetricsTracer(s.prometheusRegister)
return func(ipfs coreiface.CoreAPI, identity *identityprovider.Identity, addr address.Address, options *iface.NewStoreOptions) (iface.Store, error) {
g, err := s.getGroupFromOptions(options)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
groupPublicKey, err := g.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if options.EventBus == nil {
options.EventBus = s.EventBus()
}
replication := false
store := &MessageStore{
eventBus: options.EventBus,
secretStore: s.secretStore,
messagesQueue: newMessageQueue("cache", metricsTracer),
group: g,
groupPublicKey: groupPublicKey,
logger: logger,
deviceCaches: make(map[string]*groupCache),
}
if s.replicationMode {
replication = true
} else {
currentMemberDevice, err := s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
if errcode.Is(err, errcode.ErrCode_ErrInvalidInput) {
replication = true
} else {
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
} else {
store.currentDevicePublicKey = currentMemberDevice.Device()
store.currentDevicePublicKeyRaw, err = store.currentDevicePublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
}
}
store.ctx, store.cancel = context.WithCancel(context.Background())
go func() {
store.processMessageLoop(store.ctx, metricsTracer)
logger.Debug("store message process loop ended", zap.Error(store.ctx.Err()))
}()
if store.emitters.groupMessage, err = store.eventBus.Emitter(new(*protocoltypes.GroupMessageEvent)); err != nil {
store.cancel()
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
// for debug/test purpose
if store.emitters.groupCacheMessage, err = store.eventBus.Emitter(new(messageItem)); err != nil {
store.cancel()
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
options.Index = basestore.NewNoopIndex
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
store.cancel()
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
if replication {
return store, nil
}
chSub, err := store.EventBus().Subscribe([]any{
new(stores.EventWrite),
new(stores.EventReplicated),
}, eventbus.Name("weshnet/store-message"), eventbus.BufSize(128))
if err != nil {
return nil, fmt.Errorf("unable to subscribe to store events")
}
go func(ctx context.Context) {
defer chSub.Close()
for {
var e any
select {
case e = <-chSub.Out():
case <-ctx.Done():
return
}
var entries []ipfslog.Entry
switch evt := e.(type) {
case stores.EventWrite:
entries = []ipfslog.Entry{evt.Entry}
case stores.EventReplicated:
entries = evt.Entries
}
for _, entry := range entries {
ctx = tyber.ContextWithConstantTraceID(ctx, "msgrcvd-"+entry.GetHash().String())
store.logger.Debug("Received message store event", tyber.FormatTraceLogFields(ctx)...)
store.logger.Debug(
"Message store event",
tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "RawEvent", Description: fmt.Sprint(e)}})...,
)
if err := store.addToMessageQueue(ctx, entry); err != nil {
logger.Error("unable to add message to queue", zap.Error(err))
}
}
}
}(store.ctx)
return store, nil
}
}
func (m *MessageStore) GetMessageByCID(c cid.Cid) (operation.Operation, error) {
logEntry, ok := m.OpLog().Get(c)
if !ok {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("unable to find message entry"))
}
op, err := operation.ParseOperation(logEntry)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
return op, nil
}
func (m *MessageStore) GetOutOfStoreMessageEnvelope(_ context.Context, c cid.Cid) (*protocoltypes.OutOfStoreMessageEnvelope, error) {
op, err := m.GetMessageByCID(c)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
env, headers, err := m.secretStore.OpenEnvelopeHeaders(op.GetValue(), m.group)
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
sealedMessageEnvelope, err := m.secretStore.SealOutOfStoreMessageEnvelope(c, env, headers, m.group)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return sealedMessageEnvelope, nil
}
func (m *MessageStore) Close() error {
m.cancel()
return m.BaseStore.Close()
}
================================================
FILE: store_message_metrics.go
================================================
package weshnet
import (
"encoding/hex"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"berty.tech/weshnet/v2/internal/queue"
)
const messageMetricNamespace = "bty_store_message"
var (
collectorMessageStoreQueueLength = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: messageMetricNamespace,
Name: "message_queue_length",
Help: "message queue length",
}, []string{"kind", "device_pk"},
)
collectorsMessageStore = []prometheus.Collector{
collectorMessageStoreQueueLength,
}
)
var _ queue.MetricsTracer[*messageItem] = (*messageMetricsTracer)(nil)
type messageMetricsTracer struct {
reg prometheus.Registerer
}
func newMessageMetricsTracer(reg prometheus.Registerer) (mt *messageMetricsTracer) {
mt = &messageMetricsTracer{reg: reg}
for _, collector := range collectorsMessageStore {
if err := reg.Register(collector); err != nil {
if _, ok := err.(prometheus.AlreadyRegisteredError); !ok {
panic(fmt.Errorf("message metrics errors: %w", err))
}
return
}
}
// reg.MustRegister(collectorsMessageStore...)
return
}
func (s *messageMetricsTracer) ItemQueued(name string, m *messageItem) {
collectorMessageStoreQueueLength.WithLabelValues(
name, hex.EncodeToString(m.headers.DevicePk),
).Inc()
}
func (s *messageMetricsTracer) ItemPop(name string, m *messageItem) {
collectorMessageStoreQueueLength.WithLabelValues(
name, hex.EncodeToString(m.headers.DevicePk),
).Dec()
}
================================================
FILE: store_message_queue.go
================================================
package weshnet
import (
"github.com/ipfs/go-cid"
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/v2/internal/queue"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
// An Item is something we manage in a priority queue.
type messageItem struct {
op operation.Operation
env *protocoltypes.MessageEnvelope
headers *protocoltypes.MessageHeaders
hash cid.Cid
}
func (m *messageItem) Counter() uint64 {
return m.headers.Counter
}
type simpleMessageQueue = queue.SimpleQueue[*messageItem]
func newMessageQueue(name string, tracer queue.MetricsTracer[*messageItem]) *simpleMessageQueue {
return queue.NewSimpleQueue[*messageItem](name, tracer)
}
type priorityMessageQueue = queue.PriorityQueue[*messageItem]
func newPriorityMessageQueue(name string, tracer queue.MetricsTracer[*messageItem]) *priorityMessageQueue {
return queue.NewPriorityQueue[*messageItem](name, tracer)
}
================================================
FILE: store_message_test.go
================================================
package weshnet
import (
"container/ring"
"context"
"fmt"
"testing"
"time"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
)
func countEntries(out <-chan *protocoltypes.GroupMessageEvent) int {
found := 0
for range out {
found++
}
return found
}
func Test_AddMessage_ListMessages_manually_supplying_secrets(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
memberCount := 2
deviceCount := 1
entriesCount := 25
testMsg1 := []byte("first message")
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/message_test", memberCount, deviceCount)
defer cleanup()
dPK0 := peers[0].GC.DevicePubKey()
ds0For1, err := peers[0].SecretStore.GetShareableChainKey(ctx, peers[0].GC.Group(), peers[1].GC.MemberPubKey())
require.NoError(t, err)
require.NotNil(t, ds0For1)
err = peers[1].SecretStore.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0For1)
require.NoError(t, err)
_, err = peers[0].GC.MessageStore().AddMessage(ctx, testMsg1)
require.NoError(t, err)
<-time.After(time.Millisecond * 500)
out, err := peers[0].GC.MessageStore().ListEvents(ctx, nil, nil, false)
require.NoError(t, err)
require.Equal(t, 1, countEntries(out))
watcherCtx, watcherCancel := context.WithTimeout(ctx, time.Second*5)
chSub, err := peers[1].GC.MessageStore().EventBus().Subscribe(new(*protocoltypes.GroupMessageEvent))
require.NoError(t, err)
defer chSub.Close()
go func() {
for {
select {
case <-chSub.Out():
case <-watcherCtx.Done():
return
}
c, err := peers[1].GC.MessageStore().ListEvents(watcherCtx, nil, nil, false)
if !assert.NoError(t, err) {
watcherCancel()
break
}
if countEntries(c) == entriesCount+1 {
watcherCancel()
break
}
}
}()
for i := 0; i < entriesCount; i++ {
payload := []byte(fmt.Sprintf("test message %d", i))
_, err = peers[0].GC.MessageStore().AddMessage(ctx, payload)
require.NoError(t, err)
}
<-watcherCtx.Done()
out, err = peers[1].GC.MessageStore().ListEvents(ctx, nil, nil, false)
require.NoError(t, err)
<-time.After(time.Second)
require.Equal(t, 1+entriesCount, countEntries(out))
// TODO: check that ListEvents can be called multiple times with the same output
// TODO: check that message are correctly ordered
// TODO: check that message are correctly decrypted
// TODO: check that message sender is correct
// TODO: check that message parents IDs are valid
// TODO: check that message IDs are valid
}
func bufferCount(buffer *ring.Ring) int {
count := 0
buffer.Do(func(f any) {
if _, ok := f.(ipfslog.Entry); ok {
count++
}
})
return count
}
func Test_Add_Messages_To_Cache(t *testing.T) {
testutil.FilterSpeed(t, testutil.Fast)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
memberCount := 2
deviceCount := 1
entriesCount := 50
testMsg1 := []byte("last message")
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/message_test", memberCount, deviceCount)
defer cleanup()
dPK0 := peers[0].GC.DevicePubKey()
dPK0Raw, err := dPK0.Raw()
require.NoError(t, err)
ds0For1, err := peers[0].SecretStore.GetShareableChainKey(ctx, peers[0].GC.Group(), peers[1].GC.MemberPubKey())
require.NoError(t, err)
require.NotNil(t, ds0For1)
cevent, err := peers[0].GC.MessageStore().EventBus().Subscribe(
new(*protocoltypes.GroupMessageEvent), eventbus.BufSize(entriesCount))
require.NoError(t, err)
cadded, err := peers[1].GC.MessageStore().EventBus().Subscribe(
new(messageItem), eventbus.BufSize(entriesCount))
require.NoError(t, err)
for i := 0; i < entriesCount; i++ {
payload := []byte(fmt.Sprintf("test message %d", i))
_, err = peers[0].GC.MessageStore().AddMessage(ctx, payload)
require.NoError(t, err)
}
// check that all events has been received on peer 1
for i := 0; i < entriesCount; i++ {
select {
case <-cevent.Out():
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for group message event")
return
}
}
cevent.Close()
clist, err := peers[0].GC.MessageStore().ListEvents(ctx, nil, nil, false)
require.NoError(t, err)
count := countEntries(clist)
require.Equal(t, entriesCount, count)
// check that messages has been replicated on peer 2
for i := 0; i < entriesCount; i++ {
select {
case <-cadded.Out():
case <-time.After(time.Second * 5):
require.FailNow(t, "timeout while waiting for replicated event")
return
}
}
cadded.Close()
// time.Sleep(time.Millisecond * 500)
size, ok := peers[1].GC.MessageStore().CacheSizeForDevicePK(dPK0Raw)
require.True(t, ok)
require.Equal(t, entriesCount, size)
err = peers[1].SecretStore.RegisterChainKey(ctx, peers[0].GC.Group(), dPK0, ds0For1)
require.NoError(t, err)
cevent, err = peers[1].GC.MessageStore().EventBus().Subscribe(
new(*protocoltypes.GroupMessageEvent), eventbus.BufSize(entriesCount))
require.NoError(t, err)
peers[1].GC.MessageStore().ProcessMessageQueueForDevicePK(ctx, dPK0Raw)
// check that all events has been received on peer 2
for i := 0; i < entriesCount; i++ {
select {
case <-cevent.Out():
case <-time.After(time.Second):
require.FailNow(t, "timeout while waiting for group message event")
return
}
}
cevent.Close()
size, ok = peers[1].GC.MessageStore().CacheSizeForDevicePK(dPK0Raw)
require.True(t, ok)
require.Equal(t, 0, size)
_, err = peers[0].GC.MessageStore().AddMessage(ctx, testMsg1)
require.NoError(t, err)
size, ok = peers[1].GC.MessageStore().CacheSizeForDevicePK(dPK0Raw)
require.True(t, ok)
require.Equal(t, 0, size)
}
================================================
FILE: store_metadata.go
================================================
package weshnet
import (
"context"
crand "crypto/rand"
"encoding/base64"
"fmt"
"io"
"slices"
"strings"
coreiface "github.com/ipfs/kubo/core/coreiface"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/go-ipfs-log/identityprovider"
ipliface "berty.tech/go-ipfs-log/iface"
"berty.tech/go-orbit-db/address"
"berty.tech/go-orbit-db/iface"
"berty.tech/go-orbit-db/stores"
"berty.tech/go-orbit-db/stores/basestore"
"berty.tech/go-orbit-db/stores/operation"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/tyber"
)
type MetadataStore struct {
basestore.BaseStore
eventBus event.Bus
emitters struct {
groupMetadata event.Emitter
metadataReceived event.Emitter
}
group *protocoltypes.Group
memberDevice secretstore.OwnMemberDevice
devicePublicKeyRaw []byte
secretStore secretstore.SecretStore
logger *zap.Logger
ctx context.Context
cancel context.CancelFunc
}
func isMultiMemberGroup(m *MetadataStore) bool {
return m.group.GroupType == protocoltypes.GroupType_GroupTypeMultiMember
}
func isAccountGroup(m *MetadataStore) bool {
return m.group.GroupType == protocoltypes.GroupType_GroupTypeAccount
}
func isContactGroup(m *MetadataStore) bool {
return m.group.GroupType == protocoltypes.GroupType_GroupTypeContact
}
func (m *MetadataStore) typeChecker(types ...func(m *MetadataStore) bool) bool {
for _, t := range types {
if t(m) {
return true
}
}
return false
}
func (m *MetadataStore) setLogger(l *zap.Logger) {
if l == nil {
return
}
// m.logger = l.Named("store").With(logutil.PrivateString("group-id", fmt.Sprintf("%.6s", base64.StdEncoding.EncodeToString(m.group.PublicKey))))
m.logger = l.Named("metastore")
if index, ok := m.Index().(loggable); ok {
index.setLogger(m.logger)
}
}
func openMetadataEntry(log ipfslog.Log, e ipfslog.Entry, g *protocoltypes.Group) (*protocoltypes.GroupMetadataEvent, proto.Message, error) {
op, err := operation.ParseOperation(e)
if err != nil {
return nil, nil, err
}
meta, event, err := openGroupEnvelope(g, op.GetValue())
if err != nil {
return nil, nil, err
}
metaEvent, err := newGroupMetadataEventFromEntry(log, e, meta, event, g)
if err != nil {
return nil, nil, err
}
return metaEvent, event, err
}
// not used
// func (m *MetadataStore) openMetadataEntry(e ipfslog.Entry) (*protocoltypes.GroupMetadataEvent, proto.Message, error) {
// return openMetadataEntry(m.OpLog(), e, m.group, m.devKS)
// }
// FIXME: use iterator instead to reduce resource usage (require go-ipfs-log improvements)
func (m *MetadataStore) ListEvents(_ context.Context, since, until []byte, reverse bool) (<-chan *protocoltypes.GroupMetadataEvent, error) {
entries, err := getEntriesInRange(m.OpLog().GetEntries().Reverse().Slice(), since, until)
if err != nil {
return nil, err
}
out := make(chan *protocoltypes.GroupMetadataEvent)
go func() {
iterateOverEntries(
entries,
reverse,
func(entry ipliface.IPFSLogEntry) {
event, _, err := openMetadataEntry(m.OpLog(), entry, m.group)
if err != nil {
m.logger.Error("unable to open metadata event", zap.Error(err))
} else {
out <- event
m.logger.Info("metadata store - sent 1 event from log history")
}
},
)
close(out)
}()
return out, nil
}
func (m *MetadataStore) AddDeviceToGroup(ctx context.Context) (operation.Operation, error) {
md, err := m.secretStore.GetOwnMemberDeviceForGroup(m.group)
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return MetadataStoreAddDeviceToGroup(ctx, m, m.group, md)
}
func MetadataStoreAddDeviceToGroup(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md secretstore.OwnMemberDevice) (operation.Operation, error) {
device, err := md.Device().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
member, err := md.Member().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
k, err := m.GetMemberByDevice(md.Device())
if err == nil && k != nil {
return nil, nil
}
memberSig, err := md.MemberSign(device)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
event := &protocoltypes.GroupMemberDeviceAdded{
MemberPk: member,
DevicePk: device,
MemberSig: memberSig,
}
sig, err := signProtoWithDevice(event, md)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
m.logger.Info("announcing device on store")
return metadataStoreAddEvent(ctx, m, g, protocoltypes.EventType_EventTypeGroupMemberDeviceAdded, event, sig)
}
func (m *MetadataStore) SendSecret(ctx context.Context, memberPK crypto.PubKey) (operation.Operation, error) {
ok, err := m.Index().(*metadataStoreIndex).areSecretsAlreadySent(memberPK)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
if ok {
return nil, errcode.ErrCode_ErrGroupSecretAlreadySentToMember
}
if devs, err := m.GetDevicesForMember(memberPK); len(devs) == 0 || err != nil {
m.logger.Warn("sending secret to an unknown group member")
}
encryptedSecret, err := m.secretStore.GetShareableChainKey(ctx, m.group, memberPK)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoEncrypt.Wrap(err)
}
return MetadataStoreSendSecret(ctx, m, m.group, m.memberDevice, memberPK, encryptedSecret)
}
func MetadataStoreSendSecret(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, md secretstore.OwnMemberDevice, memberPK crypto.PubKey, encryptedSecret []byte) (operation.Operation, error) {
devicePKRaw, err := md.Device().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
memberPKRaw, err := memberPK.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
event := &protocoltypes.GroupDeviceChainKeyAdded{
DevicePk: devicePKRaw,
DestMemberPk: memberPKRaw,
Payload: encryptedSecret,
}
sig, err := signProtoWithDevice(event, md)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
return metadataStoreAddEvent(ctx, m, g, protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded, event, sig)
}
func (m *MetadataStore) ClaimGroupOwnership(ctx context.Context, groupSK crypto.PrivKey) (operation.Operation, error) {
if !m.typeChecker(isMultiMemberGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
event := &protocoltypes.MultiMemberGroupInitialMemberAnnounced{
MemberPk: m.devicePublicKeyRaw,
}
sig, err := signProtoWithPrivateKey(event, groupSK)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
return metadataStoreAddEvent(ctx, m, m.group, protocoltypes.EventType_EventTypeMultiMemberGroupInitialMemberAnnounced, event, sig)
}
func signProtoWithDevice(message proto.Message, memberDevice secretstore.OwnMemberDevice) ([]byte, error) {
data, err := proto.Marshal(message)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
sig, err := memberDevice.DeviceSign(data)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
return sig, nil
}
func signProtoWithPrivateKey(message proto.Message, sk crypto.PrivKey) ([]byte, error) {
data, err := proto.Marshal(message)
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
sig, err := sk.Sign(data)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
return sig, nil
}
func metadataStoreAddEvent(ctx context.Context, m *MetadataStore, g *protocoltypes.Group, eventType protocoltypes.EventType, event proto.Message, sig []byte) (operation.Operation, error) {
ctx, newTrace := tyber.ContextWithTraceID(ctx)
tyberLogError := tyber.LogError
if newTrace {
m.logger.Debug(fmt.Sprintf("Sending %s to %s group %s", strings.TrimPrefix(eventType.String(), "EventType"), strings.TrimPrefix(g.GroupType.String(), "GroupType"), base64.RawURLEncoding.EncodeToString(g.PublicKey)), tyber.FormatTraceLogFields(ctx)...)
tyberLogError = tyber.LogFatalError
}
env, err := sealGroupEnvelope(g, eventType, event, sig)
if err != nil {
return nil, tyberLogError(ctx, m.logger, "Failed to seal group envelope", errcode.ErrCode_ErrCryptoSignature.Wrap(err))
}
m.logger.Debug(fmt.Sprintf("Sealed group envelope (%d bytes)", len(env)), tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
op := operation.NewOperation(nil, "ADD", env)
e, err := m.AddOperation(ctx, op, nil)
if err != nil {
return nil, tyberLogError(ctx, m.logger, "Failed to add operation on log", errcode.ErrCode_ErrOrbitDBAppend.Wrap(err))
}
m.logger.Debug("Added operation on log", tyber.FormatStepLogFields(ctx, []tyber.Detail{
{Name: "CID", Description: e.GetHash().String()},
})...)
op, err = operation.ParseOperation(e)
if err != nil {
return nil, tyberLogError(ctx, m.logger, "Failed to parse operation returned by log", errcode.ErrCode_ErrOrbitDBDeserialization.Wrap(err))
}
if newTrace {
m.logger.Debug("Added metadata on log successfully", tyber.FormatStepLogFields(ctx, []tyber.Detail{}, tyber.EndTrace)...)
}
return op, nil
}
func (m *MetadataStore) ListContacts() map[string]*AccountContact {
return m.Index().(*metadataStoreIndex).listContacts()
}
func (m *MetadataStore) ListVerifiedCredentials() []*protocoltypes.AccountVerifiedCredentialRegistered {
return m.Index().(*metadataStoreIndex).listVerifiedCredentials()
}
func (m *MetadataStore) GetMemberByDevice(pk crypto.PubKey) (crypto.PubKey, error) {
return m.Index().(*metadataStoreIndex).getMemberByDevice(pk)
}
func (m *MetadataStore) GetDevicesForMember(pk crypto.PubKey) ([]crypto.PubKey, error) {
return m.Index().(*metadataStoreIndex).getDevicesForMember(pk)
}
func (m *MetadataStore) ListAdmins() []crypto.PubKey {
if m.typeChecker(isContactGroup, isAccountGroup) {
return m.ListMembers()
}
return m.Index().(*metadataStoreIndex).listAdmins()
}
func (m *MetadataStore) GetIncomingContactRequestsStatus() (bool, *protocoltypes.ShareableContact) {
if !m.typeChecker(isAccountGroup) {
return false, nil
}
enabled := m.Index().(*metadataStoreIndex).contactRequestsEnabled()
seed := m.Index().(*metadataStoreIndex).contactRequestsSeed()
rawMemberDevice, err := m.memberDevice.Member().Raw()
if err != nil {
m.logger.Error("unable to serialize member public key", zap.Error(err))
return enabled, nil
}
contactRef := &protocoltypes.ShareableContact{
Pk: rawMemberDevice,
PublicRendezvousSeed: seed,
}
return enabled, contactRef
}
func (m *MetadataStore) ListMembers() []crypto.PubKey {
if m.typeChecker(isAccountGroup, isContactGroup, isMultiMemberGroup) {
return m.Index().(*metadataStoreIndex).listMembers()
}
return nil
}
func (m *MetadataStore) ListDevices() []crypto.PubKey {
return m.Index().(*metadataStoreIndex).listDevices()
}
func (m *MetadataStore) ListMultiMemberGroups() []*protocoltypes.Group {
if !m.typeChecker(isAccountGroup) {
return nil
}
idx, ok := m.Index().(*metadataStoreIndex)
if !ok {
return nil
}
idx.lock.Lock()
defer idx.lock.Unlock()
groups := []*protocoltypes.Group(nil)
for _, g := range idx.groups {
if g.state != accountGroupJoinedStateJoined {
continue
}
groups = append(groups, g.group)
}
return groups
}
func (m *MetadataStore) ListOtherMembersDevices() []crypto.PubKey {
return m.Index().(*metadataStoreIndex).listOtherMembersDevices()
}
func (m *MetadataStore) GetRequestOwnMetadataForContact(pk []byte) ([]byte, error) {
idx, ok := m.Index().(*metadataStoreIndex)
if !ok {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid index type"))
}
idx.lock.Lock()
defer idx.lock.Unlock()
meta, ok := idx.contactRequestMetadata[string(pk)]
if !ok {
return nil, errcode.ErrCode_ErrMissingMapKey.Wrap(fmt.Errorf("no metadata found for specified contact"))
}
return meta, nil
}
func (m *MetadataStore) ListContactsByStatus(states ...protocoltypes.ContactState) []*protocoltypes.ShareableContact {
if !m.typeChecker(isAccountGroup) {
return nil
}
idx, ok := m.Index().(*metadataStoreIndex)
if !ok {
return nil
}
idx.lock.Lock()
defer idx.lock.Unlock()
contacts := []*protocoltypes.ShareableContact(nil)
for _, c := range idx.contacts {
hasState := slices.Contains(states, c.state)
if hasState {
contacts = append(contacts, c.contact)
}
}
return contacts
}
func (m *MetadataStore) GetContactFromGroupPK(groupPK []byte) *protocoltypes.ShareableContact {
if !m.typeChecker(isAccountGroup) {
return nil
}
idx, ok := m.Index().(*metadataStoreIndex)
if !ok {
return nil
}
idx.lock.Lock()
defer idx.lock.Unlock()
contact, ok := idx.contactsFromGroupPK[string(groupPK)]
if !ok || contact == nil {
return nil
}
return contact.contact
}
func (m *MetadataStore) checkIfInGroup(pk []byte) bool {
idx, ok := m.Index().(*metadataStoreIndex)
if !ok {
return false
}
idx.lock.Lock()
defer idx.lock.Unlock()
if existingGroup, ok := idx.groups[string(pk)]; ok && existingGroup.state == accountGroupJoinedStateJoined {
return true
}
return false
}
// GroupJoin indicates the payload includes that the deviceKeystore has joined a group
func (m *MetadataStore) GroupJoin(ctx context.Context, g *protocoltypes.Group) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if err := g.IsValid(); err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if m.checkIfInGroup(g.PublicKey) {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("already present in group"))
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountGroupJoined{
Group: g,
}, protocoltypes.EventType_EventTypeAccountGroupJoined)
}
// GroupLeave indicates the payload includes that the deviceKeystore has left a group
func (m *MetadataStore) GroupLeave(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if pk == nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
bytes, err := pk.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
if !m.checkIfInGroup(bytes) {
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.groupAction(ctx, pk, &protocoltypes.AccountGroupLeft{}, protocoltypes.EventType_EventTypeAccountGroupLeft)
}
// ContactRequestDisable indicates the payload includes that the deviceKeystore has disabled incoming contact requests
func (m *MetadataStore) ContactRequestDisable(ctx context.Context) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountContactRequestDisabled{}, protocoltypes.EventType_EventTypeAccountContactRequestDisabled)
}
// ContactRequestEnable indicates the payload includes that the deviceKeystore has enabled incoming contact requests
func (m *MetadataStore) ContactRequestEnable(ctx context.Context) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountContactRequestEnabled{}, protocoltypes.EventType_EventTypeAccountContactRequestEnabled)
}
// ContactRequestReferenceReset indicates the payload includes that the deviceKeystore has a new contact request reference
func (m *MetadataStore) ContactRequestReferenceReset(ctx context.Context) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
seed, err := genNewSeed()
if err != nil {
return nil, errcode.ErrCode_ErrCryptoKeyGeneration.Wrap(err)
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountContactRequestReferenceReset{
PublicRendezvousSeed: seed,
}, protocoltypes.EventType_EventTypeAccountContactRequestReferenceReset)
}
// ContactRequestOutgoingEnqueue indicates the payload includes that the deviceKeystore will attempt to send a new contact request
func (m *MetadataStore) ContactRequestOutgoingEnqueue(ctx context.Context, contact *protocoltypes.ShareableContact, ownMetadata []byte) (operation.Operation, error) {
ctx, _ = tyber.ContextWithTraceID(ctx)
b64GroupPK := base64.RawURLEncoding.EncodeToString(m.group.PublicKey)
m.logger.Debug("Enqueuing contact request", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "GroupPK", Description: fmt.Sprint(b64GroupPK)}})...)
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if err := contact.CheckFormat(); err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
accountPublicKey := m.memberDevice.Member()
if contact.IsSamePK(accountPublicKey) {
return nil, errcode.ErrCode_ErrContactRequestSameAccount
}
pk, err := contact.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateAdded) {
return nil, errcode.ErrCode_ErrContactRequestContactAlreadyAdded
}
if m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateRemoved, protocoltypes.ContactState_ContactStateDiscarded, protocoltypes.ContactState_ContactStateReceived) {
return m.ContactRequestOutgoingSent(ctx, pk)
}
op, err := m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountContactRequestOutgoingEnqueued{
Contact: &protocoltypes.ShareableContact{
Pk: contact.Pk,
PublicRendezvousSeed: contact.PublicRendezvousSeed,
Metadata: contact.Metadata,
},
OwnMetadata: ownMetadata,
}, protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued)
m.logger.Debug("Enqueued contact request", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
return op, err
}
// ContactRequestOutgoingSent indicates the payload includes that the deviceKeystore has sent a contact request
func (m *MetadataStore) ContactRequestOutgoingSent(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
switch m.getContactStatus(pk) {
case protocoltypes.ContactState_ContactStateToRequest:
case protocoltypes.ContactState_ContactStateReceived:
case protocoltypes.ContactState_ContactStateRemoved:
case protocoltypes.ContactState_ContactStateDiscarded:
case protocoltypes.ContactState_ContactStateUndefined:
return nil, errcode.ErrCode_ErrContactRequestContactUndefined
case protocoltypes.ContactState_ContactStateAdded:
return nil, errcode.ErrCode_ErrContactRequestContactAlreadyAdded
case protocoltypes.ContactState_ContactStateBlocked:
return nil, errcode.ErrCode_ErrContactRequestContactBlocked
default:
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.contactAction(ctx, pk, &protocoltypes.AccountContactRequestOutgoingSent{}, protocoltypes.EventType_EventTypeAccountContactRequestOutgoingSent)
}
// ContactRequestIncomingReceived indicates the payload includes that the deviceKeystore has received a contact request
func (m *MetadataStore) ContactRequestIncomingReceived(ctx context.Context, contact *protocoltypes.ShareableContact) (operation.Operation, error) {
m.logger.Debug("Sending ContactRequestIncomingReceived on Account group", tyber.FormatStepLogFields(ctx, []tyber.Detail{})...)
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if err := contact.CheckFormat(protocoltypes.ShareableContactOptionsAllowMissingRDVSeed); err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
accountPublicKey := m.memberDevice.Member()
if contact.IsSamePK(accountPublicKey) {
return nil, errcode.ErrCode_ErrContactRequestSameAccount
}
pk, err := contact.GetPubKey()
if err != nil {
return nil, errcode.ErrCode_ErrDeserialization.Wrap(err)
}
switch m.getContactStatus(pk) {
case protocoltypes.ContactState_ContactStateUndefined:
case protocoltypes.ContactState_ContactStateRemoved:
case protocoltypes.ContactState_ContactStateDiscarded:
// If incoming request comes from an account for which an outgoing request
// is in "sending" state, mark the outgoing request as "sent"
case protocoltypes.ContactState_ContactStateToRequest:
return m.ContactRequestOutgoingSent(ctx, pk)
// Errors
case protocoltypes.ContactState_ContactStateReceived:
return nil, errcode.ErrCode_ErrContactRequestIncomingAlreadyReceived
case protocoltypes.ContactState_ContactStateAdded:
return nil, errcode.ErrCode_ErrContactRequestContactAlreadyAdded
case protocoltypes.ContactState_ContactStateBlocked:
return nil, errcode.ErrCode_ErrContactRequestContactBlocked
default:
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.AccountContactRequestIncomingReceived{
ContactPk: contact.Pk,
ContactRendezvousSeed: contact.PublicRendezvousSeed,
ContactMetadata: contact.Metadata,
}, protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived)
}
// ContactRequestIncomingDiscard indicates the payload includes that the deviceKeystore has ignored a contact request
func (m *MetadataStore) ContactRequestIncomingDiscard(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if !m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateReceived) {
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.contactAction(ctx, pk, &protocoltypes.AccountContactRequestIncomingDiscarded{}, protocoltypes.EventType_EventTypeAccountContactRequestIncomingDiscarded)
}
// ContactRequestIncomingAccept indicates the payload includes that the deviceKeystore has accepted a contact request
func (m *MetadataStore) ContactRequestIncomingAccept(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if !m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateReceived) {
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.contactAction(ctx, pk, &protocoltypes.AccountContactRequestIncomingAccepted{}, protocoltypes.EventType_EventTypeAccountContactRequestIncomingAccepted)
}
// ContactBlock indicates the payload includes that the deviceKeystore has blocked a contact
func (m *MetadataStore) ContactBlock(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
accountPublicKey := m.memberDevice.Member()
if accountPublicKey.Equals(pk) {
return nil, errcode.ErrCode_ErrInvalidInput
}
if m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateBlocked) {
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.contactAction(ctx, pk, &protocoltypes.AccountContactBlocked{}, protocoltypes.EventType_EventTypeAccountContactBlocked)
}
// ContactUnblock indicates the payload includes that the deviceKeystore has unblocked a contact
func (m *MetadataStore) ContactUnblock(ctx context.Context, pk crypto.PubKey) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
if !m.checkContactStatus(pk, protocoltypes.ContactState_ContactStateBlocked) {
return nil, errcode.ErrCode_ErrInvalidInput
}
return m.contactAction(ctx, pk, &protocoltypes.AccountContactUnblocked{}, protocoltypes.EventType_EventTypeAccountContactUnblocked)
}
func (m *MetadataStore) ContactSendAliasKey(ctx context.Context) (operation.Operation, error) {
if !m.typeChecker(isContactGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
accountProofPublicKey, err := m.secretStore.GetAccountProofPublicKey()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
alias, err := accountProofPublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrInternal.Wrap(err)
}
return m.attributeSignAndAddEvent(ctx, &protocoltypes.ContactAliasKeyAdded{
AliasPk: alias,
}, protocoltypes.EventType_EventTypeContactAliasKeyAdded)
}
func (m *MetadataStore) SendAliasProof(ctx context.Context) (operation.Operation, error) {
if !m.typeChecker(isMultiMemberGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
resolver := []byte(nil) // TODO: should be a hmac value of something for quicker searches
proof := []byte(nil) // TODO: should be a signed value of something
return m.attributeSignAndAddEvent(ctx, &protocoltypes.MultiMemberGroupAliasResolverAdded{
AliasResolver: resolver,
AliasProof: proof,
}, protocoltypes.EventType_EventTypeMultiMemberGroupAliasResolverAdded)
}
func (m *MetadataStore) SendAppMetadata(ctx context.Context, message []byte) (operation.Operation, error) {
return m.attributeSignAndAddEvent(ctx, &protocoltypes.GroupMetadataPayloadSent{
Message: message,
}, protocoltypes.EventType_EventTypeGroupMetadataPayloadSent)
}
func (m *MetadataStore) SendAccountVerifiedCredentialAdded(ctx context.Context, token *protocoltypes.AccountVerifiedCredentialRegistered) (operation.Operation, error) {
if !m.typeChecker(isAccountGroup) {
return nil, errcode.ErrCode_ErrGroupInvalidType
}
return m.attributeSignAndAddEvent(ctx, token, protocoltypes.EventType_EventTypeAccountVerifiedCredentialRegistered)
}
func (m *MetadataStore) SendGroupReplicating(ctx context.Context, authenticationURL, replicationServer string) (operation.Operation, error) {
return m.attributeSignAndAddEvent(ctx, &protocoltypes.GroupReplicating{
AuthenticationUrl: authenticationURL,
ReplicationServer: replicationServer,
}, protocoltypes.EventType_EventTypeGroupReplicating)
}
type accountSignableEvent interface {
proto.Message
SetDevicePK([]byte)
}
type accountContactEvent interface {
accountSignableEvent
SetContactPK([]byte)
}
type accountGroupEvent interface {
accountSignableEvent
SetGroupPK([]byte)
}
func (m *MetadataStore) attributeSignAndAddEvent(ctx context.Context, evt accountSignableEvent, eventType protocoltypes.EventType) (operation.Operation, error) {
evt.SetDevicePK(m.devicePublicKeyRaw)
sig, err := signProtoWithDevice(evt, m.memberDevice)
if err != nil {
return nil, errcode.ErrCode_ErrCryptoSignature.Wrap(err)
}
m.logger.Debug("Signed event", tyber.FormatStepLogFields(ctx, []tyber.Detail{{Name: "Signature", Description: base64.RawURLEncoding.EncodeToString(sig)}})...)
return metadataStoreAddEvent(ctx, m, m.group, eventType, evt, sig)
}
func (m *MetadataStore) contactAction(ctx context.Context, pk crypto.PubKey, event accountContactEvent, evtType protocoltypes.EventType) (operation.Operation, error) {
ctx, newTrace := tyber.ContextWithTraceID(ctx)
var tyberFields []zap.Field
if newTrace {
tyberFields = tyber.FormatTraceLogFields(ctx)
} else {
tyberFields = tyber.FormatStepLogFields(ctx, []tyber.Detail{})
}
m.logger.Debug("Sending "+strings.TrimPrefix(evtType.String(), "EventType")+" on Account group", tyberFields...)
if pk == nil || event == nil {
return nil, errcode.ErrCode_ErrInvalidInput
}
pkBytes, err := pk.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
event.SetContactPK(pkBytes)
op, err := m.attributeSignAndAddEvent(ctx, event, evtType)
if err != nil {
return nil, err
}
if newTrace {
m.logger.Debug("Event added successfully", tyber.FormatStepLogFields(ctx, []tyber.Detail{}, tyber.EndTrace)...)
}
return op, nil
}
func (m *MetadataStore) groupAction(ctx context.Context, pk crypto.PubKey, event accountGroupEvent, evtType protocoltypes.EventType) (operation.Operation, error) {
pkBytes, err := pk.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
event.SetGroupPK(pkBytes)
return m.attributeSignAndAddEvent(ctx, event, evtType)
}
func (m *MetadataStore) getContactStatus(pk crypto.PubKey) protocoltypes.ContactState {
if pk == nil {
return protocoltypes.ContactState_ContactStateUndefined
}
contact, err := m.Index().(*metadataStoreIndex).getContact(pk)
if err != nil {
m.logger.Warn("unable to get contact for public key", zap.Error(err))
return protocoltypes.ContactState_ContactStateUndefined
}
return contact.state
}
func (m *MetadataStore) checkContactStatus(pk crypto.PubKey, states ...protocoltypes.ContactState) bool {
contactStatus := m.getContactStatus(pk)
return slices.Contains(states, contactStatus)
}
type EventMetadataReceived struct {
MetaEvent *protocoltypes.GroupMetadataEvent
Event proto.Message
}
func constructorFactoryGroupMetadata(s *WeshOrbitDB, logger *zap.Logger) iface.StoreConstructor {
return func(ipfs coreiface.CoreAPI, identity *identityprovider.Identity, addr address.Address, options *iface.NewStoreOptions) (iface.Store, error) {
g, err := s.getGroupFromOptions(options)
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
shortGroupType := strings.TrimPrefix(g.GetGroupType().String(), "GroupType")
b64GroupPK := base64.RawURLEncoding.EncodeToString(g.PublicKey)
replication := false
if options.EventBus == nil {
options.EventBus = eventbus.NewBus()
}
store := &MetadataStore{
eventBus: options.EventBus,
group: g,
logger: logger,
secretStore: s.secretStore,
}
if s.replicationMode {
replication = true
} else {
var err error
store.memberDevice, err = s.secretStore.GetOwnMemberDeviceForGroup(g)
if err != nil {
if errcode.Is(err, errcode.ErrCode_ErrInvalidInput) {
replication = true
} else {
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
} else {
store.devicePublicKeyRaw, err = store.memberDevice.Device().Raw()
if err != nil {
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
}
}
store.ctx, store.cancel = context.WithCancel(context.Background())
if err := store.initEmitter(); err != nil {
return nil, fmt.Errorf("unable to init emitters: %w", err)
}
if replication {
options.Index = basestore.NewNoopIndex
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
store.cancel()
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
return store, nil
}
chSub, err := store.eventBus.Subscribe([]any{
new(stores.EventWrite),
new(stores.EventReplicated),
}, eventbus.BufSize(128))
if err != nil {
store.cancel()
return nil, fmt.Errorf("unable to subscribe to store events")
}
// Enable logs in the metadata index
store.setLogger(logger)
go func(ctx context.Context) {
defer chSub.Close()
for {
var e any
select {
case e = <-chSub.Out():
case <-ctx.Done():
return
}
var entries []ipfslog.Entry
switch evt := e.(type) {
case stores.EventWrite:
entries = []ipfslog.Entry{evt.Entry}
case stores.EventReplicated:
entries = evt.Entries
}
for _, entry := range entries {
ctx = tyber.ContextWithConstantTraceID(ctx, "msgrcvd-"+entry.GetHash().String())
tyber.LogTraceStart(ctx, store.logger, fmt.Sprintf("Received metadata from %s group %s", shortGroupType, b64GroupPK))
metaEvent, event, err := openMetadataEntry(store.OpLog(), entry, g)
if err != nil {
_ = tyber.LogFatalError(ctx, store.logger, "Unable to open metadata event", err, tyber.WithDetail("RawEvent", fmt.Sprint(e)), tyber.ForceReopen)
continue
}
tyber.LogStep(ctx, store.logger, "Opened metadata store event",
tyber.ForceReopen,
tyber.EndTrace,
tyber.WithJSONDetail("MetaEvent", metaEvent),
tyber.WithJSONDetail("Event", event),
tyber.UpdateTraceName(fmt.Sprintf("Received %s from %s group %s", strings.TrimPrefix(metaEvent.GetMetadata().GetEventType().String(), "EventType"), shortGroupType, b64GroupPK)),
)
recvEvent := EventMetadataReceived{
MetaEvent: metaEvent,
Event: event,
}
if err := store.emitters.metadataReceived.Emit(recvEvent); err != nil {
store.logger.Warn("unable to emit recv event", zap.Error(err))
}
if err := store.emitters.groupMetadata.Emit(metaEvent); err != nil {
store.logger.Warn("unable to emit group metadata event", zap.Error(err))
}
}
}
}(store.ctx)
options.Index = newMetadataIndex(store.ctx, g, store.memberDevice, s.secretStore)
if err := store.InitBaseStore(ipfs, identity, addr, options); err != nil {
store.cancel()
return nil, errcode.ErrCode_ErrOrbitDBInit.Wrap(err)
}
return store, nil
}
}
func (m *MetadataStore) initEmitter() (err error) {
if m.emitters.metadataReceived, err = m.eventBus.Emitter(new(EventMetadataReceived)); err != nil {
return err
}
if m.emitters.groupMetadata, err = m.eventBus.Emitter(new(*protocoltypes.GroupMetadataEvent)); err != nil {
return err
}
return err
}
func genNewSeed() (seed []byte, err error) {
seed, err = io.ReadAll(io.LimitReader(crand.Reader, protocoltypes.RendezvousSeedLength))
return seed, err
}
func (m *MetadataStore) Close() error {
m.cancel()
return m.BaseStore.Close()
}
================================================
FILE: store_metadata_index.go
================================================
package weshnet
import (
"context"
"fmt"
"sync"
"github.com/libp2p/go-libp2p/core/crypto"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
ipfslog "berty.tech/go-ipfs-log"
"berty.tech/go-orbit-db/iface"
"berty.tech/weshnet/v2/pkg/cryptoutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
)
// FIXME: replace members, devices, sentSecrets, contacts and groups by a circular buffer to avoid an attack by RAM saturation
type metadataStoreIndex struct {
members map[string][]secretstore.MemberDevice
devices map[string]secretstore.MemberDevice
handledEvents map[string]struct{}
sentSecrets map[string]struct{}
admins map[crypto.PubKey]struct{}
contacts map[string]*AccountContact
contactsFromGroupPK map[string]*AccountContact
groups map[string]*accountGroup
contactRequestMetadata map[string][]byte
verifiedCredentials []*protocoltypes.AccountVerifiedCredentialRegistered
contactRequestSeed []byte
contactRequestEnabled *bool
eventHandlers map[protocoltypes.EventType][]func(event proto.Message) error
postIndexActions []func() error
eventsContactAddAliasKey []*protocoltypes.ContactAliasKeyAdded
ownAliasKeySent bool
otherAliasKey []byte
group *protocoltypes.Group
ownMemberDevice secretstore.MemberDevice
secretStore secretstore.SecretStore
ctx context.Context
lock sync.RWMutex
logger *zap.Logger
}
//nolint:revive
func (m *metadataStoreIndex) Get(key string) any {
return nil
}
func (m *metadataStoreIndex) setLogger(logger *zap.Logger) {
if logger == nil {
return
}
m.logger = logger
}
func (m *metadataStoreIndex) UpdateIndex(log ipfslog.Log, _ []ipfslog.Entry) error {
m.lock.Lock()
defer m.lock.Unlock()
entries := log.GetEntries().Slice()
// Resetting state
m.contacts = map[string]*AccountContact{}
m.contactsFromGroupPK = map[string]*AccountContact{}
m.groups = map[string]*accountGroup{}
m.contactRequestMetadata = map[string][]byte{}
m.contactRequestEnabled = nil
m.contactRequestSeed = []byte(nil)
m.verifiedCredentials = nil
m.handledEvents = map[string]struct{}{}
for i := len(entries) - 1; i >= 0; i-- {
e := entries[i]
_, alreadyHandledEvent := m.handledEvents[e.GetHash().String()]
// TODO: improve account events handling
if m.group.GroupType != protocoltypes.GroupType_GroupTypeAccount && alreadyHandledEvent {
continue
}
metaEvent, event, err := openMetadataEntry(log, e, m.group)
if err != nil {
m.logger.Error("unable to open metadata entry", zap.Error(err))
continue
}
handlers, ok := m.eventHandlers[metaEvent.Metadata.EventType]
if !ok {
m.handledEvents[e.GetHash().String()] = struct{}{}
m.logger.Error("handler for event type not found", zap.String("event-type", metaEvent.Metadata.EventType.String()))
continue
}
var lastErr error
for _, h := range handlers {
err = h(event)
if err != nil {
m.logger.Error("unable to handle event", zap.Error(err))
lastErr = err
}
}
if lastErr != nil {
m.handledEvents[e.GetHash().String()] = struct{}{}
continue
}
m.handledEvents[e.GetHash().String()] = struct{}{}
}
for _, h := range m.postIndexActions {
if err := h(); err != nil {
return errcode.ErrCode_ErrInternal.Wrap(err)
}
}
return nil
}
func (m *metadataStoreIndex) handleGroupMemberDeviceAdded(event proto.Message) error {
e, ok := event.(*protocoltypes.GroupMemberDeviceAdded)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
member, err := crypto.UnmarshalEd25519PublicKey(e.MemberPk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
device, err := crypto.UnmarshalEd25519PublicKey(e.DevicePk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if _, ok := m.devices[string(e.DevicePk)]; ok {
return nil
}
memberDevice := secretstore.NewMemberDevice(member, device)
m.devices[string(e.DevicePk)] = memberDevice
m.members[string(e.MemberPk)] = append(m.members[string(e.MemberPk)], memberDevice)
return nil
}
func (m *metadataStoreIndex) handleGroupDeviceChainKeyAdded(event proto.Message) error {
e, ok := event.(*protocoltypes.GroupDeviceChainKeyAdded)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
_, err := crypto.UnmarshalEd25519PublicKey(e.DestMemberPk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
senderPK, err := crypto.UnmarshalEd25519PublicKey(e.DevicePk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if m.ownMemberDevice.Device().Equals(senderPK) {
m.sentSecrets[string(e.DestMemberPk)] = struct{}{}
}
return nil
}
func (m *metadataStoreIndex) getMemberByDevice(devicePublicKey crypto.PubKey) (crypto.PubKey, error) {
m.lock.RLock()
defer m.lock.RUnlock()
publicKeyBytes, err := devicePublicKey.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
return m.unsafeGetMemberByDevice(publicKeyBytes)
}
func (m *metadataStoreIndex) unsafeGetMemberByDevice(publicKeyBytes []byte) (crypto.PubKey, error) {
if l := len(publicKeyBytes); l != cryptoutil.KeySize {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid private key size, expected %d got %d", cryptoutil.KeySize, l))
}
device, ok := m.devices[string(publicKeyBytes)]
if !ok {
return nil, errcode.ErrCode_ErrMissingInput
}
return device.Member(), nil
}
func (m *metadataStoreIndex) getDevicesForMember(pk crypto.PubKey) ([]crypto.PubKey, error) {
m.lock.RLock()
defer m.lock.RUnlock()
id, err := pk.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
mds, ok := m.members[string(id)]
if !ok {
return nil, errcode.ErrCode_ErrInvalidInput
}
ret := make([]crypto.PubKey, len(mds))
for i, md := range mds {
ret[i] = md.Device()
}
return ret, nil
}
func (m *metadataStoreIndex) MemberCount() int {
m.lock.RLock()
defer m.lock.RUnlock()
return len(m.members)
}
func (m *metadataStoreIndex) DeviceCount() int {
m.lock.RLock()
defer m.lock.RUnlock()
return len(m.devices)
}
func (m *metadataStoreIndex) listContacts() map[string]*AccountContact {
m.lock.RLock()
defer m.lock.RUnlock()
contacts := make(map[string]*AccountContact)
for k, contact := range m.contacts {
contacts[k] = &AccountContact{
state: contact.state,
contact: &protocoltypes.ShareableContact{
Pk: contact.contact.Pk,
PublicRendezvousSeed: contact.contact.PublicRendezvousSeed,
Metadata: contact.contact.Metadata,
},
}
}
return contacts
}
func (m *metadataStoreIndex) listVerifiedCredentials() []*protocoltypes.AccountVerifiedCredentialRegistered {
m.lock.RLock()
defer m.lock.RUnlock()
return m.verifiedCredentials
}
func (m *metadataStoreIndex) listMembers() []crypto.PubKey {
m.lock.RLock()
defer m.lock.RUnlock()
members := make([]crypto.PubKey, len(m.members))
i := 0
for _, md := range m.members {
members[i] = md[0].Member()
i++
}
return members
}
func (m *metadataStoreIndex) listDevices() []crypto.PubKey {
m.lock.RLock()
defer m.lock.RUnlock()
devices := make([]crypto.PubKey, len(m.devices))
i := 0
for _, md := range m.devices {
devices[i] = md.Device()
i++
}
return devices
}
func (m *metadataStoreIndex) areSecretsAlreadySent(pk crypto.PubKey) (bool, error) {
m.lock.RLock()
defer m.lock.RUnlock()
key, err := pk.Raw()
if err != nil {
return false, errcode.ErrCode_ErrInvalidInput.Wrap(err)
}
_, ok := m.sentSecrets[string(key)]
return ok, nil
}
type accountGroupJoinedState uint32
const (
accountGroupJoinedStateJoined accountGroupJoinedState = iota + 1
accountGroupJoinedStateLeft
)
type accountGroup struct {
state accountGroupJoinedState
group *protocoltypes.Group
}
type AccountContact struct {
state protocoltypes.ContactState
contact *protocoltypes.ShareableContact
}
func (m *metadataStoreIndex) handleGroupJoined(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountGroupJoined)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
_, ok = m.groups[string(evt.Group.PublicKey)]
if ok {
return nil
}
m.groups[string(evt.Group.PublicKey)] = &accountGroup{
group: evt.Group,
state: accountGroupJoinedStateJoined,
}
return nil
}
func (m *metadataStoreIndex) handleGroupLeft(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountGroupLeft)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
_, ok = m.groups[string(evt.GroupPk)]
if ok {
return nil
}
m.groups[string(evt.GroupPk)] = &accountGroup{
state: accountGroupJoinedStateLeft,
}
return nil
}
func (m *metadataStoreIndex) handleContactRequestDisabled(event proto.Message) error {
if m.contactRequestEnabled != nil {
return nil
}
_, ok := event.(*protocoltypes.AccountContactRequestDisabled)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
f := false
m.contactRequestEnabled = &f
return nil
}
func (m *metadataStoreIndex) handleContactRequestEnabled(event proto.Message) error {
if m.contactRequestEnabled != nil {
return nil
}
_, ok := event.(*protocoltypes.AccountContactRequestEnabled)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
t := true
m.contactRequestEnabled = &t
return nil
}
func (m *metadataStoreIndex) handleContactRequestReferenceReset(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestReferenceReset)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if m.contactRequestSeed != nil {
return nil
}
m.contactRequestSeed = evt.PublicRendezvousSeed
return nil
}
func (m *metadataStoreIndex) registerContactFromGroupPK(ac *AccountContact) error {
if m.group.GroupType != protocoltypes.GroupType_GroupTypeAccount {
return errcode.ErrCode_ErrGroupInvalidType
}
contactPK, err := crypto.UnmarshalEd25519PublicKey(ac.contact.Pk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
group, err := m.secretStore.GetGroupForContact(contactPK)
if err != nil {
return errcode.ErrCode_ErrOrbitDBOpen.Wrap(err)
}
m.contactsFromGroupPK[string(group.PublicKey)] = ac
return nil
}
func (m *metadataStoreIndex) handleContactRequestOutgoingEnqueued(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestOutgoingEnqueued)
if ko := !ok || evt.Contact == nil; ko {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.Contact.Pk)]; ok {
if m.contacts[string(evt.Contact.Pk)].contact.Metadata == nil {
m.contacts[string(evt.Contact.Pk)].contact.Metadata = evt.Contact.Metadata
}
if m.contacts[string(evt.Contact.Pk)].contact.PublicRendezvousSeed == nil {
m.contacts[string(evt.Contact.Pk)].contact.PublicRendezvousSeed = evt.Contact.PublicRendezvousSeed
}
return nil
}
if data, ok := m.contactRequestMetadata[string(evt.Contact.Pk)]; !ok || len(data) == 0 {
m.contactRequestMetadata[string(evt.Contact.Pk)] = evt.OwnMetadata
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateToRequest,
contact: &protocoltypes.ShareableContact{
Pk: evt.Contact.Pk,
Metadata: evt.Contact.Metadata,
PublicRendezvousSeed: evt.Contact.PublicRendezvousSeed,
},
}
m.contacts[string(evt.Contact.Pk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactRequestOutgoingSent(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestOutgoingSent)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateAdded,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactRequestIncomingReceived(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestIncomingReceived)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
if m.contacts[string(evt.ContactPk)].contact.Metadata == nil {
m.contacts[string(evt.ContactPk)].contact.Metadata = evt.ContactMetadata
}
if m.contacts[string(evt.ContactPk)].contact.PublicRendezvousSeed == nil {
m.contacts[string(evt.ContactPk)].contact.PublicRendezvousSeed = evt.ContactRendezvousSeed
}
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateReceived,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
Metadata: evt.ContactMetadata,
PublicRendezvousSeed: evt.ContactRendezvousSeed,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactRequestIncomingDiscarded(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestIncomingDiscarded)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateDiscarded,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactRequestIncomingAccepted(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactRequestIncomingAccepted)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateAdded,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactBlocked(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactBlocked)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateBlocked,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactUnblocked(event proto.Message) error {
evt, ok := event.(*protocoltypes.AccountContactUnblocked)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
if _, ok := m.contacts[string(evt.ContactPk)]; ok {
return nil
}
ac := &AccountContact{
state: protocoltypes.ContactState_ContactStateRemoved,
contact: &protocoltypes.ShareableContact{
Pk: evt.ContactPk,
},
}
m.contacts[string(evt.ContactPk)] = ac
err := m.registerContactFromGroupPK(ac)
return err
}
func (m *metadataStoreIndex) handleContactAliasKeyAdded(event proto.Message) error {
evt, ok := event.(*protocoltypes.ContactAliasKeyAdded)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
m.eventsContactAddAliasKey = append(m.eventsContactAddAliasKey, evt)
return nil
}
func (m *metadataStoreIndex) handleMultiMemberInitialMember(event proto.Message) error {
e, ok := event.(*protocoltypes.MultiMemberGroupInitialMemberAnnounced)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
pk, err := crypto.UnmarshalEd25519PublicKey(e.MemberPk)
if err != nil {
return errcode.ErrCode_ErrDeserialization.Wrap(err)
}
if _, ok := m.admins[pk]; ok {
return errcode.ErrCode_ErrInternal
}
m.admins[pk] = struct{}{}
return nil
}
//nolint:revive
func (m *metadataStoreIndex) handleMultiMemberGrantAdminRole(event proto.Message) error {
// TODO:
return nil
}
func (m *metadataStoreIndex) handleGroupMetadataPayloadSent(_ proto.Message) error {
return nil
}
func (m *metadataStoreIndex) handleAccountVerifiedCredentialRegistered(event proto.Message) error {
e, ok := event.(*protocoltypes.AccountVerifiedCredentialRegistered)
if !ok {
return errcode.ErrCode_ErrInvalidInput
}
m.verifiedCredentials = append(m.verifiedCredentials, e)
return nil
}
func (m *metadataStoreIndex) listAdmins() []crypto.PubKey {
m.lock.RLock()
defer m.lock.RUnlock()
admins := make([]crypto.PubKey, len(m.admins))
i := 0
for admin := range m.admins {
admins[i] = admin
i++
}
return admins
}
func (m *metadataStoreIndex) listOtherMembersDevices() []crypto.PubKey {
m.lock.RLock()
defer m.lock.RUnlock()
if m.ownMemberDevice == nil || m.ownMemberDevice.Member() == nil {
return nil
}
ownMemberPK, err := m.ownMemberDevice.Member().Raw()
if err != nil {
m.logger.Warn("unable to serialize member pubkey", zap.Error(err))
return nil
}
devices := []crypto.PubKey(nil)
for pk, devicesForMember := range m.members {
if string(ownMemberPK) == pk {
continue
}
for _, md := range devicesForMember {
devices = append(devices, md.Device())
}
}
return devices
}
func (m *metadataStoreIndex) contactRequestsEnabled() bool {
m.lock.RLock()
defer m.lock.RUnlock()
return m.contactRequestEnabled != nil && *m.contactRequestEnabled
}
func (m *metadataStoreIndex) contactRequestsSeed() []byte {
m.lock.RLock()
defer m.lock.RUnlock()
return m.contactRequestSeed
}
func (m *metadataStoreIndex) getContact(pk crypto.PubKey) (*AccountContact, error) {
m.lock.RLock()
defer m.lock.RUnlock()
bytes, err := pk.Raw()
if err != nil {
return nil, errcode.ErrCode_ErrSerialization.Wrap(err)
}
contact, ok := m.contacts[string(bytes)]
if !ok {
return nil, errcode.ErrCode_ErrMissingMapKey.Wrap(err)
}
return contact, nil
}
func (m *metadataStoreIndex) postHandlerSentAliases() error {
for _, evt := range m.eventsContactAddAliasKey {
memberPublicKey, err := m.unsafeGetMemberByDevice(evt.DevicePk)
if err != nil {
return fmt.Errorf("couldn't get member for device")
}
if memberPublicKey.Equals(m.ownMemberDevice.Member()) {
m.ownAliasKeySent = true
continue
}
if l := len(evt.AliasPk); l != cryptoutil.KeySize {
return errcode.ErrCode_ErrInvalidInput.Wrap(fmt.Errorf("invalid alias key size, expected %d, got %d", cryptoutil.KeySize, l))
}
m.otherAliasKey = evt.AliasPk
}
m.eventsContactAddAliasKey = nil
return nil
}
// nolint:staticcheck,revive
// newMetadataIndex returns a new index to manage the list of the group members
func newMetadataIndex(ctx context.Context, g *protocoltypes.Group, md secretstore.MemberDevice, secretStore secretstore.SecretStore) iface.IndexConstructor {
return func(publicKey []byte) iface.StoreIndex {
m := &metadataStoreIndex{
members: map[string][]secretstore.MemberDevice{},
devices: map[string]secretstore.MemberDevice{},
admins: map[crypto.PubKey]struct{}{},
sentSecrets: map[string]struct{}{},
handledEvents: map[string]struct{}{},
contacts: map[string]*AccountContact{},
contactsFromGroupPK: map[string]*AccountContact{},
groups: map[string]*accountGroup{},
contactRequestMetadata: map[string][]byte{},
group: g,
ownMemberDevice: md,
secretStore: secretStore,
ctx: ctx,
logger: zap.NewNop(),
}
m.eventHandlers = map[protocoltypes.EventType][]func(event proto.Message) error{
protocoltypes.EventType_EventTypeAccountContactBlocked: {m.handleContactBlocked},
protocoltypes.EventType_EventTypeAccountContactRequestDisabled: {m.handleContactRequestDisabled},
protocoltypes.EventType_EventTypeAccountContactRequestEnabled: {m.handleContactRequestEnabled},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingAccepted: {m.handleContactRequestIncomingAccepted},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingDiscarded: {m.handleContactRequestIncomingDiscarded},
protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived: {m.handleContactRequestIncomingReceived},
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued: {m.handleContactRequestOutgoingEnqueued},
protocoltypes.EventType_EventTypeAccountContactRequestOutgoingSent: {m.handleContactRequestOutgoingSent},
protocoltypes.EventType_EventTypeAccountContactRequestReferenceReset: {m.handleContactRequestReferenceReset},
protocoltypes.EventType_EventTypeAccountContactUnblocked: {m.handleContactUnblocked},
protocoltypes.EventType_EventTypeAccountGroupJoined: {m.handleGroupJoined},
protocoltypes.EventType_EventTypeAccountGroupLeft: {m.handleGroupLeft},
protocoltypes.EventType_EventTypeContactAliasKeyAdded: {m.handleContactAliasKeyAdded},
protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded: {m.handleGroupDeviceChainKeyAdded},
protocoltypes.EventType_EventTypeGroupMemberDeviceAdded: {m.handleGroupMemberDeviceAdded},
protocoltypes.EventType_EventTypeMultiMemberGroupAdminRoleGranted: {m.handleMultiMemberGrantAdminRole},
protocoltypes.EventType_EventTypeMultiMemberGroupInitialMemberAnnounced: {m.handleMultiMemberInitialMember},
protocoltypes.EventType_EventTypeGroupMetadataPayloadSent: {m.handleGroupMetadataPayloadSent},
protocoltypes.EventType_EventTypeAccountVerifiedCredentialRegistered: {m.handleAccountVerifiedCredentialRegistered},
}
m.postIndexActions = []func() error{
m.postHandlerSentAliases,
}
return m
}
}
var _ iface.StoreIndex = &metadataStoreIndex{}
================================================
FILE: store_metadata_test.go
================================================
package weshnet
import (
"bytes"
"context"
crand "crypto/rand"
"fmt"
mrand "math/rand"
"testing"
"time"
datastore "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
"github.com/libp2p/go-libp2p/core/crypto"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/testutil"
)
func TestMetadataStoreSecret_Basic(t *testing.T) {
t.Skip("skipping as we don't care about this code now")
// TODO: handle more cases (more members, more devices...)
memberCount := 2
deviceCount := 1
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peers, groupSK, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/secrets_test", memberCount, deviceCount)
defer cleanup()
secretsAdded := make(chan struct{})
msA := peers[0].GC.MetadataStore()
msB := peers[1].GC.MetadataStore()
go waitForBertyEventType(ctx, t, msA, protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded, 2, secretsAdded)
go waitForBertyEventType(ctx, t, msB, protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded, 2, secretsAdded)
inviteAllPeersToGroup(ctx, t, peers, groupSK)
devPkA := peers[0].GC.DevicePubKey()
devPkB := peers[1].GC.DevicePubKey()
<-secretsAdded
<-secretsAdded
_ = devPkA
_ = devPkB
}
func TestMetadataStoreMember(t *testing.T) {
t.Skip("skipping as we don't care about this code now")
// If seed is not set, it will default to 1, explicitly setting it and displaying it if the test fails
seed := time.Now().UTC().UnixNano()
mrand.Seed(seed)
for _, tc := range []struct {
memberCount int
deviceCount int
slow bool
}{
{memberCount: 1, deviceCount: 1, slow: false},
{memberCount: 1, deviceCount: 3, slow: false},
{memberCount: 3, deviceCount: 1, slow: false},
// TODO: fix pubsub issues
// {memberCount: 3, deviceCount: 3, slow: false},
} {
t.Run(fmt.Sprintf("testMemberStore seed: %d, memberCount: %d, deviceCount: %d", seed, tc.memberCount, tc.deviceCount), func(t *testing.T) {
if tc.slow {
// TODO: re-enable this test
t.Skip()
testutil.FilterSpeed(t, testutil.Slow)
}
testMemberStore(t, tc.memberCount, tc.deviceCount)
})
}
}
func testMemberStore(t *testing.T, memberCount, deviceCount int) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Creates N members with M devices each within the same group
peers, groupSK, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/member_test", memberCount, deviceCount)
defer cleanup()
done := make(chan struct{})
for _, peer := range peers {
go waitForBertyEventType(ctx, t, peer.GC.MetadataStore(), protocoltypes.EventType_EventTypeGroupMemberDeviceAdded, len(peers), done)
}
for i, peer := range peers {
if _, err := peer.GC.MetadataStore().AddDeviceToGroup(ctx); err != nil {
t.Fatal(err)
}
if i == 0 {
if _, err := peer.GC.MetadataStore().ClaimGroupOwnership(ctx, groupSK); err != nil {
t.Fatal(err)
}
}
}
// Wait for all events to be received in all peers's member log (or timeout)
for i := range peers {
<-done
t.Logf("got all members for member %d", i)
}
// Test if everything was replicated and indexed correctly
for i, peer := range peers {
ms := peer.GC.MetadataStore()
// Test list functions (only length, checking all entries would be too long)
memberList := ms.ListMembers()
if len(memberList) != memberCount {
t.Fatalf("%d member(s) missing from peer %d member list (%d/%d)", memberCount-len(memberList), i, len(memberList), memberCount)
}
deviceList := ms.ListDevices()
if len(deviceList) != memberCount*deviceCount {
t.Fatalf("%d device(s) missing from peer %d device list (%d/%d)", memberCount*deviceCount-len(deviceList), i, len(deviceList), memberCount*deviceCount)
}
// Test entries getter functions
for j, peerDev := range peers {
if _, err := ms.GetDevicesForMember(peerDev.GC.MemberPubKey()); err != nil {
t.Fatalf("member of peer %d is missing from peer %d member map: %v", j, i, err)
}
if _, err := ms.GetMemberByDevice(peerDev.GC.MemberPubKey()); err != nil {
t.Fatalf("device of peer %d is missing from peer %d device map: %v", j, i, err)
}
}
}
}
func ipfsAPIUsingMockNet(ctx context.Context, t *testing.T) ipfsutil.ExtendedCoreAPI {
ipfsopts := &ipfsutil.TestingAPIOpts{
Logger: zap.NewNop(),
Mocknet: mocknet.New(),
Datastore: ds_sync.MutexWrap(datastore.NewMapDatastore()),
}
node := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsopts)
return node.API()
}
func TestMetadataRendezvousPointLifecycle(t *testing.T) {
testutil.FilterSpeed(t, testutil.Fast)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Creates N members with M devices each within the same group
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/member_test", 1, 1)
defer cleanup()
api := ipfsAPIUsingMockNet(ctx, t)
ownCG, err := peers[0].DB.openAccountGroup(ctx, nil, api)
assert.NoError(t, err)
meta := ownCG.MetadataStore()
_, accountMemberDevice, err := peers[0].SecretStore.GetGroupForAccount()
assert.NoError(t, err)
accPK, err := accountMemberDevice.Member().Raw()
assert.NoError(t, err)
enabled, shareableContact := meta.GetIncomingContactRequestsStatus()
assert.False(t, enabled)
assert.NotNil(t, shareableContact)
// reset rdv seed
_, err = meta.ContactRequestReferenceReset(ctx)
assert.NoError(t, err)
// get set shareable contact, not enabled
enabled, shareableContact = meta.GetIncomingContactRequestsStatus()
assert.False(t, enabled)
assert.NotNil(t, shareableContact)
assert.Equal(t, accPK, shareableContact.Pk)
assert.Equal(t, 32, len(shareableContact.PublicRendezvousSeed))
_, err = meta.ContactRequestEnable(ctx)
assert.NoError(t, err)
enabled, shareableContact = meta.GetIncomingContactRequestsStatus()
assert.True(t, enabled)
assert.NotNil(t, shareableContact)
// Force reindex to check both enabled and seed
err = meta.Load(ctx, -1)
assert.NoError(t, err)
enabled, shareableContact = meta.GetIncomingContactRequestsStatus()
assert.True(t, enabled)
assert.NotNil(t, shareableContact)
assert.Equal(t, accPK, shareableContact.Pk)
assert.Equal(t, 32, len(shareableContact.PublicRendezvousSeed))
// Disable incoming contact requests
_, err = meta.ContactRequestDisable(ctx)
assert.NoError(t, err)
enabled, shareableContact = meta.GetIncomingContactRequestsStatus()
assert.False(t, enabled)
assert.NotNil(t, shareableContact)
assert.Equal(t, accPK, shareableContact.Pk)
assert.Equal(t, 32, len(shareableContact.PublicRendezvousSeed))
}
func TestMetadataContactLifecycle(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peersCount := 4
// Creates N members with M devices each within the same group
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/member_test", peersCount, 1)
defer cleanup()
var (
err error
meta = make([]*MetadataStore, peersCount)
ownCG = make([]*GroupContext, peersCount)
contacts = make([]*protocoltypes.ShareableContact, peersCount)
)
api := ipfsAPIUsingMockNet(ctx, t)
for i, p := range peers {
ownCG[i], err = p.DB.openAccountGroup(ctx, nil, api)
require.NoError(t, err)
meta[i] = ownCG[i].MetadataStore()
_, err = meta[i].ContactRequestReferenceReset(ctx)
require.NoError(t, err)
_, contacts[i] = meta[i].GetIncomingContactRequestsStatus()
require.NotNil(t, contacts[i])
contacts[i].Metadata = []byte(fmt.Sprintf("own meta %d", i))
}
_, randPK, err := crypto.GenerateEd25519Key(crand.Reader)
require.NoError(t, err)
// no contacts
require.Equal(t, len(meta[0].Index().(*metadataStoreIndex).contacts), 0)
_, err = meta[0].ContactRequestReferenceReset(ctx)
require.NoError(t, err)
contact2PK := contacts[1].Pk
contact2RDVS := contacts[1].PublicRendezvousSeed
// Enqueuing outgoing
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[0], contacts[0].Metadata)
require.Error(t, err)
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.NoError(t, err)
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.NoError(t, err)
require.Equal(t, len(meta[0].Index().(*metadataStoreIndex).contacts), 1)
require.NotNil(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)])
require.Equal(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].state, protocoltypes.ContactState_ContactStateToRequest)
require.Equal(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].contact.Pk, contact2PK)
require.Equal(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].contact.PublicRendezvousSeed, contact2RDVS)
require.Equal(t, contacts[0].Metadata, meta[0].Index().(*metadataStoreIndex).contactRequestMetadata[string(contact2PK)])
contacts[1].PublicRendezvousSeed = nil
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.Error(t, err)
contacts[1].PublicRendezvousSeed = []byte("too_short")
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.Error(t, err)
contacts[1].Pk = nil
contacts[1].PublicRendezvousSeed = contact2RDVS
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.Error(t, err)
contacts[1].Pk = []byte("invalid")
_, err = meta[0].ContactRequestOutgoingEnqueue(ctx, contacts[1], contacts[0].Metadata)
require.Error(t, err)
require.Equal(t, 1, len(meta[0].Index().(*metadataStoreIndex).contacts))
require.NotNil(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)])
require.Equal(t, protocoltypes.ContactState_ContactStateToRequest, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].state)
require.Equal(t, contact2PK, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].contact.Pk)
require.Equal(t, contact2RDVS, meta[0].Index().(*metadataStoreIndex).contacts[string(contact2PK)].contact.PublicRendezvousSeed)
require.Equal(t, contacts[0].Metadata, meta[0].Index().(*metadataStoreIndex).contactRequestMetadata[string(contact2PK)])
contacts[1].Pk = contact2PK
contacts[1].PublicRendezvousSeed = contact2RDVS
meta[0].Index().(*metadataStoreIndex).contactRequestMetadata[string(contacts[1].Pk)] = contacts[0].Metadata
// Marking as sent
_, err = meta[0].ContactRequestOutgoingSent(ctx, nil)
require.Error(t, err)
_, err = meta[0].ContactRequestOutgoingSent(ctx, randPK)
require.Error(t, err)
_, err = meta[0].ContactRequestOutgoingSent(ctx, ownCG[0].MemberPubKey())
require.Error(t, err)
meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)].state = protocoltypes.ContactState_ContactStateAdded
_, err = meta[0].ContactRequestOutgoingSent(ctx, ownCG[1].MemberPubKey())
require.Error(t, err)
meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)].state = protocoltypes.ContactState_ContactStateToRequest
_, err = meta[0].ContactRequestOutgoingSent(ctx, ownCG[1].MemberPubKey())
require.NoError(t, err)
require.Equal(t, len(meta[0].Index().(*metadataStoreIndex).contacts), 1)
require.NotNil(t, meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)])
require.Equal(t, protocoltypes.ContactState_ContactStateAdded, meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)].state)
require.Equal(t, contacts[1].Pk, meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)].contact.Pk)
require.Equal(t, contacts[1].PublicRendezvousSeed, meta[0].Index().(*metadataStoreIndex).contacts[string(contacts[1].Pk)].contact.PublicRendezvousSeed)
// Marking as received
_, err = meta[1].ContactRequestIncomingReceived(ctx, &protocoltypes.ShareableContact{})
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, &protocoltypes.ShareableContact{Pk: []byte("invalid"), PublicRendezvousSeed: []byte("invalid")})
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, &protocoltypes.ShareableContact{Pk: []byte("invalid"), PublicRendezvousSeed: contacts[0].PublicRendezvousSeed})
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, &protocoltypes.ShareableContact{Pk: contacts[0].Pk, PublicRendezvousSeed: []byte("invalid")})
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[1])
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[0])
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 1)
require.NotNil(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)])
require.Equal(t, protocoltypes.ContactState_ContactStateReceived, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state)
require.Equal(t, contacts[0].Pk, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].contact.Pk)
require.Equal(t, contacts[0].PublicRendezvousSeed, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].contact.PublicRendezvousSeed)
require.Equal(t, contacts[0].Metadata, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].contact.Metadata)
// Accepting received
_, err = meta[1].ContactRequestIncomingAccept(ctx, nil)
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingAccept(ctx, randPK)
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingAccept(ctx, ownCG[1].MemberPubKey())
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingAccept(ctx, ownCG[0].MemberPubKey())
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 1)
require.NotNil(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)])
require.Equal(t, protocoltypes.ContactState_ContactStateAdded, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state)
require.Equal(t, contacts[0].Pk, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].contact.Pk)
require.Equal(t, contacts[0].PublicRendezvousSeed, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].contact.PublicRendezvousSeed)
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[0])
require.Error(t, err)
// Auto accept when receiving an invitation from a contact you were waiting to send an invitation to
_, err = meta[1].ContactRequestOutgoingEnqueue(ctx, contacts[3], contacts[1].Metadata)
require.NoError(t, err)
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[3])
require.NoError(t, err)
require.Equal(t, 2, len(meta[1].Index().(*metadataStoreIndex).contacts))
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[3].Pk)].state, protocoltypes.ContactState_ContactStateAdded)
// Refuse contact
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[2])
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 3)
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state, protocoltypes.ContactState_ContactStateReceived)
_, err = meta[1].ContactRequestIncomingDiscard(ctx, nil)
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingDiscard(ctx, randPK)
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingDiscard(ctx, ownCG[0].MemberPubKey())
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingDiscard(ctx, ownCG[1].MemberPubKey())
require.Error(t, err)
_, err = meta[1].ContactRequestIncomingDiscard(ctx, ownCG[2].MemberPubKey())
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 3)
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state, protocoltypes.ContactState_ContactStateDiscarded)
// Allow receiving requests again after discarded
_, err = meta[1].ContactRequestIncomingReceived(ctx, contacts[2])
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 3)
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state, protocoltypes.ContactState_ContactStateReceived)
_, err = meta[1].ContactRequestOutgoingEnqueue(ctx, contacts[2], contacts[1].Metadata)
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 3)
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state, protocoltypes.ContactState_ContactStateAdded)
// Auto accept discarded requests
meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state = protocoltypes.ContactState_ContactStateDiscarded
_, err = meta[1].ContactRequestOutgoingEnqueue(ctx, contacts[2], contacts[1].Metadata)
require.NoError(t, err)
require.Equal(t, len(meta[1].Index().(*metadataStoreIndex).contacts), 3)
require.Equal(t, meta[1].Index().(*metadataStoreIndex).contacts[string(contacts[2].Pk)].state, protocoltypes.ContactState_ContactStateAdded)
// Block contact
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 0)
_, err = meta[2].ContactBlock(ctx, ownCG[2].MemberPubKey())
require.Error(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 0)
_, err = meta[2].ContactBlock(ctx, ownCG[0].MemberPubKey())
require.NoError(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 1)
require.Equal(t, meta[2].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state, protocoltypes.ContactState_ContactStateBlocked)
_, err = meta[2].ContactBlock(ctx, ownCG[0].MemberPubKey())
require.Error(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 1)
require.Equal(t, meta[2].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state, protocoltypes.ContactState_ContactStateBlocked)
// Unblock contact
_, err = meta[2].ContactUnblock(ctx, ownCG[1].MemberPubKey())
require.Error(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 1)
require.Equal(t, meta[2].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state, protocoltypes.ContactState_ContactStateBlocked)
_, err = meta[2].ContactUnblock(ctx, ownCG[0].MemberPubKey())
require.NoError(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 1)
require.Equal(t, meta[2].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state, protocoltypes.ContactState_ContactStateRemoved)
_, err = meta[2].ContactUnblock(ctx, ownCG[0].MemberPubKey())
require.Error(t, err)
require.Equal(t, len(meta[2].Index().(*metadataStoreIndex).contacts), 1)
require.Equal(t, meta[2].Index().(*metadataStoreIndex).contacts[string(contacts[0].Pk)].state, protocoltypes.ContactState_ContactStateRemoved)
}
func TestMetadataAliasLifecycle(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peersCount := 4
// Creates N members with M devices each within the same group
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/member_test", peersCount, 1)
defer cleanup()
// disclose
_, err := peers[0].GC.MetadataStore().ContactSendAliasKey(ctx)
require.Error(t, err)
g, err := peers[0].SecretStore.GetGroupForContact(peers[1].GC.MemberPubKey())
require.NoError(t, err)
cg0, err := peers[0].DB.OpenGroup(ctx, g, nil)
require.NoError(t, err)
defer cg0.Close()
require.False(t, cg0.MetadataStore().Index().(*metadataStoreIndex).ownAliasKeySent)
_, err = cg0.MetadataStore().AddDeviceToGroup(ctx)
require.NoError(t, err)
_, err = cg0.MetadataStore().ContactSendAliasKey(ctx)
require.NoError(t, err)
require.Empty(t, cg0.MetadataStore().Index().(*metadataStoreIndex).otherAliasKey)
require.True(t, cg0.MetadataStore().Index().(*metadataStoreIndex).ownAliasKeySent)
g, err = peers[1].SecretStore.GetGroupForContact(peers[0].GC.MemberPubKey())
require.NoError(t, err)
cg1, err := peers[1].DB.OpenGroup(ctx, g, nil)
require.NoError(t, err)
defer cg1.Close()
_ = cg1
// TODO: receive key on cg1 from cg0
// TODO: match received alias proof with previously disclosed key
}
func TestMetadataGroupsLifecycle(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Creates N members with M devices each within the same group
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/member_test", 1, 1)
defer cleanup()
api := ipfsAPIUsingMockNet(ctx, t)
ownCG, err := peers[0].DB.openAccountGroup(ctx, nil, api)
assert.NoError(t, err)
g1, _, err := NewGroupMultiMember()
require.NoError(t, err)
g2, _, err := NewGroupMultiMember()
require.NoError(t, err)
g3, _, err := NewGroupMultiMember()
require.NoError(t, err)
g1PK, err := g1.GetPubKey()
require.NoError(t, err)
g3PK, err := g3.GetPubKey()
require.NoError(t, err)
_, err = ownCG.MetadataStore().GroupJoin(ctx, g1)
require.NoError(t, err)
groups := ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 1)
require.Equal(t, groups[0].PublicKey, g1.PublicKey)
require.Equal(t, groups[0].Secret, g1.Secret)
require.Equal(t, groups[0].SecretSig, g1.SecretSig)
require.Equal(t, groups[0].GroupType, g1.GroupType)
_, err = ownCG.MetadataStore().GroupJoin(ctx, g2)
require.NoError(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 2)
first, second := 0, 1
if bytes.Compare(groups[1].PublicKey, g1.PublicKey) == 0 {
first, second = 1, 0
}
require.Equal(t, groups[first].PublicKey, g1.PublicKey)
require.Equal(t, groups[first].Secret, g1.Secret)
require.Equal(t, groups[first].SecretSig, g1.SecretSig)
require.Equal(t, groups[first].GroupType, g1.GroupType)
require.Equal(t, groups[second].PublicKey, g2.PublicKey)
require.Equal(t, groups[second].Secret, g2.Secret)
require.Equal(t, groups[second].SecretSig, g2.SecretSig)
require.Equal(t, groups[second].GroupType, g2.GroupType)
_, err = ownCG.MetadataStore().GroupJoin(ctx, &protocoltypes.Group{
PublicKey: []byte("invalid_pk"),
Secret: g3.Secret,
SecretSig: g3.SecretSig,
GroupType: protocoltypes.GroupType_GroupTypeMultiMember,
})
require.Error(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 2)
_, err = ownCG.MetadataStore().GroupJoin(ctx, &protocoltypes.Group{
PublicKey: g3.PublicKey,
Secret: nil,
SecretSig: g3.SecretSig,
GroupType: protocoltypes.GroupType_GroupTypeMultiMember,
})
require.Error(t, err)
_, err = ownCG.MetadataStore().GroupJoin(ctx, &protocoltypes.Group{
PublicKey: g3.PublicKey,
Secret: g3.Secret,
SecretSig: []byte("invalid_sig"),
GroupType: protocoltypes.GroupType_GroupTypeMultiMember,
})
require.Error(t, err)
_, err = ownCG.MetadataStore().GroupJoin(ctx, g1)
require.Error(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 2)
_, err = ownCG.MetadataStore().GroupLeave(ctx, nil)
require.Error(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 2)
_, err = ownCG.MetadataStore().GroupLeave(ctx, g1PK)
require.NoError(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 1)
_, err = ownCG.MetadataStore().GroupLeave(ctx, g1PK)
require.Error(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 1)
_, err = ownCG.MetadataStore().GroupLeave(ctx, g3PK)
require.Error(t, err)
groups = ownCG.MetadataStore().ListMultiMemberGroups()
require.Len(t, groups, 1)
require.Equal(t, groups[0].PublicKey, g2.PublicKey)
require.Equal(t, groups[0].Secret, g2.Secret)
require.Equal(t, groups[0].SecretSig, g2.SecretSig)
require.Equal(t, groups[0].GroupType, g2.GroupType)
}
func TestFlappyMultiDevices_Basic(t *testing.T) {
testutil.FilterStabilityAndSpeed(t, testutil.Flappy, testutil.Slow)
memberCount := 2
deviceCount := 3
totalDevices := memberCount * deviceCount
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
peers, _, cleanup := CreatePeersWithGroupTest(ctx, t, "/tmp/multidevices_test", memberCount, deviceCount)
defer cleanup()
api := ipfsAPIUsingMockNet(ctx, t)
// make peer index
pi := [][]int{}
for i := 0; i < memberCount; i++ {
pi = append(pi, []int{})
for j := 0; j < deviceCount; j++ {
pi[i] = append(pi[i], i*deviceCount+j)
}
}
var (
err error
meta = make([]*MetadataStore, totalDevices)
ownCG = make([]*GroupContext, totalDevices)
contacts = make([]*protocoltypes.ShareableContact, totalDevices)
listContacts map[string]*AccountContact
groups []*protocoltypes.Group
)
// Activate account group + contact request
for i, p := range peers {
// except for the latest peer devices
if (i % deviceCount) == (deviceCount - 1) {
continue
}
ownCG[i], err = p.DB.openAccountGroup(ctx, nil, api)
require.NoError(t, err)
meta[i] = ownCG[i].MetadataStore()
_, err = meta[i].ContactRequestEnable(ctx)
assert.NoError(t, err)
_, err = meta[i].ContactRequestReferenceReset(ctx)
require.NoError(t, err)
_, contacts[i] = meta[i].GetIncomingContactRequestsStatus()
require.NotNil(t, contacts[i])
contacts[i].Metadata = []byte(fmt.Sprintf("own meta %d", i))
}
syncChan := make(chan struct{})
go waitForBertyEventType(ctx, t, meta[pi[0][0]], protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued, 1, syncChan)
go waitForBertyEventType(ctx, t, meta[pi[0][1]], protocoltypes.EventType_EventTypeAccountContactRequestOutgoingEnqueued, 1, syncChan)
go waitForBertyEventType(ctx, t, meta[pi[1][0]], protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived, 1, syncChan)
go waitForBertyEventType(ctx, t, meta[pi[1][1]], protocoltypes.EventType_EventTypeAccountContactRequestIncomingReceived, 1, syncChan)
// Add peers to contact
// Enqueuing outgoing
_, err = meta[pi[0][0]].ContactRequestOutgoingEnqueue(ctx, contacts[pi[1][0]], contacts[pi[0][0]].Metadata)
require.NoError(t, err)
// Marking as sent
_, err = meta[pi[0][0]].ContactRequestOutgoingSent(ctx, ownCG[pi[1][0]].MemberPubKey())
require.NoError(t, err)
// Marking as received
_, err = meta[pi[1][0]].ContactRequestIncomingReceived(ctx, contacts[pi[0][0]])
require.NoError(t, err)
// Accepting received
_, err = meta[pi[1][0]].ContactRequestIncomingAccept(ctx, ownCG[pi[0][0]].MemberPubKey())
require.NoError(t, err)
for i := 0; i < 4; i++ {
select {
case <-syncChan:
case <-ctx.Done():
require.NoError(t, ctx.Err())
}
}
// test if contact is established
listContacts = meta[pi[0][0]].ListContacts()
require.Equal(t, 1, len(listContacts))
require.NotNil(t, listContacts[string(contacts[pi[1][0]].Pk)])
listContacts = meta[pi[1][0]].ListContacts()
require.Equal(t, 1, len(listContacts))
require.NotNil(t, listContacts[string(contacts[pi[0][0]].Pk)])
// test if 2nd devices have also the contact
listContacts = meta[pi[0][1]].ListContacts()
require.Equal(t, 1, len(listContacts))
require.NotNil(t, listContacts[string(contacts[pi[1][0]].Pk)])
listContacts = meta[pi[1][1]].ListContacts()
require.Equal(t, 1, len(listContacts))
require.NotNil(t, listContacts[string(contacts[pi[0][0]].Pk)])
// Activate group for 2nd peer's 1st device
groups = meta[pi[1][0]].ListMultiMemberGroups()
require.Len(t, groups, 0)
go waitForBertyEventType(ctx, t, meta[pi[1][0]], protocoltypes.EventType_EventTypeAccountGroupJoined, 1, syncChan)
go waitForBertyEventType(ctx, t, meta[pi[1][1]], protocoltypes.EventType_EventTypeAccountGroupJoined, 1, syncChan)
_, err = meta[pi[1][0]].GroupJoin(ctx, peers[pi[1][0]].GC.group)
require.NoError(t, err)
for i := 0; i < 2; i++ {
select {
case <-syncChan:
case <-ctx.Done():
require.NoError(t, ctx.Err())
}
}
groups = meta[pi[1][0]].ListMultiMemberGroups()
require.Len(t, groups, 1)
// Test if other devices have the group too
groups = meta[pi[1][1]].ListMultiMemberGroups()
require.Len(t, groups, 1)
// Check if a account group activate after the contact request is synchronized
// Activate the 2nd peer's latest device account group
ownCG[pi[1][2]], err = peers[pi[1][2]].DB.openAccountGroup(ctx, nil, api)
require.NoError(t, err)
meta[pi[1][2]] = ownCG[pi[1][2]].MetadataStore()
// wait for replication db
<-time.After(time.Second * 2)
listContacts = meta[pi[1][2]].ListContacts()
require.Equal(t, 1, len(listContacts))
require.NotNil(t, listContacts[string(contacts[0].Pk)])
// Test for group
groups = meta[pi[1][2]].ListMultiMemberGroups()
require.Len(t, groups, 1)
}
================================================
FILE: store_options.go
================================================
package weshnet
import (
"context"
"encoding/hex"
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"berty.tech/go-ipfs-log/identityprovider"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/accesscontroller"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func DefaultOrbitDBOptions(g *protocoltypes.Group, options *orbitdb.CreateDBOptions, keystore *BertySignedKeyStore, storeType string, groupOpenMode GroupOpenMode) (*orbitdb.CreateDBOptions, error) {
var err error
if options == nil {
options = &orbitdb.CreateDBOptions{}
}
options = &orbitdb.CreateDBOptions{
Directory: options.Directory,
Overwrite: options.Overwrite,
LocalOnly: options.LocalOnly,
StoreType: options.StoreType,
AccessControllerAddress: options.AccessControllerAddress,
AccessController: options.AccessController,
Replicate: options.Replicate,
Cache: options.Cache,
EventBus: options.EventBus,
Logger: options.Logger,
}
t := true
options.Create = &t
if options.EventBus == nil {
options.EventBus = eventbus.NewBus()
}
if options.AccessController == nil {
options.AccessController, err = defaultACForGroup(g, storeType)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
}
options.Keystore = keystore
if groupOpenMode != GroupOpenModeReplicate {
options.Identity, err = defaultIdentityForGroup(context.TODO(), g, keystore)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
} else {
options.Identity, err = readIdentityForGroup(g, keystore)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
}
return options, nil
}
func defaultACForGroup(g *protocoltypes.Group, storeType string) (accesscontroller.ManifestParams, error) {
groupID := g.GroupIDAsString()
sigPK, err := g.GetSigningPubKey()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
signingKeyBytes, err := sigPK.Raw()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
access := map[string][]string{
"write": {hex.EncodeToString(signingKeyBytes)},
identityGroupIDKey: {groupID},
storeTypeKey: {storeType},
}
address, err := simpleAccessControllerCID(access)
if err != nil {
return nil, err
}
param := &accesscontroller.CreateAccessControllerOptions{
Access: access,
SkipManifest: true,
Type: "bertysimple",
Address: address,
}
return param, nil
}
func defaultIdentityForGroup(ctx context.Context, g *protocoltypes.Group, ks *BertySignedKeyStore) (*identityprovider.Identity, error) {
sigPK, err := g.GetSigningPubKey()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
signingKeyBytes, err := sigPK.Raw()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
identity, err := ks.getIdentityProvider().createIdentity(ctx, &identityprovider.CreateIdentityOptions{
Type: identityType,
Keystore: ks,
ID: hex.EncodeToString(signingKeyBytes),
})
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return identity, nil
}
func readIdentityForGroup(g *protocoltypes.Group, ks *BertySignedKeyStore) (*identityprovider.Identity, error) {
sigPK, err := g.GetSigningPubKey()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
signingKeyBytes, err := sigPK.Raw()
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
return &identityprovider.Identity{
ID: hex.EncodeToString(signingKeyBytes),
PublicKey: g.PublicKey,
Signatures: &identityprovider.IdentitySignature{},
Type: ks.getIdentityProvider().GetType(),
Provider: ks.getIdentityProvider(),
}, nil
}
================================================
FILE: store_utils.go
================================================
package weshnet
import (
"bytes"
"errors"
ipliface "berty.tech/go-ipfs-log/iface"
"berty.tech/weshnet/v2/pkg/errcode"
)
func getEntriesInRange(entries []ipliface.IPFSLogEntry, since, until []byte) ([]ipliface.IPFSLogEntry, error) {
var (
startIndex, stopIndex int
startFound, stopFound bool
)
if since == nil {
startFound = true
startIndex = 0
}
if until == nil {
stopFound = true
stopIndex = len(entries) - 1
}
for i, entry := range entries {
if startFound && stopFound {
break
}
if !startFound && bytes.Equal(entry.GetHash().Bytes(), since) {
startFound = true
startIndex = i
}
if !stopFound && bytes.Equal(entry.GetHash().Bytes(), until) {
stopFound = true
stopIndex = i
}
}
if !startFound {
return nil, errcode.ErrCode_ErrInvalidRange.Wrap(errors.New("since ID not found"))
}
if !stopFound {
return nil, errcode.ErrCode_ErrInvalidRange.Wrap(errors.New("until ID not found"))
}
if startIndex > stopIndex && len(entries) > 0 {
return nil, errcode.ErrCode_ErrInvalidRange.Wrap(errors.New("since ID is after until ID"))
}
return entries[startIndex : stopIndex+1], nil
}
func iterateOverEntries(entries []ipliface.IPFSLogEntry, reverse bool, f func(ipliface.IPFSLogEntry)) {
if reverse {
for i := len(entries) - 1; i > -1; i-- {
f(entries[i])
}
} else {
for _, entry := range entries {
f(entry)
}
}
}
================================================
FILE: testing.go
================================================
package weshnet
import (
"bytes"
"context"
"fmt"
"io"
"os"
"path/filepath"
"sync"
"sync/atomic"
"testing"
"time"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
datastore "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
encrepo "berty.tech/go-ipfs-repo-encrypted"
orbitdb "berty.tech/go-orbit-db"
"berty.tech/go-orbit-db/pubsub/pubsubraw"
"berty.tech/weshnet/v2/internal/datastoreutil"
"berty.tech/weshnet/v2/pkg/errcode"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/protocoltypes"
"berty.tech/weshnet/v2/pkg/secretstore"
"berty.tech/weshnet/v2/pkg/testutil"
"berty.tech/weshnet/v2/pkg/tinder"
)
const InMemoryDir = ":memory:"
func NewTestOrbitDB(ctx context.Context, t *testing.T, logger *zap.Logger, node ipfsutil.CoreAPIMock, baseDS datastore.Batching) *WeshOrbitDB {
t.Helper()
api := node.API()
selfKey, err := api.Key().Self(ctx)
if err != nil {
t.Fatal(err)
}
baseDS = datastoreutil.NewNamespacedDatastore(baseDS, datastore.NewKey(selfKey.ID().String()))
secretStore, err := secretstore.NewSecretStore(baseDS, nil)
require.NoError(t, err)
t.Cleanup(func() {
_ = secretStore.Close()
})
pubSub := pubsubraw.NewPubSub(node.PubSub(), selfKey.ID(), logger, nil)
odb, err := NewWeshOrbitDB(ctx, api, &NewOrbitDBOptions{
Datastore: baseDS,
SecretStore: secretStore,
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
Logger: logger,
PubSub: pubSub,
},
})
require.NoError(t, err)
return odb
}
type mockedPeer struct {
CoreAPI ipfsutil.CoreAPIMock
DB *WeshOrbitDB
GC *GroupContext
SecretStore secretstore.SecretStore
}
func (m *mockedPeer) PeerInfo() peer.AddrInfo {
return m.CoreAPI.MockNode().Peerstore.PeerInfo(m.CoreAPI.MockNode().Identity)
}
type TestingProtocol struct {
Opts *Opts
Service Service
Client ServiceClient
RootDatastore datastore.Batching
IpfsCoreAPI ipfsutil.ExtendedCoreAPI
OrbitDB *WeshOrbitDB
SecretStore secretstore.SecretStore
}
type TestingOpts struct {
Logger *zap.Logger
Mocknet mocknet.Mocknet
DiscoveryServer *tinder.MockDriverServer
SecretStore secretstore.SecretStore
CoreAPIMock ipfsutil.CoreAPIMock
OrbitDB *WeshOrbitDB
ConnectFunc ConnectTestingProtocolFunc
}
func NewTestingProtocol(ctx context.Context, t testing.TB, opts *TestingOpts, ds datastore.Batching) (*TestingProtocol, func()) {
if opts == nil {
opts = &TestingOpts{}
}
opts.applyDefaults(ctx, t)
if ds == nil {
ds = ds_sync.MutexWrap(datastore.NewMapDatastore())
}
ipfsopts := &ipfsutil.TestingAPIOpts{
Logger: opts.Logger,
Mocknet: opts.Mocknet,
DiscoveryServer: opts.DiscoveryServer,
Datastore: ds,
}
node := opts.CoreAPIMock
if node == nil {
node = ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, ipfsopts)
}
secretStore := opts.SecretStore
if secretStore == nil {
var err error
secretStore, err = secretstore.NewInMemSecretStore(&secretstore.NewSecretStoreOptions{})
require.NoError(t, err)
}
odb := opts.OrbitDB
if odb == nil {
var err error
pubSub := pubsubraw.NewPubSub(node.PubSub(), node.MockNode().PeerHost.ID(), opts.Logger, nil)
odb, err = NewWeshOrbitDB(ctx, node.API(), &NewOrbitDBOptions{
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
PubSub: pubSub,
Logger: opts.Logger,
},
Datastore: ds,
SecretStore: secretStore,
})
require.NoError(t, err)
}
serviceOpts := Opts{
Host: node.MockNode().PeerHost,
PubSub: node.PubSub(),
Logger: opts.Logger,
RootDatastore: ds,
IpfsCoreAPI: node.API(),
OrbitDB: odb,
TinderService: node.Tinder(),
SecretStore: secretStore,
}
service, cleanupService := TestingService(ctx, t, serviceOpts)
// setup client
grpcLogger := opts.Logger.Named("grpc")
zapOpts := []grpc_zap.Option{}
serverOpts := []grpc.ServerOption{
grpc_middleware.WithUnaryServerChain(
grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_zap.UnaryServerInterceptor(grpcLogger, zapOpts...),
),
grpc_middleware.WithStreamServerChain(
grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
grpc_zap.StreamServerInterceptor(grpcLogger, zapOpts...),
),
}
clientOpts := []grpc.DialOption{
grpc.WithChainUnaryInterceptor(),
grpc.WithChainStreamInterceptor(),
}
server := grpc.NewServer(serverOpts...)
client, cleanupClient := TestingClientFromServer(ctx, t, server, service, clientOpts...)
tp := &TestingProtocol{
Opts: &serviceOpts,
Client: client,
Service: service,
RootDatastore: ds,
IpfsCoreAPI: node.API(),
OrbitDB: odb,
SecretStore: secretStore,
}
cleanup := func() {
server.Stop()
cleanupClient()
cleanupService()
}
return tp, cleanup
}
func (opts *TestingOpts) applyDefaults(ctx context.Context, t testing.TB) {
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
if opts.Mocknet == nil {
opts.Mocknet = mocknet.New()
t.Cleanup(func() { opts.Mocknet.Close() })
}
if opts.ConnectFunc == nil {
opts.ConnectFunc = ConnectAll
}
}
func NewTestingProtocolWithMockedPeers(ctx context.Context, t testing.TB, opts *TestingOpts, ds datastore.Batching, amount int) ([]*TestingProtocol, func()) {
t.Helper()
opts.applyDefaults(ctx, t)
logger := opts.Logger
if ds == nil {
ds = ds_sync.MutexWrap(datastore.NewMapDatastore())
}
if opts.DiscoveryServer == nil {
opts.DiscoveryServer = tinder.NewMockDriverServer()
}
cls := make([]func(), amount)
tps := make([]*TestingProtocol, amount)
for i := range tps {
svcName := fmt.Sprintf("mock%d", i)
opts.Logger = logger.Named(svcName)
ds := datastoreutil.NewNamespacedDatastore(ds, datastore.NewKey(fmt.Sprintf("%d", i)))
tps[i], cls[i] = NewTestingProtocol(ctx, t, opts, ds)
}
opts.ConnectFunc(t, opts.Mocknet)
cleanup := func() {
for i := range cls {
cls[i]()
}
}
return tps, cleanup
}
// TestingService returns a configured Client struct with in-memory contexts.
func TestingService(ctx context.Context, t testing.TB, opts Opts) (Service, func()) {
t.Helper()
if opts.Logger == nil {
opts.Logger = zap.NewNop()
}
if opts.IpfsCoreAPI == nil {
var mn ipfsutil.CoreAPIMock
mn = ipfsutil.TestingCoreAPI(ctx, t)
opts.IpfsCoreAPI = mn.API()
}
service, err := NewService(opts)
if err != nil {
t.Fatalf("failed to initialize client: %v", err)
}
cleanup := func() {
service.Close()
}
return service, cleanup
}
func TestingClientFromServer(ctx context.Context, t testing.TB, s *grpc.Server, svc Service, dialOpts ...grpc.DialOption) (client ServiceClient, cleanup func()) {
t.Helper()
var err error
client, err = NewClientFromService(ctx, s, svc, dialOpts...)
require.NoError(t, err)
cleanup = func() {
client.Close()
}
return
}
func TestingClient(ctx context.Context, t testing.TB, svc Service, clientOpts []grpc.DialOption, serverOpts []grpc.ServerOption) (client ServiceClient, cleanup func()) {
t.Helper()
var err error
srv := grpc.NewServer(serverOpts...)
client, err = NewClientFromService(ctx, srv, svc, clientOpts...)
require.NoError(t, err)
cleanup = func() {
srv.Stop()
client.Close()
}
return
}
// Connect Peers Helper
type ConnectTestingProtocolFunc func(testing.TB, mocknet.Mocknet)
// ConnectAll peers between themselves
func ConnectAll(t testing.TB, m mocknet.Mocknet) {
t.Helper()
err := m.LinkAll()
require.NoError(t, err)
err = m.ConnectAllButSelf()
require.NoError(t, err)
}
// ConnectInLine, connect peers one by one in order to make a straight line:
// ┌───┐ ┌───┐ ┌───┐ ┌───┐
// │ 1 │───▶│ 2 │───▶│ 3 │─ ─ ─ ─ ▶│ x │
// └───┘ └───┘ └───┘ └───┘
func ConnectInLine(t testing.TB, m mocknet.Mocknet) {
t.Helper()
peers := m.Peers()
for i := 0; i < len(peers)-1; i++ {
_, err := m.LinkPeers(peers[i], peers[i+1])
require.NoError(t, err)
_, err = m.ConnectPeers(peers[i], peers[i+1])
require.NoError(t, err)
}
}
func CreatePeersWithGroupTest(ctx context.Context, t testing.TB, pathBase string, memberCount int, deviceCount int) ([]*mockedPeer, crypto.PrivKey, func()) {
t.Helper()
logger, cleanupLogger := testutil.Logger(t)
var secretStore secretstore.SecretStore
mockedPeers := make([]*mockedPeer, memberCount*deviceCount)
group, groupPrivateKey, err := NewGroupMultiMember()
if err != nil {
t.Fatal(err)
}
mn := mocknet.New()
t.Cleanup(func() { mn.Close() })
ipfsopts := ipfsutil.TestingAPIOpts{
Logger: logger,
Mocknet: mn,
DiscoveryServer: tinder.NewMockDriverServer(),
}
deviceIndex := 0
cls := make([]func(), memberCount)
for i := 0; i < memberCount; i++ {
for j := 0; j < deviceCount; j++ {
ca := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, &ipfsopts)
if j == 0 {
secretStore, err = secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
} else {
privateKeyBytes, proofPrivateKeyBytes, err := secretStore.ExportAccountKeysForBackup()
require.NoError(t, err, "ExportAccountKeysForBackup error")
secretStore, err = secretstore.NewInMemSecretStore(nil)
require.NoError(t, err)
require.NoError(t, secretStore.ImportAccountKeys(privateKeyBytes, proofPrivateKeyBytes))
}
db, err := NewWeshOrbitDB(ctx, ca.API(), &NewOrbitDBOptions{
NewOrbitDBOptions: orbitdb.NewOrbitDBOptions{
Logger: logger,
},
SecretStore: secretStore,
})
if err != nil {
t.Fatal(err)
}
gc, err := db.OpenGroup(ctx, group, nil)
if err != nil {
t.Fatalf("err: creating new group context, %v", err)
}
mp := &mockedPeer{
CoreAPI: ca,
DB: db,
GC: gc,
SecretStore: secretStore,
}
// setup cleanup
cls[i] = func() {
if ms := mp.GC.MetadataStore(); ms != nil {
err := ms.Drop()
assert.NoError(t, err)
}
gc.Close()
if db := mp.DB; db != nil {
assert.NoError(t, err)
err = db.Close()
assert.NoError(t, err)
}
_ = secretStore.Close()
}
mockedPeers[deviceIndex] = mp
deviceIndex++
}
}
connectPeers(ctx, t, ipfsopts.Mocknet)
return mockedPeers, groupPrivateKey, func() {
for _, cleanup := range cls {
cleanup()
}
cleanupLogger()
}
}
func connectPeers(ctx context.Context, t testing.TB, mn mocknet.Mocknet) {
t.Helper()
err := mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
}
func dropPeers(t *testing.T, mockedPeers []*mockedPeer) {
t.Helper()
for _, m := range mockedPeers {
if ms := m.GC.MetadataStore(); ms != nil {
if err := ms.Drop(); err != nil {
t.Fatal(err)
}
}
if db := m.DB; db != nil {
if err := db.Close(); err != nil {
t.Fatal(err)
}
}
if ca := m.CoreAPI; ca != nil {
if err := ca.MockNode().Close(); err != nil {
t.Fatal(err)
}
}
}
}
type ServiceMethods interface {
GetContextGroupForID(id []byte) (*GroupContext, error)
}
func GetRootDatastoreForPath(dir string, key []byte, salt []byte, logger *zap.Logger) (datastore.Batching, error) {
inMemory := dir == InMemoryDir
var ds datastore.Batching
if inMemory {
ds = datastore.NewMapDatastore()
} else {
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
dbPath := filepath.Join(dir, "datastore.sqlite")
sqldsOpts := encrepo.SQLCipherDatastoreOptions{JournalMode: "WAL", PlaintextHeader: len(salt) != 0, Salt: salt}
ds, err = encrepo.NewSQLCipherDatastore("sqlite3", dbPath, "blocks", key, sqldsOpts)
if err != nil {
return nil, errcode.ErrCode_TODO.Wrap(err)
}
}
ds = ds_sync.MutexWrap(ds)
return ds, nil
}
func CreateMultiMemberGroupInstance(ctx context.Context, t *testing.T, tps ...*TestingProtocol) *protocoltypes.Group {
testutil.LogTree(t, "Create and Join MultiMember Group", 0, true)
start := time.Now()
ntps := len(tps)
// Create group
group, _, err := NewGroupMultiMember()
require.NoError(t, err)
// Get Instance Configurations
{
testutil.LogTree(t, "Get Instance Configuration", 1, true)
start := time.Now()
// check if everything is ready
for _, pt := range tps {
_, err := pt.Client.ServiceGetConfiguration(ctx, &protocoltypes.ServiceGetConfiguration_Request{})
require.NoError(t, err)
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Join Group
{
testutil.LogTree(t, "Join Group", 1, true)
start := time.Now()
for _, pt := range tps {
req := protocoltypes.MultiMemberGroupJoin_Request{
Group: group,
}
// pt join group
_, err = pt.Client.MultiMemberGroupJoin(ctx, &req)
require.NoError(t, err)
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Get Member/Device PKs
memberPKs := make([][]byte, ntps)
devicePKs := make([][]byte, ntps)
{
testutil.LogTree(t, "Get Member/Device PKs", 1, true)
start := time.Now()
for i, pt := range tps {
res, err := pt.Client.GroupInfo(ctx, &protocoltypes.GroupInfo_Request{
GroupPk: group.PublicKey,
})
require.NoError(t, err)
assert.Equal(t, group.PublicKey, res.Group.PublicKey)
memberPKs[i] = res.MemberPk
devicePKs[i] = res.DevicePk
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Activate Group
{
testutil.LogTree(t, "Activate Group", 1, true)
start := time.Now()
for i, pt := range tps {
_, err := pt.Client.ActivateGroup(ctx, &protocoltypes.ActivateGroup_Request{
GroupPk: group.PublicKey,
})
assert.NoError(t, err, fmt.Sprintf("error for client %d", i))
}
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
// Exchange Secrets
{
testutil.LogTree(t, "Exchange Secrets", 1, true)
start := time.Now()
wg := sync.WaitGroup{}
secretsReceivedLock := sync.Mutex{}
secretsReceived := make([]map[string]struct{}, ntps)
wg.Add(ntps)
nSuccess := int64(0)
for i := range tps {
go func(i int) {
tp := tps[i]
defer wg.Done()
secretsReceived[i] = map[string]struct{}{}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
sub, inErr := tp.Client.GroupMetadataList(ctx, &protocoltypes.GroupMetadataList_Request{
GroupPk: group.PublicKey,
})
if inErr != nil {
assert.NoError(t, err, fmt.Sprintf("error for client %d", i))
return
}
for {
evt, inErr := sub.Recv()
if inErr != nil {
if inErr != io.EOF {
assert.NoError(t, err, fmt.Sprintf("error for client %d", i))
}
break
}
if source, err := isEventAddSecretTargetedToMember(memberPKs[i], evt); err != nil {
tps[i].Opts.Logger.Error("err:", zap.Error(inErr))
assert.NoError(t, err, fmt.Sprintf("error for client %d", i))
break
} else if source != nil {
secretsReceivedLock.Lock()
secretsReceived[i][string(source)] = struct{}{}
done := len(secretsReceived[i]) == ntps
secretsReceivedLock.Unlock()
if done {
n := atomic.AddInt64(&nSuccess, 1)
got := fmt.Sprintf("%d/%d", n, ntps)
tps[i].Opts.Logger.Debug("received all secrets", zap.String("ok", got))
return
}
}
}
}(i)
}
wg.Wait()
secretsReceivedLock.Lock()
ok := true
for i := range secretsReceived {
if !assert.Equal(t, ntps, len(secretsReceived[i]), fmt.Sprintf("mismatch for client %d", i)) {
ok = false
}
}
require.True(t, ok)
secretsReceivedLock.Unlock()
testutil.LogTree(t, "duration: %s", 1, false, time.Since(start))
}
testutil.LogTree(t, "duration: %s", 0, false, time.Since(start))
return group
}
func isEventAddSecretTargetedToMember(ownRawPK []byte, evt *protocoltypes.GroupMetadataEvent) ([]byte, error) {
// Only count EventTypeGroupDeviceChainKeyAdded events
if evt.Metadata.EventType != protocoltypes.EventType_EventTypeGroupDeviceChainKeyAdded {
return nil, nil
}
sec := &protocoltypes.GroupDeviceChainKeyAdded{}
err := proto.Unmarshal(evt.Event, sec)
if err != nil {
return nil, err
}
// Filter out events targeted at other members
if !bytes.Equal(ownRawPK, sec.DestMemberPk) {
return nil, nil
}
return sec.DevicePk, nil
}
================================================
FILE: testing_test.go
================================================
package weshnet
import (
"context"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/protocoltypes"
)
func TestClient_impl(t *testing.T) {
var _ Service = (*service)(nil)
var _ protocoltypes.ProtocolServiceServer = (*service)(nil)
}
func TestEmptyArgs(t *testing.T) {
// disable resources manager for test
os.Setenv("LIBP2P_RCMGR", "false")
// initialize new client
client, err := NewService(Opts{})
require.NoError(t, err)
err = client.Close()
require.NoError(t, err)
client.Close()
}
func TestTestingProtocol(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
opts := TestingOpts{}
tp, cleanup := NewTestingProtocol(ctx, t, &opts, nil)
assert.NotNil(t, tp)
cleanup()
cancel()
}
func TestTestingProtocolWithMockedPeers(t *testing.T) {
for amount := 0; amount < 5; amount++ {
t.Run(fmt.Sprintf("%d-peers", amount), func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
opts := TestingOpts{}
tp, cleanup := NewTestingProtocolWithMockedPeers(ctx, t, &opts, nil, amount)
assert.NotNil(t, tp)
cleanup()
cancel()
})
}
}
================================================
FILE: tinder_swiper.go
================================================
package weshnet
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
mrand "math/rand"
"sync"
"time"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer"
backoff "github.com/libp2p/go-libp2p/p2p/discovery/backoff"
"go.uber.org/zap"
"moul.io/srand"
"berty.tech/weshnet/v2/pkg/logutil"
"berty.tech/weshnet/v2/pkg/rendezvous"
tinder "berty.tech/weshnet/v2/pkg/tinder"
"berty.tech/weshnet/v2/pkg/tyber"
)
type swiperRequest struct {
bstrat backoff.BackoffStrategy
wgRefresh *sync.WaitGroup
ctx context.Context
out chan<- peer.AddrInfo
rdvTopic string
}
type Swiper struct {
topics map[string]*pubsub.Topic
backoffFactory backoff.BackoffFactory
inprogressLookup map[string]*swiperRequest
muRequest sync.Mutex
rp *rendezvous.RotationInterval
logger *zap.Logger
tinder *tinder.Service
}
func NewSwiper(logger *zap.Logger, tinder *tinder.Service, rp *rendezvous.RotationInterval) *Swiper {
// we need to use math/rand here, but it is seeded from crypto/rand
srand := mrand.New(mrand.NewSource(srand.MustSecure())) // nolint:gosec
backoffstrat := backoff.NewExponentialBackoff(time.Second, time.Minute*10,
backoff.FullJitter,
time.Second, 30.0, 0, srand)
return &Swiper{
backoffFactory: backoffstrat,
logger: logger.Named("swiper"),
topics: make(map[string]*pubsub.Topic),
inprogressLookup: make(map[string]*swiperRequest),
rp: rp,
tinder: tinder,
}
}
func (s *Swiper) RefreshContactRequest(ctx context.Context, topic []byte) (addrs []peer.AddrInfo, err error) {
ctx, _, endSection := tyber.Section(ctx, s.logger, "swiper starting refresh: "+hex.EncodeToString(topic))
defer func() {
endSection(err, "")
}()
// canceling find peers
s.muRequest.Lock()
req, ok := s.inprogressLookup[base64.StdEncoding.EncodeToString(topic)]
if !ok {
err = fmt.Errorf("unknown topic")
s.muRequest.Unlock()
return addrs, err
}
// add a refresh job process
req.wgRefresh.Add(1)
defer req.wgRefresh.Done()
s.muRequest.Unlock()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go func() {
// if rotation topic is outdated, cancel research
<-req.ctx.Done()
cancel()
}()
// force find peers re check topic
cpeer := s.tinder.FindPeers(req.ctx, req.rdvTopic)
select {
case p := <-cpeer:
req.out <- p
return []peer.AddrInfo{p}, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
// WatchTopic looks for peers providing a resource.
// 'done' is used to alert parent when everything is done, to avoid data races.
func (s *Swiper) WatchTopic(ctx context.Context, topic, seed []byte) <-chan peer.AddrInfo {
ctx, _, endSection := tyber.Section(ctx, s.logger, "swiper looking for peers: "+hex.EncodeToString(topic))
s.muRequest.Lock()
defer s.muRequest.Unlock()
s.logger.Debug("start watch for peer with",
logutil.PrivateString("topic", base64.StdEncoding.EncodeToString(topic)),
zap.String("seed", string(seed)))
var point *rendezvous.Point
cpeers := make(chan peer.AddrInfo)
go func() {
defer endSection(nil, "watch topic ended")
defer close(cpeers)
wgRefresh := sync.WaitGroup{}
for ctx.Err() == nil {
if point == nil || time.Now().After(point.Deadline()) {
point = s.rp.NewRendezvousPointForPeriod(time.Now(), base64.StdEncoding.EncodeToString(topic), seed)
}
bstrat := s.backoffFactory()
// store watch peers information to be later used by the refresh method to force a lookup
s.muRequest.Lock()
wctx, cancel := context.WithCancel(ctx)
s.inprogressLookup[base64.StdEncoding.EncodeToString(topic)] = &swiperRequest{
bstrat: bstrat,
wgRefresh: &wgRefresh,
ctx: wctx,
out: cpeers,
rdvTopic: point.RotationTopic(),
}
s.muRequest.Unlock()
// start looking for peers for the given rotation topic
s.logger.Debug("looking for peers", logutil.PrivateString("topic", point.RotationTopic()))
if err := s.watchPeers(wctx, bstrat, cpeers, point.RotationTopic()); err != nil && err != context.DeadlineExceeded {
s.logger.Debug("watch until deadline ended", zap.Error(err))
}
cancel()
// at this point upper context is done or we need to refresh
// rotation point.
// take a little breath and wait one second to avoid calling find
// peer in short amount of time
time.Sleep(time.Second)
}
s.muRequest.Lock()
delete(s.inprogressLookup, base64.StdEncoding.EncodeToString(topic))
s.muRequest.Unlock()
// wait all refresh job are done before closing the channel
// we dont want to send peer on a closed channel
wgRefresh.Wait()
}()
return cpeers
}
func (s *Swiper) watchPeers(ctx context.Context, _ backoff.BackoffStrategy, out chan<- peer.AddrInfo, topic string) error {
sub := s.tinder.Subscribe(topic)
defer sub.Close()
// func () {
// if err := sub.Close(); err != nil {
// s.logger.Error("unable to close sub properly", zap.Error(err))
// }
// }()
s.logger.Debug("swipper watch peers started", logutil.PrivateString("topic", topic))
// start findpeers for pulls
go func() {
timeout := time.Minute // @TODO(gfanton): do we need to use backoffstartegy here ?
for ctx.Err() == nil {
s.logger.Debug("swiper pulling for peers", logutil.PrivateString("topic", topic))
if err := sub.Pull(); err != nil {
s.logger.Error("unable to pull for peer on subscription", zap.Error(err))
}
select {
case <-time.After(timeout):
case <-ctx.Done():
}
}
}()
for {
// wait until the context is done
select {
case p := <-sub.Out():
s.logger.Debug("found a peers", logutil.PrivateString("topic", topic), zap.String("peer", p.String()))
out <- p
case <-ctx.Done():
s.logger.Debug("watch peers done", logutil.PrivateString("topic", topic))
return ctx.Err()
}
}
}
// watch looks for peers providing a resource
func (s *Swiper) Announce(ctx context.Context, topic, seed []byte) {
var point *rendezvous.Point
s.logger.Debug("start announce for peer with",
logutil.PrivateString("topic", base64.StdEncoding.EncodeToString(topic)),
logutil.PrivateString("seed", string(seed)))
go func() {
for ctx.Err() == nil {
if point == nil || time.Now().After(point.Deadline()) {
point = s.rp.NewRendezvousPointForPeriod(time.Now(), base64.StdEncoding.EncodeToString(topic), seed)
}
s.logger.Debug("self announce topic for time", logutil.PrivateString("topic", point.RotationTopic()))
actx, cancel := context.WithDeadline(ctx, point.Deadline())
if err := s.tinder.StartAdvertises(actx, point.RotationTopic()); err != nil && err != ctx.Err() {
cancel()
<-time.After(time.Second * 10) // retry after 10sc
continue
}
select {
case <-actx.Done():
s.logger.Debug("rotation ended", logutil.PrivateString("topic", point.RotationTopic()))
case <-ctx.Done():
s.logger.Debug("announce advertise ended", logutil.PrivateString("topic", point.RotationTopic()), zap.Error(ctx.Err()))
}
cancel()
}
}()
}
================================================
FILE: tinder_swiper_test.go
================================================
package weshnet
import (
"context"
"fmt"
"testing"
"time"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"berty.tech/weshnet/v2/pkg/ipfsutil"
"berty.tech/weshnet/v2/pkg/rendezvous"
"berty.tech/weshnet/v2/pkg/testutil"
"berty.tech/weshnet/v2/pkg/tinder"
)
func TestAnnounceWatchForPeriod(t *testing.T) {
testutil.FilterSpeed(t, testutil.Slow)
cases := []struct {
expectedPeersFound int
topicA []byte
topicB []byte
seedA []byte
seedB []byte
}{
{
expectedPeersFound: 0,
topicA: []byte("topicA"),
topicB: []byte("topicB"),
seedA: []byte("seedA"),
seedB: []byte("seedA"),
},
{
expectedPeersFound: 1,
topicA: []byte("topicA"),
topicB: []byte("topicA"),
seedA: []byte("seedA"),
seedB: []byte("seedA"),
},
}
logger, cleanup := testutil.Logger(t)
defer cleanup()
for i, tc := range cases {
t.Run(fmt.Sprintf("tc: %d", i), func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mn := mocknet.New()
defer mn.Close()
opts := &ipfsutil.TestingAPIOpts{
Logger: logger,
Mocknet: mn,
DiscoveryServer: tinder.NewMockDriverServer(),
}
apiA := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, opts)
apiB := ipfsutil.TestingCoreAPIUsingMockNet(ctx, t, opts)
err := mn.LinkAll()
require.NoError(t, err)
err = mn.ConnectAllButSelf()
require.NoError(t, err)
rpA := rendezvous.NewRotationInterval(time.Hour)
rpB := rendezvous.NewRotationInterval(time.Hour)
swiperA := NewSwiper(opts.Logger, apiA.Tinder(), rpA)
swiperB := NewSwiper(opts.Logger, apiB.Tinder(), rpB)
swiperA.Announce(ctx, tc.topicA, tc.seedA)
time.Sleep(time.Millisecond * 100)
cpeers := swiperB.WatchTopic(ctx, tc.topicB, tc.seedB)
var foundPeers int
loop:
for foundPeers = 0; foundPeers < tc.expectedPeersFound; foundPeers++ {
select {
case <-ctx.Done():
break loop
case <-cpeers:
}
}
assert.Equal(t, len(cpeers), 0)
assert.Equal(t, tc.expectedPeersFound, foundPeers)
})
}
}
func TestAnnounceForPeriod(t *testing.T) {
}
================================================
FILE: tool/bench-cellular/.gitignore
================================================
bench
================================================
FILE: tool/bench-cellular/Makefile
================================================
SRCS := $(wildcard *.go)
bench: $(SRCS)
go build $(SRCS)
@echo "Now run './bench -h'"
help: bench
./bench -h
================================================
FILE: tool/bench-cellular/bench.go
================================================
package main
import (
"context"
crand "crypto/rand"
"flag"
"fmt"
"io"
mrand "math/rand"
"os"
"strings"
golog "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
quict "github.com/libp2p/go-libp2p-quic-transport"
"github.com/libp2p/go-libp2p/core/crypto"
tcpt "github.com/libp2p/go-libp2p/p2p/transport/tcp"
ma "github.com/multiformats/go-multiaddr"
"github.com/peterbourgon/ff/v3/ffcli"
)
const (
benchDownloadPID = "/bench/download/1.0.0"
benchUploadPID = "/bench/upload/1.0.0"
)
type globalOpts struct {
tcp bool
insecure bool
seed int64
verbose bool
veryVerbose bool
}
func globalOptsToLibp2pOpts(gOpts *globalOpts) ([]libp2p.Option, error) {
var (
r io.Reader
opts []libp2p.Option
)
if gOpts.seed == 0 {
r = crand.Reader
} else {
r = mrand.New(mrand.NewSource(gOpts.seed))
}
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, crypto.MinRsaKeyBits, r)
if err != nil {
return nil, err
}
opts = append(opts, libp2p.Identity(priv))
if gOpts.tcp {
opts = append(opts, libp2p.Transport(tcpt.NewTCPTransport))
} else {
opts = append(opts, libp2p.Transport(quict.NewTransport))
}
if gOpts.insecure {
opts = append(opts, libp2p.NoSecurity)
}
return opts, nil
}
func main() {
var (
ctx = context.Background()
gOpts = &globalOpts{}
sOpts = &serverOpts{}
cOpts = &clientOpts{}
)
var serverCommand *ffcli.Command
{
serverFs := flag.NewFlagSet("server", flag.ExitOnError)
serverFs.IntVar(&sOpts.port, "port", 0, "port to listen on (default: random)")
serverFs.BoolVar(&sOpts.ip6, "ip6", false, "use ipv6 instead of ipv4")
serverFs.StringVar(&sOpts.relay, "relay", staticBertyRelayMode, fmt.Sprintf("set relay mode, possible values: '%s', '%s', '%s' or '%s'", staticBertyRelayMode, staticIPFSRelayMode, discoveryRelayMode, disabledRelayMode))
serverCommand = &ffcli.Command{
Name: "server",
ShortUsage: "bench server [flags]",
ShortHelp: "run a benchmark server that listen for client request",
FlagSet: serverFs,
Exec: func(ctx context.Context, args []string) error {
if len(args) > 0 {
return flag.ErrHelp
}
if sOpts.relay != staticBertyRelayMode && sOpts.relay != staticIPFSRelayMode && sOpts.relay != discoveryRelayMode && sOpts.relay != disabledRelayMode {
fmt.Fprintf(os.Stderr, "error: invalid value for -relay flag: %s\n\n", sOpts.relay)
return flag.ErrHelp
}
if gOpts.verbose {
golog.SetAllLoggers(golog.LevelError)
golog.SetLogLevel("autorelay", "debug")
golog.SetLogLevel("autonat", "debug")
golog.SetLogLevel("basichost", "debug")
golog.SetLogLevel("swarm2", "debug")
}
if gOpts.veryVerbose {
golog.SetAllLoggers(golog.LevelDebug)
}
return runServer(ctx, gOpts, sOpts)
},
}
}
var clientCommand *ffcli.Command
{
const megabyte = 1048576
clientFs := flag.NewFlagSet("client", flag.ExitOnError)
clientFs.StringVar(&cOpts.dest, "dest", "", "server multiaddr to dial")
clientFs.StringVar(&cOpts.request, "request", fmt.Sprintf("%s,%s,%s", pingRequestType, uploadRequestType, downloadRequestType), fmt.Sprintf("comma separated list of request type to send, possible values: '%s', '%s' and '%s'", pingRequestType, uploadRequestType, downloadRequestType))
clientFs.BoolVar(&cOpts.reco, "reco", false, "test reconnection to server")
clientFs.IntVar(&cOpts.size, "size", megabyte, "size (in bytes) of data to upload / download (default: 1MB)")
clientCommand = &ffcli.Command{
Name: "client",
ShortUsage: "bench client [flags]",
ShortHelp: "run a benchmark client that send request to server",
FlagSet: clientFs,
Exec: func(ctx context.Context, args []string) error {
if len(args) > 0 {
return flag.ErrHelp
}
requestTypes := strings.Split(cOpts.request, ",")
if len(requestTypes) == 0 {
fmt.Fprintf(os.Stderr, "error: at least one request type must be specified using -request flag\n\n")
return flag.ErrHelp
}
for _, requestType := range requestTypes {
trimed := strings.TrimSpace(requestType)
if trimed != pingRequestType && trimed != uploadRequestType && trimed != downloadRequestType {
fmt.Fprintf(os.Stderr, "error: invalid request type specified using -request flag: '%s'\n\n", trimed)
return flag.ErrHelp
}
}
if cOpts.dest == "" {
fmt.Fprintf(os.Stderr, "error: a server multiaddr must be specified using -dest flag\n\n")
return flag.ErrHelp
}
if _, err := ma.NewMultiaddr(cOpts.dest); err != nil {
fmt.Fprintf(os.Stderr, "error: invalid multiaddr specified using -dest flag: %v\n\n", err)
return flag.ErrHelp
}
if cOpts.size <= 0 {
fmt.Fprintf(os.Stderr, "error: a positive bytes amount must be set using -size flag (default 1MB)\n\n")
return flag.ErrHelp
}
if gOpts.verbose {
golog.SetAllLoggers(golog.LevelError)
golog.SetLogLevel("basichost", "debug")
golog.SetLogLevel("swarm2", "debug")
}
if gOpts.veryVerbose {
golog.SetAllLoggers(golog.LevelDebug)
}
return runClient(ctx, gOpts, cOpts)
},
}
}
var rootCommand *ffcli.Command
{
rootFs := flag.NewFlagSet("root", flag.ExitOnError)
rootFs.BoolVar(&gOpts.tcp, "tcp", false, "use TCP instead of QUIC")
rootFs.BoolVar(&gOpts.insecure, "insecure", false, "use an unencrypted connection")
rootFs.Int64Var(&gOpts.seed, "seed", 0, "set random seed for id generation")
rootFs.BoolVar(&gOpts.verbose, "v", false, "verbose mode: print debug level for relevant libp2p loggers")
rootFs.BoolVar(&gOpts.veryVerbose, "vv", false, "very verbose mode: print debug level for all libp2p loggers")
rootCommand = &ffcli.Command{
ShortUsage: "bench [flags] [subcommand_flags]",
FlagSet: rootFs,
Exec: func(context.Context, []string) error { return flag.ErrHelp },
Subcommands: []*ffcli.Command{
serverCommand,
clientCommand,
},
}
}
err := rootCommand.ParseAndRun(ctx, os.Args[1:])
if err == flag.ErrHelp {
os.Exit(1)
} else if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(2)
}
}
================================================
FILE: tool/bench-cellular/client.go
================================================
package main
import (
"bufio"
"context"
"fmt"
"io"
"log"
"math/rand"
"os"
"strings"
"time"
"github.com/libp2p/go-libp2p"
peer "github.com/libp2p/go-libp2p-peer"
"github.com/libp2p/go-libp2p/core/host"
peerstore "github.com/libp2p/go-libp2p/p2p/host/peerstore"
p2pping "github.com/libp2p/go-libp2p/p2p/protocol/ping"
ma "github.com/multiformats/go-multiaddr"
)
const (
pingRequestType = "ping"
uploadRequestType = "upload"
downloadRequestType = "download"
)
type clientOpts struct {
dest string
request string
reco bool
size int
}
func createClientHost(ctx context.Context, gOpts *globalOpts) (host.Host, error) {
opts, err := globalOptsToLibp2pOpts(gOpts) // Get identity and transport
if err != nil {
return nil, err
}
opts = append(
opts,
libp2p.ListenAddrs(), // On client mode, set no listener
)
return libp2p.New(ctx, opts...) // Create host
}
func addDestToPeerstore(h host.Host, dest string) (peer.ID, error) {
maddr, err := ma.NewMultiaddr(dest)
if err != nil {
return "", err
}
var pid string
if _, err := maddr.ValueForProtocol(ma.P_CIRCUIT); err == nil {
first := true
// Get the second peerid (target), the first being the relay peerid
ma.ForEach(maddr, func(c ma.Component) bool {
if c.Protocol().Code == ma.P_IPFS {
if first {
first = false
} else {
pid = c.Value()
return false
}
}
return true
})
} else {
pid, err = maddr.ValueForProtocol(ma.P_IPFS)
if err != nil {
return "", err
}
}
peerid, err := peer.IDB58Decode(pid)
if err != nil {
return "", err
}
if _, err := maddr.ValueForProtocol(ma.P_CIRCUIT); err != nil {
targetAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", pid))
maddr = maddr.Decapsulate(targetAddr)
}
h.Peerstore().AddAddr(peerid, maddr, peerstore.PermanentAddrTTL)
return peerid, nil
}
func ping(ctx context.Context, h host.Host, peerid peer.ID) error {
var (
timeout = 30 * time.Second
timeoutCtx, cancel = context.WithTimeout(ctx, timeout)
resultOccured = 0
resultRequired = 8
start = time.Now()
)
defer cancel()
log.Printf("New ping started with timeout: %v", timeout)
for result := range p2pping.Ping(timeoutCtx, h, peerid) {
if result.Error != nil {
return fmt.Errorf("ping error: %v", result.Error)
}
log.Printf("\tPing RTT: %v", result.RTT)
resultOccured++
if resultOccured >= resultRequired {
break
}
}
if resultOccured < resultRequired {
return fmt.Errorf("ping request timeouted after %v: %d/%d (RTT done/required)", timeout, resultOccured, resultRequired)
}
log.Printf("Ping request with %d RTT took: %v", resultOccured, time.Since(start))
return nil
}
func upload(ctx context.Context, h host.Host, peerid peer.ID, cOpts *clientOpts) error {
start := time.Now()
su, err := h.NewStream(ctx, peerid, benchUploadPID)
if err != nil {
return fmt.Errorf("new upload stream failed: %v", err)
}
reader := bufio.NewReader(su)
if _, err = reader.ReadString('\n'); err != nil {
return fmt.Errorf("read error during stream opened ack: %v", err)
}
log.Printf("New upload stream took: %v", time.Since(start))
data := make([]byte, cOpts.size)
rand.Read(data)
start = time.Now()
if _, err = su.Write(data); err != nil {
return fmt.Errorf("write error during upload: %v", err)
}
su.CloseWrite()
if _, err = reader.ReadString('\n'); err != nil {
return fmt.Errorf("read error during uploaded ack: %v", err)
}
log.Printf("Data (%d bytes) upload took: %v", cOpts.size, time.Since(start))
su.CloseRead()
return nil
}
func download(ctx context.Context, h host.Host, peerid peer.ID, cOpts *clientOpts) error {
start := time.Now()
sd, err := h.NewStream(ctx, peerid, benchDownloadPID)
if err != nil {
return fmt.Errorf("new download stream failed: %v", err)
}
reader := bufio.NewReader(sd)
if _, err = reader.ReadString('\n'); err != nil {
return fmt.Errorf("read error during stream opened ack: %v", err)
}
log.Printf("New download stream took: %v", time.Since(start))
// Send size to download
sizeStr := fmt.Sprintf("%d\n", cOpts.size)
if _, err = sd.Write([]byte(sizeStr)); err != nil {
return fmt.Errorf("write size error during download: %v", err)
}
start = time.Now()
if _, err = io.ReadAll(sd); err != nil {
return err
}
log.Printf("Data (%d bytes) download took: %v", cOpts.size, time.Since(start))
sd.Close()
return nil
}
func runClient(ctx context.Context, gOpts *globalOpts, cOpts *clientOpts) error {
h, err := createClientHost(ctx, gOpts)
if err != nil {
return fmt.Errorf("client host creation failed: %v", err)
}
log.Println("Local peerID:", h.ID().String())
peerid, err := addDestToPeerstore(h, cOpts.dest)
if err != nil {
return err
}
requestList := strings.Split(cOpts.request, ",")
for i, request := range requestList {
requestList[i] = strings.TrimSpace(request)
}
for {
log.Printf("Playing request list: %q", requestList)
start := time.Now()
for _, request := range requestList {
switch request {
case pingRequestType:
err = ping(ctx, h, peerid)
case uploadRequestType:
err = upload(ctx, h, peerid, cOpts)
case downloadRequestType:
err = download(ctx, h, peerid, cOpts)
}
if err != nil {
return err
}
}
log.Printf("Playing request list took: %v", time.Since(start))
if cOpts.reco {
cOpts.reco = false
reader := bufio.NewReader(os.Stdin)
fmt.Printf("%s Reconnection test: switch connection then press enter... ", time.Now().Format("2006/01/02 15:04:05"))
_, _ = reader.ReadString('\n')
log.Print("Reconnection test: replay request list using new connection")
continue
}
break
}
return nil
}
================================================
FILE: tool/bench-cellular/go.mod
================================================
module berty.tech/weshnet/tool/bench-cellular
go 1.15
require (
github.com/ipfs/go-log v1.0.4
github.com/libp2p/go-libp2p v0.13.0
github.com/libp2p/go-libp2p/core v0.8.0
github.com/libp2p/go-libp2p-kad-dht v0.11.1
github.com/libp2p/go-libp2p-peer v0.2.0
github.com/libp2p/go-libp2p-peerstore v0.2.6
github.com/libp2p/go-libp2p-quic-transport v0.10.0
github.com/libp2p/go-libp2p-routing v0.1.0
github.com/libp2p/go-tcp-transport v0.2.1
github.com/multiformats/go-multiaddr v0.3.1
github.com/peterbourgon/ff/v3 v3.0.0
)
================================================
FILE: tool/bench-cellular/go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0=
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg=
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=
github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=
github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0=
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=
github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=
github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=
github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc=
github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8=
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s=
github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo=
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U=
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=
github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=
github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=
github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug=
github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk=
github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=
github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=
github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk=
github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=
github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=
github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=
github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc=
github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA=
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=
github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=
github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
github.com/libp2p/go-libp2p-core v0.8.0 h1:5K3mT+64qDTKbV3yTdbMCzJ7O6wbNsavAEb8iqBvBcI=
github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ=
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc=
github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=
github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70=
github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk=
github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw=
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRhPwSMGpQ=
github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=
github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U=
github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0=
github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA=
github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0=
github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=
github.com/libp2p/go-libp2p-routing v0.1.0 h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU=
github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE=
github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=
github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=
github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=
github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA=
github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw=
github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ=
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0=
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI=
github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s=
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=
github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po=
github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0=
github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4=
github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=
github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU=
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA=
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=
github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
github.com/libp2p/go-netroute v0.1.3 h1:1ngWRx61us/EpaKkdqkMjKk/ufr/JlIFYQAxV2XX8Ig=
github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=
github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM=
github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw=
github.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q=
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=
github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=
github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=
github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=
github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=
github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=
github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns=
github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M=
github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k=
github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA=
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU=
github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U=
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4=
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I=
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=
github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=
github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk=
github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU=
github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/peterbourgon/ff/v3 v3.0.0 h1:eQzEmNahuOjQXfuegsKQTSTDbf4dNvr/eNLrmJhiH7M=
github.com/peterbourgon/ff/v3 v3.0.0/go.mod h1:UILIFjRH5a/ar8TjXYLTkIvSvekZqPm5Eb/qbGk6CT0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=
github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
================================================
FILE: tool/bench-cellular/server.go
================================================
package main
import (
"bufio"
"context"
"fmt"
"io"
"log"
"math/rand"
"strconv"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
routing "github.com/libp2p/go-libp2p-routing"
"github.com/libp2p/go-libp2p/core/event"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
var tcpBertyRelays = []string{
"/ip4/51.159.21.214/tcp/4040/p2p/QmdT7AmhhnbuwvCpa5PH1ySK9HJVB82jr3fo1bxMxBPW6p",
"/ip4/51.15.25.224/tcp/4040/p2p/12D3KooWHhDBv6DJJ4XDWjzEXq6sVNEs6VuxsV1WyBBEhPENHzcZ",
}
var quicBertyRelays = []string{
"/ip4/51.159.21.214/udp/4040/quic/p2p/QmdT7AmhhnbuwvCpa5PH1ySK9HJVB82jr3fo1bxMxBPW6p",
"/ip4/51.15.25.224/udp/4040/quic/p2p/12D3KooWHhDBv6DJJ4XDWjzEXq6sVNEs6VuxsV1WyBBEhPENHzcZ",
}
var tcpIPFSRelays = []string{
"/ip4/147.75.80.110/tcp/4001/p2p/QmbFgm5zan8P6eWWmeyfncR5feYEMPbht5b1FW1C37aQ7y",
"/ip4/147.75.195.153/tcp/4001/p2p/QmW9m57aiBDHAkKj9nmFSEn7ZqrcF1fZS4bipsTCHburei",
"/ip4/147.75.70.221/tcp/4001/p2p/Qme8g49gm3q4Acp7xWBKg3nAa9fxZ1YmyDJdyGgoG6LsXh",
}
var quicIPFSRelays = []string{
"/ip4/147.75.80.110/udp/4001/quic/p2p/QmbFgm5zan8P6eWWmeyfncR5feYEMPbht5b1FW1C37aQ7y",
"/ip4/147.75.195.153/udp/4001/quic/p2p/QmW9m57aiBDHAkKj9nmFSEn7ZqrcF1fZS4bipsTCHburei",
"/ip4/147.75.70.221/udp/4001/quic/p2p/Qme8g49gm3q4Acp7xWBKg3nAa9fxZ1YmyDJdyGgoG6LsXh",
}
const (
staticBertyRelayMode = "static-berty"
staticIPFSRelayMode = "static-ipfs"
discoveryRelayMode = "discovery"
disabledRelayMode = "none"
)
type serverOpts struct {
port int
ip6 bool
relay string
}
func createServerHost(ctx context.Context, gOpts *globalOpts, sOpts *serverOpts) (host.Host, error) {
opts, err := globalOptsToLibp2pOpts(gOpts) // Get identity and transport
if err != nil {
return nil, err
}
if sOpts.relay == disabledRelayMode { // If no relay, add relevant listener
if sOpts.ip6 {
if gOpts.tcp {
opts = append(opts, libp2p.ListenAddrStrings(fmt.Sprintf("/ip6/::/tcp/%d", sOpts.port)))
} else {
opts = append(opts, libp2p.ListenAddrStrings(fmt.Sprintf("/ip6/::/udp/%d/quic", sOpts.port)))
}
} else {
if gOpts.tcp {
opts = append(opts, libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", sOpts.port)))
} else {
opts = append(opts, libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic", sOpts.port)))
}
}
opts = append(opts, libp2p.NATPortMap()) // Open port on NAT for access through public IP
opts = append(opts, libp2p.DisableRelay())
} else {
opts = append(opts, libp2p.ListenAddrs()) // If using relay, set no listener
opts = append(opts, libp2p.EnableAutoRelay())
opts = append(opts, libp2p.ForceReachabilityPrivate())
}
// Relay discovery needs DHT routing to discover relays
// NATPortMap (relay disabled) needs DHT routing to get host public IP
if sOpts.relay == discoveryRelayMode || sOpts.relay == disabledRelayMode {
opts = append(
opts,
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
return dht.New(ctx, h, dht.Mode(dht.ModeClient), dht.BootstrapPeers(dht.GetDefaultBootstrapPeerAddrInfos()...))
}),
)
} else { // Or setup Berty / IPFS static relays
var (
maddrRelays []string
staticRelays []peer.AddrInfo
)
if sOpts.relay == staticBertyRelayMode {
if gOpts.tcp {
maddrRelays = tcpBertyRelays
} else {
maddrRelays = quicBertyRelays
}
} else {
if gOpts.tcp {
maddrRelays = tcpIPFSRelays
} else {
maddrRelays = quicIPFSRelays
}
}
for _, addr := range maddrRelays {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
log.Printf("error: can't parse Multiaddr: %v\n", err)
continue
}
pi, err := peer.AddrInfoFromP2pAddr(maddr)
if err != nil {
log.Printf("error: can't parse AddrInfo: %v\n", err)
continue
}
staticRelays = append(staticRelays, *pi)
}
opts = append(opts, libp2p.StaticRelays(staticRelays))
}
return libp2p.New(ctx, opts...) // Create host
}
func printHint(h host.Host, gOpts *globalOpts, sOpts *serverOpts) {
var serverAddr ma.Multiaddr
if sOpts.relay == disabledRelayMode {
log.Print("Waiting for public address...")
} else {
log.Print("Waiting for relay address...")
}
eventReceiver, err := h.EventBus().Subscribe(new(event.EvtLocalAddressesUpdated))
if err != nil {
log.Fatalf("can't subscribe to local addresses updated events: %v", err)
}
defer eventReceiver.Close()
for ev := range eventReceiver.Out() {
serverAddr = nil
update := ev.(event.EvtLocalAddressesUpdated)
for _, addr := range update.Current {
if addr.Action != event.Added {
continue
}
if sOpts.relay != disabledRelayMode {
if _, err := addr.Address.ValueForProtocol(ma.P_CIRCUIT); err != nil {
continue
}
if gOpts.tcp {
if _, err := addr.Address.ValueForProtocol(ma.P_TCP); err != nil {
continue
}
serverAddr = addr.Address
} else {
if _, err := addr.Address.ValueForProtocol(ma.P_QUIC); err != nil {
continue
}
serverAddr = addr.Address
}
} else if sOpts.ip6 {
if _, err := addr.Address.ValueForProtocol(ma.P_IP6); err != nil {
continue
}
if manet.IsPublicAddr(addr.Address) {
serverAddr = addr.Address
}
} else {
if _, err := addr.Address.ValueForProtocol(ma.P_IP4); err != nil {
continue
}
if manet.IsPublicAddr(addr.Address) {
serverAddr = addr.Address
}
}
}
if serverAddr != nil {
hostAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", h.ID().String()))
if err != nil {
panic(err)
}
fullAddr := serverAddr.Encapsulate(hostAddr)
hint := "Now run: './bench"
if gOpts.insecure {
hint += " -insecure"
}
if gOpts.tcp {
hint += " -tcp"
}
hint += fmt.Sprintf(" client -dest %s [-request ...] [-size X] [-reco]'", fullAddr)
log.Println(hint)
}
}
}
func runServer(ctx context.Context, gOpts *globalOpts, sOpts *serverOpts) error {
h, err := createServerHost(ctx, gOpts, sOpts)
if err != nil {
return fmt.Errorf("server host creation failed: %v", err)
}
go printHint(h, gOpts, sOpts)
h.SetStreamHandler(benchDownloadPID, func(s network.Stream) {
defer s.Close()
remotePeerID := s.Conn().RemotePeer().String()
log.Printf("New download stream from: %s\n", remotePeerID)
_, err := s.Write([]byte("\n"))
if err != nil {
log.Printf("Write error during stream opened ack to %s: %v\n", remotePeerID, err)
}
buf := bufio.NewReader(s)
str, err := buf.ReadString('\n')
if err != nil {
log.Printf("Read error during download from %s: %v\n", remotePeerID, err)
return
}
size, err := strconv.Atoi(string(str[:len(str)-1]))
if err != nil {
log.Printf("Invalid size received: %s: %v", str, err)
return
}
data := make([]byte, size)
rand.Read(data)
_, err = s.Write(data)
if err != nil {
log.Printf("Write error during download to %s: %v\n", remotePeerID, err)
}
log.Printf("Sent %d bytes to %s", len(data), remotePeerID)
})
h.SetStreamHandler(benchUploadPID, func(s network.Stream) {
defer s.Close()
remotePeerID := s.Conn().RemotePeer().String()
log.Printf("New upload stream from: %s\n", remotePeerID)
_, err := s.Write([]byte("\n"))
if err != nil {
log.Printf("Write error during stream opened ack to %s: %v\n", remotePeerID, err)
}
reader := bufio.NewReader(s)
data, err := io.ReadAll(reader)
if err != nil {
log.Printf("Read error during upload from %s: %v\n", remotePeerID, err)
return
}
log.Printf("Received %d bytes from %s", len(data), remotePeerID)
_, err = s.Write([]byte("\n"))
if err != nil {
log.Printf("Write error during uploaded ack to %s: %v\n", remotePeerID, err)
}
})
select {}
}
================================================
FILE: tool/docker-protoc/Dockerfile
================================================
FROM moul/protoc-gen-gotemplate:latest as pgg
# build image
FROM golang:1.22-alpine as builder
# install deps
RUN apk --no-cache add make git go rsync libc-dev openssh docker npm bash curl
# ensure we use bash for all RUN commands
SHELL ["/bin/bash", "-c"]
RUN git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.12.0 && \
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
# install compilers
WORKDIR $GOPATH/src/berty.tech/weshnet
COPY go.mod go.sum .tool-versions ./
# ensure modifications to bashrc are properly sourced
ENV BASH_ENV=~/.bashrc
# @TODO(gfanton): use asdf version
RUN go install -mod=readonly \
google.golang.org/protobuf/cmd/protoc-gen-go \
github.com/srikrsna/protoc-gen-gotag \
google.golang.org/grpc/cmd/protoc-gen-go-grpc \
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger \
github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc \
golang.org/x/tools/cmd/goimports
RUN asdf plugin add buf && asdf install buf && \
cp $(asdf which buf) /go/bin/buf
# runtime
FROM golang:1.22-alpine
RUN apk --no-cache add git openssh make protobuf gcc libc-dev nodejs npm yarn sudo perl-utils tar sed grep \
&& mkdir -p /.cache/go-build \
&& chmod -R 777 /.cache \
&& npm install -g eclint
COPY --from=pgg /go/bin/* /go/bin/
COPY --from=builder /go/bin/* /go/bin/
COPY --from=pgg /protobuf /protobuf
ENV GOPATH=/go \
PATH=/go/bin:/node/node_modules/.bin:${PATH} \
GOROOT=/usr/local/go
================================================
FILE: tool/docker-protoc/Makefile
================================================
IMAGE ?= bertytech/buf
VERSION ?= 5
build:
cd ../../ && docker build -f ./tool/docker-protoc/Dockerfile -t $(IMAGE):$(VERSION) -t $(IMAGE):latest .
publish: build
docker push $(IMAGE):$(VERSION)
docker push $(IMAGE):latest
================================================
FILE: tyber.go
================================================
package weshnet
const (
TyberEventTinderPeerFound = "Tinder peer found"
TyberEventTinderPeerJoined = "Tinder peer joined"
TyberEventTinderPeerLeft = "Tinder peer left"
)