From 8686c0afdfdb33650f8fb3d2405bbd8491a60cbc Mon Sep 17 00:00:00 2001 From: muji Date: Fri, 21 Jun 2024 10:18:03 +0800 Subject: [PATCH] Move sos-server to it's own crate (#460) * Refactor to server crate. * Move binary file to sos-server crate. * Update doc comments. * Remove sos-server binary from the sos crate. * Update doc comments. * Remove server module from the sos-net crate. * Remove obsolete convert command module. * Add AGPL license file, update README. * Include AGPL license file. * Use shared sos-protocol crate. * Move protocol files up a level. * Fix search feature in sos-protocol. Was causing the tests to fail. * Remove obsolete test-utils feature. * Tidy features and dependencies. * Flatten structure in sos-net crate. * Update Dockerfile. * Flatten structure in server crate. * Tweak doc comment. * Move sos binary to crate. * Bump minor version. * Completely remove the device feature. Multiple devices are intrinsic to much of the logic so trying to put device support behind a feature flag was too cumbersome. * Fixing handling of files feature. * Improving feature handling. * Fix handling of files feature. * Bump patch version. * Add release plz workflow. * Update .gitignore. * Using release-plz changelogs. --- .github/workflows/publish.yml | 11 +- .github/workflows/release-plz.yml | 27 + .gitignore | 1 - CHANGELOG.md | 889 ++++++++++++++++++ Cargo.lock | 205 ++-- Cargo.toml | 92 +- Dockerfile | 7 +- LICENSE-AGPL | 661 +++++++++++++ README.md | 2 +- crates/artifact/CHANGELOG.md | 12 + crates/artifact/Cargo.toml | 2 +- crates/cli_helpers/Cargo.toml | 13 + crates/cli_helpers/src/lib.rs | 21 + .../cli_helpers/src}/messages.rs | 4 +- crates/keychain_parser/CHANGELOG.md | 13 + crates/keychain_parser/Cargo.toml | 2 +- crates/net/Cargo.toml | 80 +- crates/net/build.rs | 21 - .../src/{client => }/account/auto_merge.rs | 42 +- .../account/file_transfers/inflight.rs | 4 +- .../account/file_transfers/mod.rs | 5 +- .../account/file_transfers/operations.rs | 3 +- crates/net/src/{client => }/account/listen.rs | 10 +- crates/net/src/{client => }/account/mod.rs | 0 .../{client => }/account/network_account.rs | 60 +- crates/net/src/{client => }/account/remote.rs | 31 +- crates/net/src/{client => }/account/sync.rs | 21 +- crates/net/src/client/error.rs | 223 ----- crates/net/src/client/mod.rs | 99 -- crates/net/src/error.rs | 205 +++- crates/net/src/{client => }/hashcheck.rs | 0 crates/net/src/lib.rs | 112 ++- crates/net/src/{client => }/net/http.rs | 32 +- crates/net/src/{client => }/net/mod.rs | 2 +- crates/net/src/{client => }/net/websocket.rs | 7 +- .../src/{client => }/pairing/enrollment.rs | 11 +- crates/net/src/{client => }/pairing/error.rs | 8 +- crates/net/src/{client => }/pairing/mod.rs | 0 .../net/src/{client => }/pairing/share_url.rs | 0 .../net/src/{client => }/pairing/websocket.rs | 14 +- crates/net/src/server/mod.rs | 17 - crates/net/src/{client => }/sync.rs | 21 +- crates/protocol/Cargo.toml | 44 + crates/protocol/build.rs | 33 + .../src}/bindings/common.rs | 9 +- .../src}/bindings/diff.rs | 2 +- .../src}/bindings/files.rs | 7 +- .../protocol => protocol/src}/bindings/mod.rs | 3 +- .../src}/bindings/notifications.rs | 2 +- .../src}/bindings/patch.rs | 2 +- .../src}/bindings/relay.rs | 13 +- .../src}/bindings/scan.rs | 3 +- .../src}/bindings/sync.rs | 38 +- .../src/protocol => protocol/src}/error.rs | 0 .../protocol/mod.rs => protocol/src/lib.rs} | 23 +- .../src}/protobuf/common.proto | 0 .../src}/protobuf/diff.proto | 0 .../src}/protobuf/files.proto | 0 .../src}/protobuf/notifications.proto | 0 .../src}/protobuf/patch.proto | 0 .../src}/protobuf/relay.proto | 0 .../src}/protobuf/scan.proto | 0 .../src}/protobuf/sync.proto | 0 .../protocol => protocol/src}/sync/folder.rs | 10 +- .../src}/sync/local_account.rs | 19 +- .../src/protocol => protocol/src}/sync/mod.rs | 0 .../src}/sync/primitives.rs | 34 +- .../src}/sync/transfer.rs | 0 .../src}/sync/transport.rs | 11 +- crates/{net => protocol}/src/tests/mod.rs | 0 .../{net => protocol}/src/tests/protocol.rs | 18 +- crates/sdk/Cargo.toml | 9 +- crates/sdk/src/account/account.rs | 40 +- crates/sdk/src/account/sync.rs | 7 - crates/sdk/src/encoding/v1/events.rs | 3 - crates/sdk/src/events/log/file.rs | 3 - crates/sdk/src/events/log/mod.rs | 13 +- crates/sdk/src/events/log/patch.rs | 3 - crates/sdk/src/events/log/reducer.rs | 2 - crates/sdk/src/events/mod.rs | 3 - crates/sdk/src/identity/identity.rs | 3 - crates/sdk/src/identity/identity_folder.rs | 12 - crates/sdk/src/lib.rs | 2 - crates/sdk/src/prelude.rs | 1 - crates/sdk/src/storage/client.rs | 22 +- crates/sdk/src/storage/mod.rs | 2 - crates/server/Cargo.toml | 61 ++ crates/server/build.rs | 12 + .../src/server => server/src}/api_docs.rs | 16 +- .../src/server => server/src}/authenticate.rs | 2 +- .../{net/src/server => server/src}/backend.rs | 6 +- .../{net/src/server => server/src}/config.rs | 2 +- .../{net/src/server => server/src}/error.rs | 20 +- .../server => server/src}/handlers/account.rs | 52 +- .../server => server/src}/handlers/files.rs | 32 +- .../src/server => server/src}/handlers/mod.rs | 18 +- .../server => server/src}/handlers/relay.rs | 2 +- .../src}/handlers/websocket.rs | 4 +- crates/server/src/lib.rs | 31 + crates/server/src/main.rs | 126 +++ .../{net/src/server => server/src}/server.rs | 71 +- .../src}/storage/filesystem/mod.rs | 27 +- .../src}/storage/filesystem/sync.rs | 26 +- .../src/server => server/src}/storage/mod.rs | 0 crates/sos/Cargo.toml | 57 ++ crates/sos/src/cli/mod.rs | 1 + {src => crates/sos/src}/cli/sos.rs | 0 {src => crates/sos/src}/commands/account.rs | 2 +- {src => crates/sos/src}/commands/audit.rs | 0 {src => crates/sos/src}/commands/changes.rs | 0 {src => crates/sos/src}/commands/check.rs | 0 {src => crates/sos/src}/commands/device.rs | 2 +- .../sos/src}/commands/environment.rs | 0 {src => crates/sos/src}/commands/events.rs | 0 {src => crates/sos/src}/commands/folder.rs | 0 {src => crates/sos/src}/commands/mod.rs | 0 .../sos/src}/commands/preferences.rs | 0 {src => crates/sos/src}/commands/secret.rs | 0 .../sos/src}/commands/security_report.rs | 2 +- {src => crates/sos/src}/commands/server.rs | 4 +- {src => crates/sos/src}/commands/shell/cli.rs | 2 +- {src => crates/sos/src}/commands/shell/mod.rs | 0 .../sos/src}/commands/shell/repl.rs | 0 .../sos/src}/commands/shell/welcome.txt | 0 {src => crates/sos/src}/commands/sync.rs | 4 +- {src => crates/sos/src}/commands/tools.rs | 0 {src => crates/sos/src}/error.rs | 13 +- {src => crates/sos/src}/helpers/account.rs | 2 +- {src => crates/sos/src}/helpers/editor.rs | 0 {src => crates/sos/src}/helpers/mod.rs | 3 +- {src => crates/sos/src}/helpers/readline.rs | 0 {src => crates/sos/src}/helpers/secret.rs | 0 {src => crates/sos/src}/lib.rs | 28 +- src/bin/sos.rs => crates/sos/src/main.rs | 3 +- crates/test_utils/Cargo.toml | 1 + crates/test_utils/src/lib.rs | 5 +- crates/test_utils/src/network.rs | 8 +- crates/test_utils/src/pairing.rs | 6 +- crates/vfs/CHANGELOG.md | 13 + crates/vfs/Cargo.toml | 2 +- scripts/ci/prepare-executables.sh | 2 +- src/bin/sos_server.rs | 23 - src/cli/mod.rs | 2 - src/cli/sos_server.rs | 104 -- src/commands/convert.rs | 83 -- tests/access_control/allow.rs | 8 +- tests/access_control/deny.rs | 8 +- tests/auto_merge/create_secrets.rs | 2 +- tests/auto_merge/delete_secrets.rs | 2 +- tests/auto_merge/edit_secrets.rs | 2 +- tests/auto_merge/scan_commits.rs | 3 +- tests/diff_merge/folder_create.rs | 2 +- tests/diff_merge/folder_delete.rs | 2 +- tests/diff_merge/folder_import.rs | 2 +- tests/diff_merge/folder_rename.rs | 2 +- tests/diff_merge/secret_create.rs | 2 +- tests/diff_merge/secret_delete.rs | 2 +- tests/diff_merge/secret_move.rs | 2 +- tests/diff_merge/secret_update.rs | 2 +- tests/file_transfers/multi_server.rs | 2 +- tests/file_transfers/offline_multi.rs | 2 +- tests/file_transfers/single_server.rs | 2 +- tests/network_account/archive_unarchive.rs | 2 +- .../change_account_password.rs | 2 +- tests/network_account/change_cipher.rs | 2 +- .../network_account/change_folder_password.rs | 2 +- tests/network_account/compact_account.rs | 2 +- tests/network_account/compact_folder.rs | 2 +- tests/network_account/delete_account.rs | 2 +- tests/network_account/multiple_remotes.rs | 2 +- .../multiple_remotes_fallback.rs | 5 +- tests/network_account/offline_manual.rs | 2 +- tests/network_account/rename_account.rs | 2 +- tests/network_account/send_secret_create.rs | 2 +- tests/network_account/send_secret_move.rs | 2 +- tests/network_account/websocket_reconnect.rs | 5 +- .../websocket_shutdown_explicit.rs | 2 +- .../websocket_shutdown_signout.rs | 2 +- tests/pairing/device_revoke.rs | 5 +- tests/pairing/pairing_account_name.rs | 2 +- tests/pairing/pairing_inverted.rs | 2 +- tests/pairing/pairing_protocol.rs | 2 +- tests/pairing/pairing_websocket_shutdown.rs | 2 +- 183 files changed, 2892 insertions(+), 1472 deletions(-) create mode 100644 .github/workflows/release-plz.yml create mode 100644 CHANGELOG.md create mode 100644 LICENSE-AGPL create mode 100644 crates/artifact/CHANGELOG.md create mode 100644 crates/cli_helpers/Cargo.toml create mode 100644 crates/cli_helpers/src/lib.rs rename {src/helpers => crates/cli_helpers/src}/messages.rs (92%) create mode 100644 crates/keychain_parser/CHANGELOG.md rename crates/net/src/{client => }/account/auto_merge.rs (96%) rename crates/net/src/{client => }/account/file_transfers/inflight.rs (98%) rename crates/net/src/{client => }/account/file_transfers/mod.rs (99%) rename crates/net/src/{client => }/account/file_transfers/operations.rs (99%) rename crates/net/src/{client => }/account/listen.rs (96%) rename crates/net/src/{client => }/account/mod.rs (100%) rename crates/net/src/{client => }/account/network_account.rs (97%) rename crates/net/src/{client => }/account/remote.rs (94%) rename crates/net/src/{client => }/account/sync.rs (93%) delete mode 100644 crates/net/src/client/error.rs delete mode 100644 crates/net/src/client/mod.rs rename crates/net/src/{client => }/hashcheck.rs (100%) rename crates/net/src/{client => }/net/http.rs (97%) rename crates/net/src/{client => }/net/mod.rs (99%) rename crates/net/src/{client => }/net/websocket.rs (98%) rename crates/net/src/{client => }/pairing/enrollment.rs (97%) rename crates/net/src/{client => }/pairing/error.rs (94%) rename crates/net/src/{client => }/pairing/mod.rs (100%) rename crates/net/src/{client => }/pairing/share_url.rs (100%) rename crates/net/src/{client => }/pairing/websocket.rs (99%) delete mode 100644 crates/net/src/server/mod.rs rename crates/net/src/{client => }/sync.rs (89%) create mode 100644 crates/protocol/Cargo.toml create mode 100644 crates/protocol/build.rs rename crates/{net/src/protocol => protocol/src}/bindings/common.rs (97%) rename crates/{net/src/protocol => protocol/src}/bindings/diff.rs (97%) rename crates/{net/src/protocol => protocol/src}/bindings/files.rs (94%) rename crates/{net/src/protocol => protocol/src}/bindings/mod.rs (94%) rename crates/{net/src/protocol => protocol/src}/bindings/notifications.rs (96%) rename crates/{net/src/protocol => protocol/src}/bindings/patch.rs (97%) rename crates/{net/src/protocol => protocol/src}/bindings/relay.rs (89%) rename crates/{net/src/protocol => protocol/src}/bindings/scan.rs (96%) rename crates/{net/src/protocol => protocol/src}/bindings/sync.rs (92%) rename crates/{net/src/protocol => protocol/src}/error.rs (100%) rename crates/{net/src/protocol/mod.rs => protocol/src/lib.rs} (87%) rename crates/{net/src/protocol => protocol/src}/protobuf/common.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/diff.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/files.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/notifications.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/patch.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/relay.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/scan.proto (100%) rename crates/{net/src/protocol => protocol/src}/protobuf/sync.proto (100%) rename crates/{net/src/protocol => protocol/src}/sync/folder.rs (96%) rename crates/{net/src/protocol => protocol/src}/sync/local_account.rs (97%) rename crates/{net/src/protocol => protocol/src}/sync/mod.rs (100%) rename crates/{net/src/protocol => protocol/src}/sync/primitives.rs (97%) rename crates/{net/src/protocol => protocol/src}/sync/transfer.rs (100%) rename crates/{net/src/protocol => protocol/src}/sync/transport.rs (96%) rename crates/{net => protocol}/src/tests/mod.rs (100%) rename crates/{net => protocol}/src/tests/protocol.rs (96%) create mode 100644 crates/server/Cargo.toml create mode 100644 crates/server/build.rs rename crates/{net/src/server => server/src}/api_docs.rs (87%) rename crates/{net/src/server => server/src}/authenticate.rs (98%) rename crates/{net/src/server => server/src}/backend.rs (98%) rename crates/{net/src/server => server/src}/config.rs (98%) rename crates/{net/src/server => server/src}/error.rs (93%) rename crates/{net/src/server => server/src}/handlers/account.rs (97%) rename crates/{net/src/server => server/src}/handlers/files.rs (97%) rename crates/{net/src/server => server/src}/handlers/mod.rs (95%) rename crates/{net/src/server => server/src}/handlers/relay.rs (98%) rename crates/{net/src/server => server/src}/handlers/websocket.rs (98%) create mode 100644 crates/server/src/lib.rs create mode 100644 crates/server/src/main.rs rename crates/{net/src/server => server/src}/server.rs (85%) rename crates/{net/src/server => server/src}/storage/filesystem/mod.rs (95%) rename crates/{net/src/server => server/src}/storage/filesystem/sync.rs (97%) rename crates/{net/src/server => server/src}/storage/mod.rs (100%) create mode 100644 crates/sos/Cargo.toml create mode 100644 crates/sos/src/cli/mod.rs rename {src => crates/sos/src}/cli/sos.rs (100%) rename {src => crates/sos/src}/commands/account.rs (99%) rename {src => crates/sos/src}/commands/audit.rs (100%) rename {src => crates/sos/src}/commands/changes.rs (100%) rename {src => crates/sos/src}/commands/check.rs (100%) rename {src => crates/sos/src}/commands/device.rs (98%) rename {src => crates/sos/src}/commands/environment.rs (100%) rename {src => crates/sos/src}/commands/events.rs (100%) rename {src => crates/sos/src}/commands/folder.rs (100%) rename {src => crates/sos/src}/commands/mod.rs (100%) rename {src => crates/sos/src}/commands/preferences.rs (100%) rename {src => crates/sos/src}/commands/secret.rs (100%) rename {src => crates/sos/src}/commands/security_report.rs (99%) rename {src => crates/sos/src}/commands/server.rs (97%) rename {src => crates/sos/src}/commands/shell/cli.rs (99%) rename {src => crates/sos/src}/commands/shell/mod.rs (100%) rename {src => crates/sos/src}/commands/shell/repl.rs (100%) rename {src => crates/sos/src}/commands/shell/welcome.txt (100%) rename {src => crates/sos/src}/commands/sync.rs (98%) rename {src => crates/sos/src}/commands/tools.rs (100%) rename {src => crates/sos/src}/error.rs (95%) rename {src => crates/sos/src}/helpers/account.rs (99%) rename {src => crates/sos/src}/helpers/editor.rs (100%) rename {src => crates/sos/src}/helpers/mod.rs (97%) rename {src => crates/sos/src}/helpers/readline.rs (100%) rename {src => crates/sos/src}/helpers/secret.rs (100%) rename {src => crates/sos/src}/lib.rs (51%) rename src/bin/sos.rs => crates/sos/src/main.rs (91%) create mode 100644 crates/vfs/CHANGELOG.md delete mode 100644 src/bin/sos_server.rs delete mode 100644 src/cli/mod.rs delete mode 100644 src/cli/sos_server.rs delete mode 100644 src/commands/convert.rs diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d3e6464253..a9da281e06 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -93,13 +93,20 @@ jobs: rustup update stable rustup target add ${{ matrix.binary_target }} - # Build - - name: Build binaries + # Build client + - name: Build client binary uses: actions-rs/cargo@v1 with: command: build args: --release --locked --target ${{ matrix.binary_target }} + # Build server + - name: Build server binary + uses: actions-rs/cargo@v1 + with: + command: build + args: -p sos-server --release --locked --target ${{ matrix.binary_target }} + - name: Gather executables shell: bash run: | diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml new file mode 100644 index 0000000000..a24f31b198 --- /dev/null +++ b/.github/workflows/release-plz.yml @@ -0,0 +1,27 @@ +name: Release Plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - main + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.gitignore b/.gitignore index 9c7c425e43..c566e8a5b8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ target *.bak *.profraw -*.pem *.deb *.buildinfo *.changes diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..0e69dda3b6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,889 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.14.1](https://github.com/saveoursecrets/sdk/releases/tag/sos-workspace-v0.14.1) - 2024-06-21 + +### Other +- Update .gitignore. +- Add release plz workflow. +- Bump patch version. +- Fix handling of files feature. +- Improving feature handling. +- Fixing handling of files feature. +- Completely remove the device feature. +- Bump minor version. +- Move sos binary to crate. +- Tweak doc comment. +- Flatten structure in server crate. +- Update Dockerfile. +- Flatten structure in sos-net crate. +- Tidy features and dependencies. +- Remove obsolete test-utils feature. +- Fix search feature in sos-protocol. +- Move protocol files up a level. +- Use shared sos-protocol crate. +- Include AGPL license file. +- Add AGPL license file, update README. +- Remove obsolete convert command module. +- Remove server module from the sos-net crate. +- Update doc comments. +- Remove sos-server binary from the sos crate. +- Update doc comments. +- Move binary file to sos-server crate. +- Refactor to server crate. +- Ignore failing tests on windows (see [#451](https://github.com/saveoursecrets/sdk/pull/451)) ([#456](https://github.com/saveoursecrets/sdk/pull/456)) +- Disable windows checks in CI for file guard bug. +- Use protocol buffers for wire protocol ([#450](https://github.com/saveoursecrets/sdk/pull/450)) +- Automerge on soft conflict ([#448](https://github.com/saveoursecrets/sdk/pull/448)) +- No comment on saved account password. +- Fix for crate Contents re-export. +- Disable Linux CI checks for now. +- Bump patch version. +- Support updating servers origin information. +- Support server account deletion ([#443](https://github.com/saveoursecrets/sdk/pull/443)) +- Verify device signature for sync status ([#442](https://github.com/saveoursecrets/sdk/pull/442)) +- Expose transfer_status() ([#441](https://github.com/saveoursecrets/sdk/pull/441)) +- Improve integrity checks ([#439](https://github.com/saveoursecrets/sdk/pull/439)) +- Bump tokio-tungstenite. +- Transfer cancellation and notifications ([#432](https://github.com/saveoursecrets/sdk/pull/432)) +- Bump patch version. +- File transfer improvements ([#431](https://github.com/saveoursecrets/sdk/pull/431)) +- Implement account-level file locking ([#429](https://github.com/saveoursecrets/sdk/pull/429)) +- Sync all servers on new device enrollment ([#427](https://github.com/saveoursecrets/sdk/pull/427)) +- Send websocket notifications with sync error result ([#422](https://github.com/saveoursecrets/sdk/pull/422)) +- Rename account sync support ([#419](https://github.com/saveoursecrets/sdk/pull/419)) +- Use biased select! for file transfers loop. ([#417](https://github.com/saveoursecrets/sdk/pull/417)) +- Update test spec for linux CI. +- Bump patch version. +- Update file-guard to fix Windows build issue. +- Remove sleep from file_transfers logic. +- Update timeout for file transfer with debug_assertions. +- Remove span from upload_file. +- Bump patch version. +- Create folder inherits cipher/kdf from identity. ([#410](https://github.com/saveoursecrets/sdk/pull/410)) +- Update reqwest and HTTP client timeouts. +- Bump patch version. +- Optimize release builds for size. +- Tidy unused functions. +- Support setting folder names in account builder. ([#405](https://github.com/saveoursecrets/sdk/pull/405)) +- Import Address type from dependency ([#404](https://github.com/saveoursecrets/sdk/pull/404)) +- Fix statistics for file uploads ([#401](https://github.com/saveoursecrets/sdk/pull/401)) +- Enable aes_armv8 for aarch64-apple-darwin. +- Decouple event log references from sync feature ([#393](https://github.com/saveoursecrets/sdk/pull/393)) +- add social recovery doc ([#234](https://github.com/saveoursecrets/sdk/pull/234)) +- Avoid glob pattern in clean-cli task. ([#392](https://github.com/saveoursecrets/sdk/pull/392)) +- Bump minor version. +- Bump thedoctor0/zip-release from 0.7.1 to 0.7.6 ([#278](https://github.com/saveoursecrets/sdk/pull/278)) +- Bump jaxxstorm/action-install-gh-release from 1.10.0 to 1.11.0 ([#343](https://github.com/saveoursecrets/sdk/pull/343)) +- Bump softprops/action-gh-release from 1 to 2 ([#376](https://github.com/saveoursecrets/sdk/pull/376)) +- Bump sigstore/cosign-installer from 3.1.1 to 3.5.0 ([#384](https://github.com/saveoursecrets/sdk/pull/384)) +- Compact account ([#390](https://github.com/saveoursecrets/sdk/pull/390)) +- Draft security policy file. ([#388](https://github.com/saveoursecrets/sdk/pull/388)) +- Support changing account password ([#386](https://github.com/saveoursecrets/sdk/pull/386)) +- Support changing cipher and set AES-GCM as default cipher ([#383](https://github.com/saveoursecrets/sdk/pull/383)) +- Add generic type for Uuid::as_ref() inference. +- Reqwest upgrade ([#379](https://github.com/saveoursecrets/sdk/pull/379)) +- Set last_modification_date() for zip entries. +- Update async_zip, use BufReader. +- Update plist, which updates line-wrap which fixes safemem. +- Set connect_timeout() on reqwest client. +- Do not call create-invalidation in workflow. +- Update whoami dependency. +- Remove check step from CI. +- Add script_runner to Makefile. +- Only run keychain tests on macos. +- Bump patch version. +- Tidy unused var. +- Support options when sending devices patch ([#369](https://github.com/saveoursecrets/sdk/pull/369)) +- Device vault fix ([#367](https://github.com/saveoursecrets/sdk/pull/367)) +- Remove unused field. +- Fix device key URN handling. +- Generate device key on authenticated side of pairing ([#363](https://github.com/saveoursecrets/sdk/pull/363)) +- Logging module ([#362](https://github.com/saveoursecrets/sdk/pull/362)) +- CLI Demos ([#354](https://github.com/saveoursecrets/sdk/pull/354)) +- CLI test specs ([#349](https://github.com/saveoursecrets/sdk/pull/349)) +- Improve server init command ([#347](https://github.com/saveoursecrets/sdk/pull/347)) +- Support inverted pairing flow ([#342](https://github.com/saveoursecrets/sdk/pull/342)) +- Tidy ShareUrl constructor. +- Prefer concrete type to Self. +- Improve system message counts. +- Move keychain parser code to a crate ([#340](https://github.com/saveoursecrets/sdk/pull/340)) +- Update dependencies ([#339](https://github.com/saveoursecrets/sdk/pull/339)) +- Add sub_title to system messages. +- Include key when sorting system messages. +- Update feature combinator compiler errors. +- Bump patch version. +- Upgrade logos ([#336](https://github.com/saveoursecrets/sdk/pull/336)) +- Update probly-search dependency to 2.0.0. +- Add CachedPreferences::new_account(). +- Only load when file exists. +- System messages channel ([#335](https://github.com/saveoursecrets/sdk/pull/335)) +- Fix numeric handling in preferences. +- System messages implementation ([#332](https://github.com/saveoursecrets/sdk/pull/332)) +- Improve preferences test specs and API. ([#331](https://github.com/saveoursecrets/sdk/pull/331)) +- Tidy tracing on sign out. +- Docker file for the server ([#327](https://github.com/saveoursecrets/sdk/pull/327)) +- Tidy unused imports in relay handler. +- Simplify relay handler. ([#325](https://github.com/saveoursecrets/sdk/pull/325)) +- Expose address in device enrollment. +- Hack for CI failure on Linux ([#323](https://github.com/saveoursecrets/sdk/pull/323)) +- Bump minor version. +- Pairing improvements ([#321](https://github.com/saveoursecrets/sdk/pull/321)) +- Shutdown pairing loop when socket closed. ([#320](https://github.com/saveoursecrets/sdk/pull/320)) +- :enroll_device() is no longer public. +- Tidy unused imports. +- Tidy unused field. +- Remove obsolete type. +- Fix language in docs. +- Tweak language in docs. +- Tweak docs language. +- Device pairing protocol. ([#318](https://github.com/saveoursecrets/sdk/pull/318)) +- Harden device revoke logic. ([#315](https://github.com/saveoursecrets/sdk/pull/315)) +- Prefer IndexSet for trusted devices. ([#313](https://github.com/saveoursecrets/sdk/pull/313)) +- Explicit new resolver for the workspace. +- Read PublicIdentity in DeviceEnrollment. +- Expose address in DeviceEnrollment. +- Improve DeviceShareUrl API. +- Add formal DeviceShareUrl type. +- Update bitflags dependency. ([#308](https://github.com/saveoursecrets/sdk/pull/308)) +- Test spec for preferences API. ([#304](https://github.com/saveoursecrets/sdk/pull/304)) +- Increase timeout in websocket test for CI. +- Update lock file. +- Preferences api ([#302](https://github.com/saveoursecrets/sdk/pull/302)) +- Improve file transfers list output ([#297](https://github.com/saveoursecrets/sdk/pull/297)) +- Add test spec for syncing the file transfers queue. ([#296](https://github.com/saveoursecrets/sdk/pull/296)) +- Show file progress in CLI ([#295](https://github.com/saveoursecrets/sdk/pull/295)) +- Bump human_bytes dependency. +- Update indexmap, use explicit shift_remove(). +- Support file integrity command. ([#294](https://github.com/saveoursecrets/sdk/pull/294)) +- Bump actions/cache from 2 to 4 ([#280](https://github.com/saveoursecrets/sdk/pull/280)) +- Bump actions/checkout from 1 to 4 ([#279](https://github.com/saveoursecrets/sdk/pull/279)) +- Support querying inflight transfers ([#287](https://github.com/saveoursecrets/sdk/pull/287)) +- Deny revoking current device. ([#286](https://github.com/saveoursecrets/sdk/pull/286)) +- Fix for windows checks in CI ([#276](https://github.com/saveoursecrets/sdk/pull/276)) +- Tidy device list command. +- Bump version. +- Move network test specs ([#274](https://github.com/saveoursecrets/sdk/pull/274)) +- Use device signature in websockets ([#273](https://github.com/saveoursecrets/sdk/pull/273)) +- Wait for write lock in file transfers shutdown. ([#272](https://github.com/saveoursecrets/sdk/pull/272)) +- Add access control test specs ([#271](https://github.com/saveoursecrets/sdk/pull/271)) +- Expose sync command when not shell. +- Use self::http for re-export. +- Use self:: for re-export. +- Do not enable keychain-access when migrate feature. +- Update checks workflow. +- Update workflow. +- Update workflow. +- Fix workflows and test-utils dependency. +- Bump versions. +- Self-hosted server sync ([#219](https://github.com/saveoursecrets/sdk/pull/219)) +- Add flatpak to linux distro definition. +- Update mpc-protocol library. ([#217](https://github.com/saveoursecrets/sdk/pull/217)) +- Support notes column for CSV import (Chrome/MacOS/Safari) ([#216](https://github.com/saveoursecrets/sdk/pull/216)) +- Bump patch version. +- Support chrome CSV with note column. +- Remove keyring ([#213](https://github.com/saveoursecrets/sdk/pull/213)) +- Detached view ([#212](https://github.com/saveoursecrets/sdk/pull/212)) +- Fix doc comment. +- Security report improvements ([#211](https://github.com/saveoursecrets/sdk/pull/211)) +- Bump version, update lock file. +- Do not store field index. +- Improve types for security report. +- Bump patch version. +- Tidy security report types. +- Support --include-all option in security-report. +- Bump patch version. +- Security report command ([#210](https://github.com/saveoursecrets/sdk/pull/210)) +- Add cli collection to artifact release info. +- Update libp2p for deprecated members. +- Security report generation ([#209](https://github.com/saveoursecrets/sdk/pull/209)) +- App logs directory ([#207](https://github.com/saveoursecrets/sdk/pull/207)) +- Bump patch version for artifact. +- Support finding meta data by channel. +- Add release meta data. +- Fix release info serde implementation. +- Update README. +- Update lock file. +- Support unknown linux distro. +- Tidy check warnings. +- Run check with --all-features. +- CI checks workflow ([#205](https://github.com/saveoursecrets/sdk/pull/205)) +- Update checks workflow. +- Fix workflow path. +- Update checks workflow. +- Update paths in homebrew workflow. +- Add checks workflow. +- Fix release workflow. +- Update dependencies. +- Ensure version in lock file. +- Add release information. +- Prefer platform in Artifact. +- Improve artifact types, bump minor version. +- Add Arch type. +- Expose constants in artifact package. +- Artifact for iOS is standard artifact. +- Linux distro defaults to debian. +- Re-export semver library. +- Bump patch version. +- Add find_by_distro(). +- Derive debug in releases module. +- Tidy serializing when None. +- Add types for releases information. +- Artifact fields must be public. +- Add types for release artifact meta data. +- Bump patch version. +- Update to Account Password when saving account password. +- Updating dependencies. +- Revert forbid unsafe, expose reqwest. +- Forbid unsafe code. +- Use zeroize feature for totp-rs. +- Bump version for sos-net library. +- Bump version in migrate library. +- Bump minor version. +- Update totp-rs dependency. +- Recovery group types ([#202](https://github.com/saveoursecrets/sdk/pull/202)) +- Refactor patch to use EventRecord not WriteEvent. ([#201](https://github.com/saveoursecrets/sdk/pull/201)) +- Use borrowed buffers for buffer streams. +- Update Compat for stream iterator. +- Expose prelude in SDK, bump patch version. +- Add MIME type constants, bump SDK patch version. +- Tweak doc comment. +- Bump versions. +- Update lock file. +- Do not share version. +- Update dependencies. +- Update ouroboros dependency. +- Update lock file version. +- Bump patch version. +- Update upload and download for distribution channel. ([#199](https://github.com/saveoursecrets/sdk/pull/199)) +- Force push in homebrew workflow. +- Homebrew release workflow ([#198](https://github.com/saveoursecrets/sdk/pull/198)) +- Update changelog. +- Tweak README. +- Update README. +- Tidy Makefile. +- Tidy workflows. +- Tidy workflow, no need to specify shell. +- Fetch release signing public key. +- Include COPYRIGHT in release. +- Split server commands into executables ([#197](https://github.com/saveoursecrets/sdk/pull/197)) +- Cosign workflow integration ([#196](https://github.com/saveoursecrets/sdk/pull/196)) +- Fix env variable name in workflow. +- Disable for sign test. +- Sigstore cosign ([#195](https://github.com/saveoursecrets/sdk/pull/195)) +- Use variant and commit hash in upload. +- Update publish.yaml +- Github release workflow ([#194](https://github.com/saveoursecrets/sdk/pull/194)) +- Update lock file. +- Update dependencies for the executable. +- Update Cargo.toml for publish. +- Remove git dependencies. +- Fix test path assertions for nested debug dir. +- Update conditional reqwest dependency. +- Add debian-dist task using cargo-deb. ([#193](https://github.com/saveoursecrets/sdk/pull/193)) +- Use nested debug folder when debug_assertions. +- Update notes for FileStorageSync hack. +- Revert to sync file encryption. +- Support file progress channel ([#192](https://github.com/saveoursecrets/sdk/pull/192)) +- Handle websocket close frame. +- Noise channel ([#189](https://github.com/saveoursecrets/sdk/pull/189)) +- Support importing a folder from a buffer. +- Remove brew script. +- Remove direct dependency on hyper. +- Update feature flags. +- Tweak coverage ignore pattern. +- Update APP_NAME to change storage location. +- Use max_buffer_size in encoding ([#187](https://github.com/saveoursecrets/sdk/pull/187)) +- Integrate with system keyring ([#185](https://github.com/saveoursecrets/sdk/pull/185)) +- Asymmetric encryption (AGE X25519) ([#184](https://github.com/saveoursecrets/sdk/pull/184)) +- Split into AppDirs and UserDirs ([#182](https://github.com/saveoursecrets/sdk/pull/182)) +- Tidy algorithm enum. +- Tidy key derivation enum. +- Expose kdf() on Summary. +- Support multiple KDFs ([#180](https://github.com/saveoursecrets/sdk/pull/180)) +- Audit trail integration test ([#179](https://github.com/saveoursecrets/sdk/pull/179)) +- Virtual file system for better webassembly integration ([#177](https://github.com/saveoursecrets/sdk/pull/177)) +- Support copy to clipboard in CLI ([#176](https://github.com/saveoursecrets/sdk/pull/176)) +- Fix bug with alt shell sort order. +- Test specs for secret and shell commands ([#174](https://github.com/saveoursecrets/sdk/pull/174)) +- Refactor file content to enum ([#173](https://github.com/saveoursecrets/sdk/pull/173)) +- CLI enhancements ([#159](https://github.com/saveoursecrets/sdk/pull/159)) +- Unify event types ([#158](https://github.com/saveoursecrets/sdk/pull/158)) +- Fix and format. +- Tidy file extension handling. +- Update dependencies. +- Update crypto-bigint. +- Update rustyline dependency. +- Refactor account manager ([#154](https://github.com/saveoursecrets/sdk/pull/154)) +- Support backup/restore in CLI ([#153](https://github.com/saveoursecrets/sdk/pull/153)) +- Peer to peer client and server code plus device signer types ([#149](https://github.com/saveoursecrets/sdk/pull/149)) +- Add NO_SYNC_* flags to VaultFlags. +- Support Ed25519 secret and signer ([#145](https://github.com/saveoursecrets/sdk/pull/145)) +- Integration tests for AccountManager ([#144](https://github.com/saveoursecrets/sdk/pull/144)) +- Move deprecated account functions to integration tests. +- Remove key agent ([#143](https://github.com/saveoursecrets/sdk/pull/143)) +- Remove web3_keystore, update CLI sign in logic ([#140](https://github.com/saveoursecrets/sdk/pull/140)) +- Use checksum of encrypted file data. ([#139](https://github.com/saveoursecrets/sdk/pull/139)) +- Fix archive writer bug. +- Support for large files ([#136](https://github.com/saveoursecrets/sdk/pull/136)) +- Update vcard4 dependency. +- Fix search test spec. +- Search extra fields ([#135](https://github.com/saveoursecrets/sdk/pull/135)) +- Support contact vault flag. +- Add From impl to Timestamp. +- Update vcard dependency. +- Update vcard dependency. +- Tweak language in account manager. +- Update vcard4 dependency. +- Formatting. +- Add SecretFlags to SecretMeta. ([#134](https://github.com/saveoursecrets/sdk/pull/134)) +- Support creating authenticator vault. +- Use struct for new account options. +- Fix for account restore logic. +- Update logic for account restore. +- Use zip for archive format ([#133](https://github.com/saveoursecrets/sdk/pull/133)) +- Formatting. +- Guard against duplicates in search index. +- Add export_archive_file() to AccountManager. +- Expose measure_entropy(). +- Move diceware module to passgen. +- Lazily instantiate diceware wordlist. +- Create diceware config ahead of time. +- Update doc comment. +- Expose diceware via standard password generator. +- Use zxcvbn for password entropy calculation. +- Removed Heading variant, add SecretMeta to Embedded. +- Convert note to comment in migrate import logic. +- Update time and vcard4 dependencies. +- Card expiry date is optional. +- Fix dashlane card expiry parsing. +- Use Timestamp type for card expiry. +- Identity kind ([#131](https://github.com/saveoursecrets/sdk/pull/131)) +- Search index supports pointer to archive vault. +- Rename note field to comment. +- Support creating archive vault in new_account(). +- Add archive vault flag. +- Increase VaultFlags size, upgrade binary-stream. +- Keep count of favorites in search index. +- Set favorite flag on the master passphrase secret. +- Use note for master passphrase signing address. +- Add generic note to UserData. +- Store master passphrase when creating account. +- Update shell client for identification secret. +- Update vcard dependency. +- Add favorite flag to SecretMeta. +- Add find_by_label_any() to SearchIndex. +- Add parse_rfc33939() to Timestamp. +- Basic assertions for dashlane import. +- Do not use time re-export from vcard4. +- Preparing to handle dashlane personalInfo. +- Prepare to handle dashlane payments records. +- Prepare to handle dashlane identification types. +- Update identification types. +- Support secret type to represent identification. +- Rename struct. +- Support parsing bitwarden CSV input. +- Prepare for multiple CSV variants. +- Initial 1Password CSV support. +- Add assertions for 1password csv. +- Prepare for 1password csv filtering. +- Support for firefox CSV export. +- Prepare for firefox CSV handling. +- Support chrome CSV passwords export. +- Add fixtures, prepare zip dependency. +- Move module. +- Ensure we drop search index in convert code. +- Handling for duplicate labels on import. +- Fix parser bug, allow for empty data: block. +- Update AccountManager with dir builder functions. +- Improve logic for ignoring system keychains. +- Ignore empty lines when parsing keychain list. +- Call security list-keychains, do not readdir(). +- Make fields public, rename struct. +- Handle file attachments when exporting. +- Improve keychain import logic. +- Handle parsing MacOS passwords export in CSV. +- Pass existing vault when converting. +- Assert on converting keychain dump to a vault. +- Draft logic to generate data dump with autofill. +- Add test spec for parsing certificate. +- Support parsing data: in keychain dump. +- Run fmt. +- Update fixtures, support unescaping octal. +- Update fixtures. +- Improve keychain parser assertions. +- Update fixtures and readme. +- Add readme and update test spec. +- Improve draft keychain dump parser. +- Improve parser error handling. +- Draft keychain dump parser. +- Move error module, prepare Convert trait. +- Exploring keychain access support with security framework. +- Move migration code to a crate. +- Optional seed entropy for the master passphrase ([#125](https://github.com/saveoursecrets/sdk/pull/125)) +- Support unencrypted export archive ([#124](https://github.com/saveoursecrets/sdk/pull/124)) +- Add date_created to VaultMeta. +- Use more words for vault passphrases. +- Add date_created to SecretMeta. +- Better error message when decryption fails. +- Run formatting. +- Add remove_vault() to SearchIndex. +- Add rotate_identifier() to Vault. +- Add find_default_vault() to AccountManager. +- Update doc comments. +- Add export_vault() and find_local_vault(). +- Add find_vault_passphrase() to AccountManager. +- Support removing vault passphrases from identity vault. +- Support creating a mirrored Gatekeeper on login. +- Update test specs for API change. +- Fix new_account() logic. +- Save default vault passphrase in identity vault. +- Return Gatekeeper for identity vault on sign in. +- Define account_manager module. +- Fix shell client for new secret types. +- Support URN in SecretMeta ([#120](https://github.com/saveoursecrets/sdk/pull/120)) +- Support standalone Secret::Password type. +- Support Link secret type. +- Update crate type to generate wasm file. +- Support tag count in search index statistics. +- Run cargo fmt. +- Update DocumentCount to expose fields. +- Expose access to search index statistics. +- Add basic count statistics to search index. +- Do not always call reduce_wal() in open_vault(). +- User fields ([#113](https://github.com/saveoursecrets/sdk/pull/113)) +- Update shell client ([#111](https://github.com/saveoursecrets/sdk/pull/111)) +- Tweak coverage scripts. +- Support bank account secret type ([#110](https://github.com/saveoursecrets/sdk/pull/110)) +- Support Secret::Card type. ([#108](https://github.com/saveoursecrets/sdk/pull/108)) +- Use git repo for search fork. +- Support tags for secret meta data ([#106](https://github.com/saveoursecrets/sdk/pull/106)) +- Add remove_all() to SearchIndex(). +- Verify an archive has at least one default vault. +- Verify identity signing key in archive. +- Basic assertion on restoring from an archive. +- Improve coverage tasks. +- Prepare restore_archive() in StorageProvider. +- Expose Inventory fields. +- Assert on archive inventory. +- Support reading inventory in archive reader. +- Rename struct field. +- Archive writing and reading ([#104](https://github.com/saveoursecrets/sdk/pull/104)) +- Include VaultId in search index. +- Support predicate in SearchIndex::query_map(). +- Prefer create_search_index(). +- Support vault_id in SearchIndex Document. +- Do not call create_index() in open_vault(). +- Run cargo fmt. +- Refactor SearchIndex to Arc. +- Always use OpenOptions with truncate(). +- Use SOS_CACHE_DIR for cache dir override. +- Add workaround for set_len(0) failing with "Access Denied" on Windows. +- Include reqwest for windows builds. +- Switch to vcard4 library. +- Fix totp library for test spec. +- Tweak cover task. +- Switch to forked TOTP library. +- Switch to git dependency for vcard_parser. +- Contact vCard secret type ([#103](https://github.com/saveoursecrets/sdk/pull/103)) +- Improve identity unit tests. +- Update storage dirs. +- Remove indirection on encryption passphrase. +- Tweak struct field name. +- Add VaultFlags::Login. +- Create login vault as identity ([#101](https://github.com/saveoursecrets/sdk/pull/101)) +- Exposing import_vault() on providers. +- Remove generate_safe_nonce(). +- Change default vault name. +- Do not assert on password length. +- Expose passgen module. +- Include score with generated passwords. +- Wrap in SecretString. +- Add passgen module. +- Add VaultFlags to constructors. +- Expose mutable reference to the VaultFlags. +- Change default server bind address. +- Update keystore dependency. +- Rebuild browser webapp. +- Support purpose field in vault meta data. +- Reserve 32 bit VaultFlags in Summary. +- Rebuild bundled webapp. +- Add methods to search index. +- Use bundle id for fallback storage location. +- Fix bug with path location. +- Rename config field. +- Support for polymorphic providers ([#100](https://github.com/saveoursecrets/sdk/pull/100)) +- Refactor to support local provider ([#99](https://github.com/saveoursecrets/sdk/pull/99)) +- Expose close_vault(). +- Add open_vault() and TryFrom impl. +- Use TraceLayer in server. +- Expose create_remote_account(). +- Expose list_vaults() in SpotFileClient. +- Update doc comments. +- Expose all server config types. +- Support server config with dummy file path. +- Non-reference TryFrom for SingleParty. +- Update web3-keystore for label option. +- Remove run_blocking() from wasm32 build. +- Used nested vaults directory for local vaults. +- Do not use HTTPS for local development. +- Fix compilation for ios. +- Check response status in SpotFileClient::create_account(). +- Tidy create_account() signature. +- Remove Send bound from run_blocking(). +- Tweak constructor argument order. +- Update binary-stream dependency. +- Update dependencies for target_family="wasm". +- Update dependencies for android. +- Update binary-stream dependency. +- Update conditional dependencies. +- Improve wrapper executable help. ([#98](https://github.com/saveoursecrets/sdk/pull/98)) +- Use address library. ([#97](https://github.com/saveoursecrets/sdk/pull/97)) +- Update binary-stream dependency. +- Update tower-http dependency. +- Update rustyline dependency. +- Using ngram tokenizer for search index. +- Update search dependency for improved API. +- Support PIN secret type ([#94](https://github.com/saveoursecrets/sdk/pull/94)) +- Add find_all_by_label(). +- Return Summary in SpotMemoryClient::create_account(). +- Update search library. +- Respond to change actions ([#91](https://github.com/saveoursecrets/sdk/pull/91)) +- Use websocket for change notifications ([#89](https://github.com/saveoursecrets/sdk/pull/89)) +- Use RPC client in node cache. ([#87](https://github.com/saveoursecrets/sdk/pull/87)) +- Request session support ([#84](https://github.com/saveoursecrets/sdk/pull/84)) +- Expose index_mut() on Gatekeeper. +- Support query_map() on SearchIndex. +- Restore whoami command, closes [#80](https://github.com/saveoursecrets/sdk/pull/80). +- Search index ([#83](https://github.com/saveoursecrets/sdk/pull/83)) +- Update browser-gui task. +- Static futures for webassembly compat ([#78](https://github.com/saveoursecrets/sdk/pull/78)) +- Tidy dependencies. +- Use chrono for wasm32 and macros in request client ([#77](https://github.com/saveoursecrets/sdk/pull/77)) +- Update chbs dependency. +- Use last updated in shell client. +- Add updated date/time to secret meta data. ([#76](https://github.com/saveoursecrets/sdk/pull/76)) +- Basic lock file handling in shell client. ([#74](https://github.com/saveoursecrets/sdk/pull/74)) +- Support page secret variant. ([#73](https://github.com/saveoursecrets/sdk/pull/73)) +- Client for the SPOT networking mode ([#72](https://github.com/saveoursecrets/sdk/pull/72)) +- Tidy filesystem handling logic in node cache ([#71](https://github.com/saveoursecrets/sdk/pull/71)) +- Patch cache ([#69](https://github.com/saveoursecrets/sdk/pull/69)) +- Cache generics ([#67](https://github.com/saveoursecrets/sdk/pull/67)) +- Update readme. +- Update main proxy program. +- Agent for caching identity keys ([#66](https://github.com/saveoursecrets/sdk/pull/66)) +- Update SecretKey to use secrecy types. +- Add comment to secret type. +- Use secrecy types ([#64](https://github.com/saveoursecrets/sdk/pull/64)) +- Improve changes listener handling. +- Update readme. +- Improve readme. +- Update readme. +- Fix changes stream handling. +- Fix error logging in shell client. +- Tweak readme. +- Update readme. +- Binary encoding refactor ([#63](https://github.com/saveoursecrets/sdk/pull/63)) +- Binary signatures ([#61](https://github.com/saveoursecrets/sdk/pull/61)) +- Sketching node types, rename trait. +- Improve features handling in node crate. +- Change stream ([#58](https://github.com/saveoursecrets/sdk/pull/58)) +- Update check-wasm task. +- Support building node client feature for wasm32. +- Add integration test for checking file integrity. +- Rename trait. +- Do not expose server URL. +- Tidy change password builder. +- Tidy re-exports in core library. +- Tidy main files. +- Use trait for the HTTP client. +- Tidy re-exports. +- Use node crate to encapsulate the client and server library code ([#57](https://github.com/saveoursecrets/sdk/pull/57)) +- Update release config. +- Configure for release. +- Implement switch command in shell client. ([#56](https://github.com/saveoursecrets/sdk/pull/56)) +- Guard against nonce re-use. ([#55](https://github.com/saveoursecrets/sdk/pull/55)) +- Add integration test for force pull on compact event. +- Improve assertions in integration test. +- Add integration test for handling change notifications. +- Add integration test for resolvable conflict. +- Improve readme docs. +- Support PEM secret type ([#53](https://github.com/saveoursecrets/sdk/pull/53)) +- React to change notifications in shell client ([#52](https://github.com/saveoursecrets/sdk/pull/52)) +- Support changing encryption passphrase. ([#51](https://github.com/saveoursecrets/sdk/pull/51)) +- Audit monitor ([#49](https://github.com/saveoursecrets/sdk/pull/49)) +- Store hash for previous row in WAL logs ([#48](https://github.com/saveoursecrets/sdk/pull/48)) +- Remove GetVaultName from SyncEvent. +- Improve WAL file iterator handling. +- Refactor vault iteration. ([#47](https://github.com/saveoursecrets/sdk/pull/47)) +- Prefer explicit VaultId. +- Tidy audit module. +- Improving generic iterator. +- Audit file iterator ([#45](https://github.com/saveoursecrets/sdk/pull/45)) +- Patch file iterator ([#42](https://github.com/saveoursecrets/sdk/pull/42)) +- Disable PR workflow for now. +- Update chbs dependency for strict cargo audit. +- Run cargo fmt. +- Implement draft sos executable. +- Add task to build homebrew tarball. +- Sketch top-level proxy executable. +- Disable windows ARM, need to wait for ring:0.17. +- Try setting TARGET_CC for windows ARM. +- Update release build for windows ARM. +- Trying ARM windows builds. +- Try windows with msvc vendor. +- Update release workflow for windows. +- Try for windows release build. +- Restore targets in release build. +- Try to set linker. +- Disable default-features for reqwest. +- Revert script changes. +- Trying new sources list. +- Move cat statement. +- Debug sources.list. +- Update script. +- Update dependencies. +- Update depdendencies in script. +- Update install script for linux. +- Update CI install script. +- Try new config for aarch64 linux. +- Disable aarch64 linux for now. +- Update test script. +- Update CI build script. +- Try sudo for dpkg. +- Trying libssl-dev:armhf. +- Add libssl-dev to CI build script. +- Tweak CI build script. +- Try new release matrix. +- Update release workflow. +- Lifting ring script for aarch64 linux build. +- Reduce matrix settings in release. +- Disable failing aarch64 for windows due to ring. +- Update release targets. +- Fix for release workflow. +- Update release workflow. +- Update release workflow. +- Update release workflow for test. +- Update library workflow. +- Update workflow. +- Test workflow change. +- Update workflow. +- Update library workflow. +- Update workflow. +- Use self-signed certificate in integration tests. +- Update readme. +- Support generating code coverage. +- Switch to cargo make as task runner. +- Improve handling of change notifications. ([#40](https://github.com/saveoursecrets/sdk/pull/40)) +- Trying new release workflow. +- Update release targets. +- Update target in rust toolchain. +- Update build targets in release workflow. +- Enable release action in workflow. +- Disable windows for now. +- Update Makefile task. +- Preparing release workflow. +- Integration tests ([#39](https://github.com/saveoursecrets/sdk/pull/39)) +- Tweak force pull/push logic. +- Pull and push command implementations ([#36](https://github.com/saveoursecrets/sdk/pull/36)) +- Handling conflict responses ([#26](https://github.com/saveoursecrets/sdk/pull/26)) +- Tidy shell command. +- Remove save() from VaultAccess trait. +- Update make task. +- Move Patch to events module. +- Improve shell client logic for managing summaries. +- Fix bug converting to ChangeEvent. +- Update README. +- Remove public directory. +- Update the README. +- Add sandbox directory with mock server config. +- Update Cargo.toml with license info. +- Write ahead log ([#16](https://github.com/saveoursecrets/sdk/pull/16)) +- Support commit merkle tree ([#15](https://github.com/saveoursecrets/sdk/pull/15)) +- Client shell implementation ([#11](https://github.com/saveoursecrets/sdk/pull/11)) +- Handle conflicts ([#10](https://github.com/saveoursecrets/sdk/pull/10)) +- Draft file access logic. ([#8](https://github.com/saveoursecrets/sdk/pull/8)) +- Encode header length after identity bytes. +- Encode row length for each entry in the contents. ([#7](https://github.com/saveoursecrets/sdk/pull/7)) +- Improve layout of file upload reader. +- Use two bytes for bit flags and operation identifier. +- Use u16 for log record bit flags. +- Improve audit log documentation. +- Use .dat file extension for audit logs. +- Move audit log record bit flags. +- Use bit flags in audit log record. +- Support secret UUID in audit log data. +- Mark deprecated modules. +- Support printing audit log records. +- Add LoginChallenge and LoginResponse to audit logs. +- Use enum for Operation. +- Rename module. +- Fix bug with audit lock file. +- Tidy make task and script. +- Fix public URL for bundled GUI. +- Ensure backend API is async. +- Improve server handlers. +- Tidy x-signed-message handling. +- Use the x-signed-message header. +- Updating whitepaper. +- Draft audit log implementation. +- Helper for file identity magic bytes. +- Improve audit log. +- Improve handling of audit file path. +- Draft audit file support. +- Fix padding on signup views. +- Use u16 for audit log operation. +- Tidy encoding of UUID values. +- Sketch audit log record. +- Use tokio::fs in file system backend. +- Separate views for login flow. +- Render summaries in vault list. +- Rename vaults to summaries. +- Save vault summaries with the Account. +- Return vault summaries at login. +- Draft login logic. +- Use Summary type in vault header. +- Check account exists before issuing a challenge. +- Rename routes. +- Sketch authenticate module. +- Draft logic for creating new accounts. +- Use single backend for server config. +- Extract address from bearer auth token. +- Improve signup finish view. +- Upgrade dependencies. +- Improve the signup components. +- Add signup screen to verify encryption passphrase. +- Add logic to dispose of signup state. +- Use snackbar, improve error handling. +- Draft web signer class. +- Improving signup logic. +- Improving file upload read logic. +- Improve signup flow. +- Support downloading new private key. +- Prepare for new signup views. +- Pass payload back from CRUD operations. +- Sketching logic for signing payloads. +- Restore validation for create / update. +- Migrate to tuple for meta data and secret. ([#6](https://github.com/saveoursecrets/sdk/pull/6)) +- Fix bug on update with unique label test. +- Use thunk for reading a secret. +- Tweak link target. +- Support editing the file upload secret type. +- Support editing the credentials type. +- Support editing the account password type. +- Draft logic to update secure notes. +- Support name field when creaing vaults. +- Use vault name in browser GUI. +- Encode public name in file. +- Support deleting secrets in browser GUI. +- Show dialog to confirm secret deletion. +- Improve secret layout. +- Tidy logic for secret creation. +- Use untagged enum variants. +- Camel case for Secret variants. +- Improve secret views. +- Sketch account secret view. +- Draft secret views for notes and files. +- Prepare for secret view. +- Hack for meta data sorting. +- Improve routing logic in browser app. +- Support navigating to secret view. +- Sort secrets list using a BTreeMap. +- Improve meta data handling in webassembly. +- Draft logic to unlock vaults in browser. +- Show mime and file size for file secrets. +- Support show for credentials type in cli. +- Support show for account and blob secret types. +- Draft support for creating credentials lists. +- Improve handling when label already exists. +- Support adding the account type in the cli. +- Encode kind in secret meta data. +- Support removing secrets in the cli. +- Ensure meta data labels are unique. +- Prepare to support removing secrets. +- Prepare gatekeeper for new API. +- Tidy module names. +- Support multiple algorithms ([#5](https://github.com/saveoursecrets/sdk/pull/5)) +- Support adding files via the cli. +- Multiline input for notes ([#4](https://github.com/saveoursecrets/sdk/pull/4)) +- Hack for pasted passwords. +- Support listing secrets in the vault. +- Support UUID when creating new vault. +- Support writing passphrase to stdin. +- Add support for XChaCha20Poly1305. ([#3](https://github.com/saveoursecrets/sdk/pull/3)) +- Tidy encode and decode function names. +- Initialize new vaults with passphrase. +- Remove React.StrictMode as it renders twice. +- Debugging double render. +- Ensure salt is encoded and decoded from the auth map. +- Parcel for web app ([#2](https://github.com/saveoursecrets/sdk/pull/2)) +- Serde binary migration ([#1](https://github.com/saveoursecrets/sdk/pull/1)) +- Update dependencies for web gui. +- Update to react@18 for webapp. +- Update axum. +- Use fixtures for test specs. +- Use 32 bit for wasm32 compatibility. +- Fixing worker handling. +- Handle CORS origin configuration. +- Mapping user configs to backend implementations. +- Draft logic to support config in server. +- Sketch AddressStr new type wrapper. +- Tidy error handling. +- Draft file upload handling. +- Work in progress on the credentials list logic. +- Draft logic to create account password secrets. +- Tweak secure note form. +- Initial listing of secrets. +- Draft logic for create a new secure note. +- Support bundling GUI assets in the server. +- Sketching the secure note form. +- Separate routers for auth states. +- Sketch logout logic. +- Improve dialog handling. +- Improve Diceware component. +- Use top-level await. +- Fix wasm issue. +- Fix lint issues. +- Add Diceware UI component. +- Support diceware passphrases. +- Draft logic to lock/unlock a vault. +- Improve whitepaper. +- Integrate Argon2 pbkdf with vault initialization. +- Draft implementation of Argon2 pbkdf. +- Rename sandbox -> browser. +- Use dialog for new vault form. +- Sketch secret list and UI elements. +- Draft new vault form. +- Support download for exporting the vault. +- Improve navigation in sandbox sketch. +- Using material UI in sandbox. +- Draft logic for creating webassembly vaults. +- Tweak doc comments. +- Sketch sandbox logic for creating a new vault. +- Add draft sandbox. +- Improve webassembly bindings. +- Complete update to thiserror. +- Work in progress migrating to thiserror. +- Start migration to thiserror. +- Start sketching webassembly bindings. +- Assert on secret meta data. +- Assert on creating and retrieving secrets. +- Sketch types of secret. +- Draft gatekeeper logic. +- Flush backend on index POST. +- Work in progress in index update handler. +- Abstraction for server backend. +- Improving server sketch. +- Sketch draft server. +- Use UUID for secret keys. +- Update whitepaper. +- Import old Makefile, update whitepaper. +- Add whitepaper source file. +- Add native module. +- Import draft rust libraries. +- Add initial flutter files. diff --git a/Cargo.lock b/Cargo.lock index 3eda61f682..e0339d8199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -870,16 +870,6 @@ dependencies = [ "windows", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -2448,7 +2438,7 @@ dependencies = [ [[package]] name = "keychain_parser" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "logos", @@ -3943,12 +3933,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -4281,39 +4265,30 @@ dependencies = [ [[package]] name = "sos" -version = "0.13.0" +version = "0.14.1" dependencies = [ - "anticipate-runner", - "anyhow", "arboard", "async-recursion", "axum-server", "binary-stream", "clap", - "copy_dir", "crossterm", "csv-async", "ctrlc", "enum-iterator", "futures", - "http", "human_bytes", - "indexmap 2.2.6", "kdam", - "log", - "maplit2", "num_cpus", "once_cell", "parking_lot", - "pretty_assertions", "rustyline", "rustyline-derive", - "secrecy", "serde", "serde_json", "shell-words", + "sos-cli-helpers", "sos-net", - "sos_test_utils", "tempfile", "terminal-banner", "thiserror", @@ -4322,14 +4297,11 @@ dependencies = [ "tracing", "tracing-subscriber", "unicode-width", - "wasm-bindgen", - "wasm-bindgen-test", - "wasm-log", ] [[package]] name = "sos-artifact" -version = "0.8.6" +version = "0.8.7" dependencies = [ "anyhow", "hex", @@ -4341,18 +4313,23 @@ dependencies = [ "url", ] +[[package]] +name = "sos-cli-helpers" +version = "0.1.0" +dependencies = [ + "clap", + "colored", + "serde", +] + [[package]] name = "sos-net" -version = "0.13.0" +version = "0.14.1" dependencies = [ "anyhow", "async-recursion", "async-stream", "async-trait", - "axum", - "axum-extra", - "axum-macros", - "axum-server", "binary-stream", "bs58", "colored", @@ -4360,11 +4337,7 @@ dependencies = [ "hex", "http", "indexmap 2.2.6", - "once_cell", - "parking_lot", "prost", - "prost-build", - "protoc-bin-vendored", "rand", "reqwest", "rs_merkle", @@ -4375,27 +4348,44 @@ dependencies = [ "serde_with", "sha3", "snow", + "sos-protocol", "sos-sdk", "thiserror", "tokio", - "tokio-stream", "tokio-tungstenite 0.23.1", "tokio-util", - "toml 0.8.14", - "tower", - "tower-http", "tracing", "tracing-subscriber", "url", "urlencoding", - "utoipa", - "utoipa-rapidoc", + "uuid", +] + +[[package]] +name = "sos-protocol" +version = "0.14.1" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "indexmap 2.2.6", + "prost", + "prost-build", + "protoc-bin-vendored", + "rs_merkle", + "rustc_version", + "serde", + "sos-sdk", + "thiserror", + "tokio", + "tracing", + "url", "uuid", ] [[package]] name = "sos-sdk" -version = "0.13.1" +version = "0.14.1" dependencies = [ "aes-gcm", "age", @@ -4445,7 +4435,7 @@ dependencies = [ "sha1", "sha2", "sha3", - "sos-vfs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sos-vfs 0.2.2", "sos_test_utils", "subtle", "tempfile", @@ -4468,9 +4458,60 @@ dependencies = [ "zxcvbn", ] +[[package]] +name = "sos-server" +version = "0.14.1" +dependencies = [ + "async-trait", + "axum", + "axum-extra", + "axum-macros", + "axum-server", + "binary-stream", + "bs58", + "clap", + "colored", + "futures", + "hex", + "http", + "indexmap 2.2.6", + "rustc_version", + "serde", + "serde_json", + "sos-cli-helpers", + "sos-protocol", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "toml 0.8.14", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", + "url", + "utoipa", + "utoipa-rapidoc", + "uuid", +] + [[package]] name = "sos-vfs" version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9009f68f8a2f7b64f24916907114467b74f25c2e7cb16a89885a0601cb7e4664" +dependencies = [ + "async-recursion", + "bitflags 1.3.2", + "futures", + "once_cell", + "parking_lot", + "tokio", +] + +[[package]] +name = "sos-vfs" +version = "0.2.3" dependencies = [ "anyhow", "async-recursion", @@ -4482,17 +4523,34 @@ dependencies = [ ] [[package]] -name = "sos-vfs" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9009f68f8a2f7b64f24916907114467b74f25c2e7cb16a89885a0601cb7e4664" +name = "sos-workspace" +version = "0.14.1" dependencies = [ + "anticipate-runner", + "anyhow", "async-recursion", - "bitflags 1.3.2", + "binary-stream", + "clap", + "copy_dir", "futures", + "http", + "indexmap 2.2.6", + "kdam", + "maplit2", "once_cell", "parking_lot", + "pretty_assertions", + "secrecy", + "serde", + "serde_json", + "sos-net", + "sos-server", + "sos_test_utils", + "tempfile", + "thiserror", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -4507,6 +4565,7 @@ dependencies = [ "secrecy", "serde_json", "sos-net", + "sos-server", "tempfile", "tokio", "tracing", @@ -5496,8 +5555,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", - "serde", - "serde_json", "wasm-bindgen-macro", ] @@ -5557,42 +5614,6 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2 1.0.85", - "quote 1.0.36", - "syn 2.0.66", -] - -[[package]] -name = "wasm-log" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def95b2a762924804037f77e3de791f1c177d6ecbe0385a64e519bd7902a5f81" -dependencies = [ - "log", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 2548d264e0..e50250a55a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "sos" -version = "0.13.0" +name = "sos-workspace" +version = "0.14.1" edition = "2021" -rust-version = "1.75.0" +rust-version = "1.78.0" description = "Distributed, encrypted database for private secrets." homepage = "https://saveoursecrets.com" -license = "MIT OR Apache-2.0" +license = "MIT OR Apache-2.0 OR AGPL-3.0" authors = ["saveoursecrets-developers "] -default-run = "sos" +publish = false categories = [ "command-line-utilities", "cryptography::cryptocurrencies", @@ -18,9 +18,13 @@ categories = [ resolver = "2" members = [ "crates/artifact", + "crates/cli_helpers", "crates/keychain_parser", "crates/net", + "crates/protocol", "crates/sdk", + "crates/server", + "crates/sos", "crates/test_utils", "crates/vfs", ] @@ -28,16 +32,16 @@ members = [ [features] default = [] enable-cli-tests = [] -mem-fs = ["sos-net/mem-fs"] -test-utils = ["sos-net/test-utils"] [workspace.dependencies] csv-async = { version = "1", features = ["tokio", "with_serde"] } thiserror = "1" +anyhow = "1" tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } secrecy = { version = "0.8", features = ["serde"] } serde = { version = "1", features = ["derive"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"]} serde_json = "1" serde_with = { version = "3", features = ["base64"] } tokio-util = { version = "0.7", default-features = false, features = ["io", "compat"] } @@ -66,6 +70,8 @@ enum-iterator = "2" file-guard = "0.2" tempfile = "3.5" prost = "0.12.6" +clap = { version = "4.3.19", features = ["derive", "wrap_help", "env"] } +colored = "2" [workspace.dependencies.rs_merkle] version = "1.4.2" @@ -75,8 +81,7 @@ version = "9.1.0" features = ["async"] #path = "../../../../binary-stream" -[dependencies] -csv-async.workspace = true +[dev-dependencies] binary-stream.workspace = true tracing.workspace = true tracing-subscriber.workspace = true @@ -86,72 +91,31 @@ async-recursion.workspace = true futures.workspace = true parking_lot.workspace = true once_cell.workspace = true -toml.workspace = true serde.workspace = true -enum-iterator.workspace = true -human_bytes = "0.4" -tempfile = "3.5" -shell-words = "1" -terminal-banner = { version = "0.4.1", features = ["color"] } -unicode-width = "0.1" -kdam = { version = "0.5", features = ["rich", "spinner"] } -num_cpus = "1" -crossterm = "0.27" -ctrlc = "3" - -[dependencies.sos-net] -version = "0.13.0" -features = ["full"] -path = "crates/net" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -clap = { version = "4.3.19", features = ["derive", "wrap_help", "env"] } -axum-server = { version = "0.6", features = ["tls-rustls"] } -tokio = { version = "1", features = ["full"] } -arboard = "3" -rustyline = "14" -rustyline-derive = "0.10" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -tokio = { version = "1", features = ["rt", "time", "sync"] } - -[dev-dependencies] +clap.workspace = true indexmap.workspace = true +tokio.workspace = true +anyhow.workspace = true +secrecy.workspace = true +http.workspace = true + +sos-server = { path = "crates/server" } +sos_test_utils = { path = "crates/test_utils" } -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -anyhow = "1" -tokio = { version = "1", features = ["full"] } -secrecy = "0.8" -http = "1" copy_dir = "0.1" maplit2 = "1" -sos_test_utils = { path = "crates/test_utils" } +tempfile = "3.5" +kdam = { version = "0.5", features = ["rich", "spinner"] } pretty_assertions = "1.4" anticipate-runner = { version = "0.5.1" } -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = "0.3" -wasm-bindgen = { version = "0.2.80", features = ["serde-serialize"] } -wasm-log = "0.3" -log = "0.4" - -[[bin]] -name = "sos" -path = "src/bin/sos.rs" - -[[bin]] -name = "sos-server" -path = "src/bin/sos_server.rs" +[dev-dependencies.sos-net] +version = "0.14.0" +features = ["full"] +path = "crates/net" [profile.release] codegen-units = 1 lto = true strip = true opt-level = "z" - -[workspace.metadata.release] -allow-branch = ["main"] -sign-tag = true -sign-commit = true -pre-release-hook = ["cargo", "audit"] -pre-release-commit-message = "Release {{version}}" diff --git a/Dockerfile b/Dockerfile index 4ba6df7d69..9e1448a08a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,12 @@ -FROM rust:1.75-buster AS rust +FROM rust:1.78-buster AS rust WORKDIR /usr/app -COPY workspace workspace -COPY src src +COPY crates crates COPY Cargo.toml Cargo.toml COPY Cargo.lock Cargo.lock COPY sandbox/config.toml config.toml RUN mkdir accounts -RUN cargo build --release --bin sos-server +RUN cargo build --locked --release -p sos-server CMD /usr/app/target/release/sos-server start /usr/app/config.toml diff --git a/LICENSE-AGPL b/LICENSE-AGPL new file mode 100644 index 0000000000..be3f7b28e5 --- /dev/null +++ b/LICENSE-AGPL @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index b7fc8336b1..19749b0d1a 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,6 @@ See the [overview](/doc/overview.md) for concepts and terminology, the [API docu ## License -MIT or Apache-2.0 at your discretion. +The server code is licensed under AGPL-3.0; other crates are licensed under the MIT or Apache-2.0 license at your discretion. © Copyright Save Our Secrets Pte Ltd 2022; all rights reserved. diff --git a/crates/artifact/CHANGELOG.md b/crates/artifact/CHANGELOG.md new file mode 100644 index 0000000000..73fc5d0f2c --- /dev/null +++ b/crates/artifact/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.8.7](https://github.com/saveoursecrets/sdk/compare/sos-artifact-v0.8.6...sos-artifact-v0.8.7) - 2024-06-21 + +### Other +- Device vault fix ([#367](https://github.com/saveoursecrets/sdk/pull/367)) diff --git a/crates/artifact/Cargo.toml b/crates/artifact/Cargo.toml index 5445ebdf00..7d26f4f31b 100644 --- a/crates/artifact/Cargo.toml +++ b/crates/artifact/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sos-artifact" -version = "0.8.6" +version = "0.8.7" edition = "2021" description = "Types for release artifact meta data" homepage = "https://saveoursecrets.com" diff --git a/crates/cli_helpers/Cargo.toml b/crates/cli_helpers/Cargo.toml new file mode 100644 index 0000000000..ce41829770 --- /dev/null +++ b/crates/cli_helpers/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sos-cli-helpers" +version = "0.1.0" +edition = "2021" +description = "Shared helpers for command line executables." +homepage = "https://saveoursecrets.com" +license = "MIT OR Apache-2.0" +authors = ["saveoursecrets-developers "] + +[dependencies] +serde.workspace = true +clap.workspace = true +colored.workspace = true diff --git a/crates/cli_helpers/src/lib.rs b/crates/cli_helpers/src/lib.rs new file mode 100644 index 0000000000..b712162640 --- /dev/null +++ b/crates/cli_helpers/src/lib.rs @@ -0,0 +1,21 @@ +//! Helper types and functions for the [Save Our Secrets](https://saveoursecrets.com) command line [executables](https://saveoursecrets.com/command-line-tools/). + +pub mod messages; + +/// Command tree used to print help output for the website. +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct CommandTree { + /// Name of the command. + pub name: String, + /// Subcommands. + pub commands: Vec, +} + +impl From<&clap::Command> for CommandTree { + fn from(value: &clap::Command) -> Self { + CommandTree { + name: value.get_name().to_string(), + commands: value.get_subcommands().map(|c| c.into()).collect(), + } + } +} diff --git a/src/helpers/messages.rs b/crates/cli_helpers/src/messages.rs similarity index 92% rename from src/helpers/messages.rs rename to crates/cli_helpers/src/messages.rs index b3e17b4b3d..5af23ec1b4 100644 --- a/src/helpers/messages.rs +++ b/crates/cli_helpers/src/messages.rs @@ -1,4 +1,6 @@ -use terminal_banner::colored::Colorize; +//! Helper functions to print messages. + +use colored::Colorize; const TICK: &str = "✓"; const INFO: &str = "Info"; diff --git a/crates/keychain_parser/CHANGELOG.md b/crates/keychain_parser/CHANGELOG.md new file mode 100644 index 0000000000..e361c053e0 --- /dev/null +++ b/crates/keychain_parser/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.1](https://github.com/saveoursecrets/sdk/compare/keychain_parser-v0.1.0...keychain_parser-v0.1.1) - 2024-06-21 + +### Other +- Update plist, which updates line-wrap which fixes safemem. +- Only run keychain tests on macos. diff --git a/crates/keychain_parser/Cargo.toml b/crates/keychain_parser/Cargo.toml index 0d8cc1de6d..c1e0175451 100644 --- a/crates/keychain_parser/Cargo.toml +++ b/crates/keychain_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "keychain_parser" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "Parse the output of security(1) dump-keychain." homepage = "https://saveoursecrets.com" diff --git a/crates/net/Cargo.toml b/crates/net/Cargo.toml index f5e992b998..e4f84601d4 100644 --- a/crates/net/Cargo.toml +++ b/crates/net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sos-net" -version = "0.13.0" +version = "0.14.1" edition = "2021" description = "Networking library for the Save Our Secrets SDK." homepage = "https://saveoursecrets.com" @@ -16,9 +16,7 @@ default = [] full = [ "audit", "archive", - "client", "contacts", - "device", "files", "hashcheck", "listen", @@ -26,44 +24,24 @@ full = [ "pairing", "preferences", "search", - "server", "security-report", "keychain-access", "system-messages", ] -client = [ - "dep:reqwest", -] -listen = ["dep:tokio-tungstenite"] -server = [ - "dep:toml", - "dep:axum", - "dep:axum-extra", - "dep:axum-macros", - "dep:axum-server", - "dep:tower", - "dep:tower-http", - "dep:tokio-stream", - "dep:utoipa", - "dep:utoipa-rapidoc", - "device", -] +listen = ["dep:tokio-tungstenite", "sos-protocol/listen"] hashcheck = [] audit = ["sos-sdk/audit"] archive = ["sos-sdk/archive"] -files = ["sos-sdk/files"] +files = ["sos-sdk/files", "sos-protocol/files"] contacts = ["sos-sdk/contacts"] migrate = ["sos-sdk/migrate"] keychain-access = ["sos-sdk/keychain-access"] -device = ["sos-sdk/device"] recovery = ["sos-sdk/recovery"] -pairing = ["dep:snow"] +pairing = ["dep:snow", "sos-protocol/pairing"] preferences = ["sos-sdk/preferences"] -search = ["sos-sdk/search"] +search = ["sos-sdk/search", "sos-protocol/search"] security-report = ["sos-sdk/security-report"] system-messages = ["sos-sdk/system-messages"] -mem-fs = ["sos-sdk/mem-fs"] -test-utils = ["sos-sdk/test-utils"] [dependencies] tokio-util.workspace = true @@ -80,13 +58,11 @@ hex.workspace = true sha3.workspace = true secrecy.workspace = true serde_with.workspace = true -once_cell.workspace = true rand.workspace = true url.workspace = true futures.workspace = true bs58.workspace = true urlencoding.workspace = true -parking_lot.workspace = true indexmap.workspace = true async-stream = "0.3" colored = "2" @@ -94,53 +70,23 @@ binary-stream.workspace = true rs_merkle.workspace = true prost.workspace = true - -# server -toml = { workspace = true, optional = true } -axum = { version = "0.7", features = ["ws", "original-uri"], optional = true } -axum-extra = {version = "0.9", features = ["typed-header"], optional = true} -axum-macros = { version = "0.4", optional = true } -axum-server = { version = "0.6", features = ["tls-rustls"], optional = true } -tower = { version = "0.4", optional = true } -tower-http = { version = "0.5", features = ["cors", "trace"], optional = true } -tokio-stream = { version = "0.1", optional = true } -tokio-tungstenite = { version = "0.23", features = ["rustls-tls-native-roots"] , optional = true} -utoipa = { version = "4", features = ["uuid"], optional = true } -utoipa-rapidoc = { version = "3", features = ["axum"], optional = true } - # pairing snow = { version = "0.9", optional = true } -[dependencies.sos-sdk] -version = "0.13.0" -path = "../sdk" - -[target.'cfg(not(target_arch="wasm32"))'.dependencies] +reqwest = { version = "0.12.5", features = ["json", "rustls-tls", "stream"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "macros"] } +tokio-tungstenite = { version = "0.23", features = ["rustls-tls-native-roots"] , optional = true} -[target.'cfg(target_arch="wasm32")'.dependencies] -tokio = { version = "1", features = ["rt", "time", "sync"] } - -[target.'cfg(target_os="macos")'.dependencies] -reqwest = { version = "0.12.5", default-features = true, features = ["json", "rustls-tls", "stream"], optional = true } +[dependencies.sos-sdk] +version = "0.14.1" +path = "../sdk" -# NOTE: Must disable default-features so that openssl -# NOTE: is not compiled when cross-compiling in CI. -# -# NOTE: If we disable `default-features` during -# NOTE: development then attempting to connect to -# NOTE: the changes feed using the locally issued mkcert -# NOTE: certificate yields an "Unknown Issuer" error. -# NOTE: Which is related to the `security-framework` not -# NOTE: being compiled on macos when `default-features` is -# NOTE: disabled. -[target.'cfg(not(target_os="macos"))'.dependencies] -reqwest = { version = "0.12.5", default-features = false, features = ["json", "rustls-tls", "stream"], optional = true } +[dependencies.sos-protocol] +version = "0.14.1" +path = "../protocol" [dev-dependencies] anyhow = "1" [build-dependencies] rustc_version = "0.4.0" -prost-build = "0.12.6" -protoc-bin-vendored = "3" diff --git a/crates/net/build.rs b/crates/net/build.rs index 3b9406bee6..20f4205502 100644 --- a/crates/net/build.rs +++ b/crates/net/build.rs @@ -1,4 +1,3 @@ -extern crate prost_build; use rustc_version::{version_meta, Channel}; fn main() { @@ -10,24 +9,4 @@ fn main() { Channel::Dev => "CHANNEL_DEV", }; println!("cargo:rustc-cfg={}", channel); - - std::env::set_var( - "PROTOC", - protoc_bin_vendored::protoc_bin_path().unwrap(), - ); - - prost_build::compile_protos( - &[ - "src/protocol/protobuf/common.proto", - "src/protocol/protobuf/diff.proto", - "src/protocol/protobuf/files.proto", - "src/protocol/protobuf/notifications.proto", - "src/protocol/protobuf/patch.proto", - "src/protocol/protobuf/relay.proto", - "src/protocol/protobuf/scan.proto", - "src/protocol/protobuf/sync.proto", - ], - &["src/protocol"], - ) - .unwrap(); } diff --git a/crates/net/src/client/account/auto_merge.rs b/crates/net/src/account/auto_merge.rs similarity index 96% rename from crates/net/src/client/account/auto_merge.rs rename to crates/net/src/account/auto_merge.rs index 29605f3ef3..171549ff10 100644 --- a/crates/net/src/client/account/auto_merge.rs +++ b/crates/net/src/account/auto_merge.rs @@ -1,31 +1,29 @@ //! Implements auto merge logic for a remote. -use crate::{ - client::{Error, RemoteBridge, Result, SyncClient}, - protocol::{DiffRequest, PatchRequest, ScanRequest}, +use crate::sdk::{ + account::Account, + commit::{CommitHash, CommitProof, CommitTree}, + events::{ + AccountDiff, AccountEvent, CheckedPatch, EventLogExt, EventRecord, + FolderDiff, Patch, WriteEvent, + }, + storage::StorageEventLogs, + vault::VaultId, }; use crate::{ - protocol::sync::{ - EventLogType, ForceMerge, HardConflictResolver, MaybeConflict, Merge, - MergeOutcome, SyncOptions, SyncStatus, - }, - sdk::{ - account::Account, - commit::{CommitHash, CommitProof, CommitTree}, - events::{ - AccountDiff, AccountEvent, CheckedPatch, EventLogExt, - EventRecord, FolderDiff, Patch, WriteEvent, - }, - storage::StorageEventLogs, - vault::VaultId, - }, + protocol::{DiffRequest, PatchRequest, ScanRequest}, + Error, RemoteBridge, Result, SyncClient, }; + use async_recursion::async_recursion; +use sos_protocol::{ + EventLogType, ForceMerge, HardConflictResolver, MaybeConflict, Merge, + MergeOutcome, SyncOptions, SyncStatus, +}; use std::collections::HashSet; use tracing::instrument; const PROOF_SCAN_LIMIT: u16 = 32; -#[cfg(feature = "device")] use sos_sdk::events::{DeviceDiff, DeviceEvent}; #[cfg(feature = "files")] @@ -142,7 +140,6 @@ impl RemoteBridge { has_hard_conflict = has_hard_conflict || hard_conflict; } - #[cfg(feature = "device")] if conflict.device { let hard_conflict = self .auto_merge_device(options, &mut force_merge_outcome) @@ -215,7 +212,6 @@ impl RemoteBridge { force_merge_account ); - #[cfg(feature = "device")] auto_merge_impl!( "auto_merge::device", auto_merge_device, @@ -224,7 +220,6 @@ impl RemoteBridge { device_hard_conflict ); - #[cfg(feature = "device")] auto_merge_conflict_impl!( "hard_conflict::force_merge::device", device_hard_conflict, @@ -342,7 +337,6 @@ impl RemoteBridge { let event_log = log.read().await; event_log.diff_records(Some(&commit)).await? } - #[cfg(feature = "device")] EventLogType::Device => { let log = account.device_log().await?; let event_log = log.read().await; @@ -481,7 +475,6 @@ impl RemoteBridge { }; account.merge_account(diff, &mut outcome).await? } - #[cfg(feature = "device")] EventLogType::Device => { let patch = Patch::::new(events); let diff = DeviceDiff { @@ -542,7 +535,6 @@ impl RemoteBridge { let mut event_log = log.write().await; event_log.apply_records(records).await?; } - #[cfg(feature = "device")] EventLogType::Device => { let log = account.device_log().await?; let mut event_log = log.write().await; @@ -634,7 +626,6 @@ impl RemoteBridge { let mut event_log = log.write().await; event_log.rewind(commit).await? } - #[cfg(feature = "device")] EventLogType::Device => { let log = account.device_log().await?; let mut event_log = log.write().await; @@ -674,7 +665,6 @@ impl RemoteBridge { let event_log = log.read().await; event_log.tree().leaves().unwrap_or_default() } - #[cfg(feature = "device")] EventLogType::Device => { let log = account.device_log().await?; let event_log = log.read().await; diff --git a/crates/net/src/client/account/file_transfers/inflight.rs b/crates/net/src/account/file_transfers/inflight.rs similarity index 98% rename from crates/net/src/client/account/file_transfers/inflight.rs rename to crates/net/src/account/file_transfers/inflight.rs index 24393c67c1..72bc3cb773 100644 --- a/crates/net/src/client/account/file_transfers/inflight.rs +++ b/crates/net/src/account/file_transfers/inflight.rs @@ -1,8 +1,8 @@ //! Tracks inflight file transfer requests. use crate::{ - client::CancelReason, - protocol::sync::{Origin, TransferOperation}, + protocol::{Origin, TransferOperation}, sdk::storage::files::ExternalFile, + CancelReason, }; use std::{ diff --git a/crates/net/src/client/account/file_transfers/mod.rs b/crates/net/src/account/file_transfers/mod.rs similarity index 99% rename from crates/net/src/client/account/file_transfers/mod.rs rename to crates/net/src/account/file_transfers/mod.rs index 4085574fcd..4da066d7e0 100644 --- a/crates/net/src/client/account/file_transfers/mod.rs +++ b/crates/net/src/account/file_transfers/mod.rs @@ -15,9 +15,10 @@ //! Requests are limited to the `concurrent_requests` setting guarded //! by a semaphore and notifications are sent via [InflightTransfers]. use crate::{ - client::{net::NetworkRetry, CancelReason, Error, Result, SyncClient}, - protocol::sync::{FileOperation, Origin, TransferOperation}, + net::NetworkRetry, + protocol::{FileOperation, Origin, TransferOperation}, sdk::{storage::files::ExternalFile, vfs, Paths}, + CancelReason, Error, Result, SyncClient, }; use futures::FutureExt; diff --git a/crates/net/src/client/account/file_transfers/operations.rs b/crates/net/src/account/file_transfers/operations.rs similarity index 99% rename from crates/net/src/client/account/file_transfers/operations.rs rename to crates/net/src/account/file_transfers/operations.rs index 7ae8a377e1..193700692b 100644 --- a/crates/net/src/client/account/file_transfers/operations.rs +++ b/crates/net/src/account/file_transfers/operations.rs @@ -3,8 +3,9 @@ //! Tasks that handle retry until exhaustion for //! download, upload, move and delete operations. use crate::{ - client::{net::NetworkRetry, CancelReason, Error, Result, SyncClient}, + net::NetworkRetry, sdk::{storage::files::ExternalFile, vfs, Paths}, + CancelReason, Error, Result, SyncClient, }; use async_recursion::async_recursion; diff --git a/crates/net/src/client/account/listen.rs b/crates/net/src/account/listen.rs similarity index 96% rename from crates/net/src/client/account/listen.rs rename to crates/net/src/account/listen.rs index a4541bbf1d..e935328ea0 100644 --- a/crates/net/src/client/account/listen.rs +++ b/crates/net/src/account/listen.rs @@ -1,13 +1,9 @@ //! Adds functions for listening to change notifications using //! a websocket connection. use crate::{ - client::{ - sync::RemoteSync, Error, ListenOptions, NetworkAccount, Result, - }, - protocol::{ - sync::{Origin, SyncError, SyncStorage}, - ChangeNotification, - }, + protocol::{ChangeNotification, Origin, SyncError, SyncStorage}, + sync::RemoteSync, + Error, ListenOptions, NetworkAccount, Result, }; use std::sync::Arc; use tokio::sync::mpsc; diff --git a/crates/net/src/client/account/mod.rs b/crates/net/src/account/mod.rs similarity index 100% rename from crates/net/src/client/account/mod.rs rename to crates/net/src/account/mod.rs diff --git a/crates/net/src/client/account/network_account.rs b/crates/net/src/account/network_account.rs similarity index 97% rename from crates/net/src/client/account/network_account.rs rename to crates/net/src/account/network_account.rs index 1cf871698d..65906510b4 100644 --- a/crates/net/src/client/account/network_account.rs +++ b/crates/net/src/account/network_account.rs @@ -1,8 +1,6 @@ //! Network aware account. use crate::{ - protocol::sync::{ - FileOperation, Origin, SyncError, SyncOptions, UpdateSet, - }, + protocol::{Origin, SyncError, SyncOptions, UpdateSet}, sdk::{ account::{ Account, AccountBuilder, AccountChange, AccountData, @@ -12,18 +10,14 @@ use crate::{ }, commit::{CommitHash, CommitState}, crypto::{AccessKey, Cipher, KeyDerivation}, + device::{ + DeviceManager, DevicePublicKey, DeviceSigner, TrustedDevice, + }, events::{AccountEvent, EventLogExt, ReadEvent}, identity::{AccountRef, PublicIdentity}, sha2::{Digest, Sha256}, signer::ecdsa::{Address, BoxedEcdsaSigner}, - storage::{ - files::FileMutationEvent, - search::{ - AccountStatistics, ArchiveFilter, Document, DocumentCount, - DocumentView, QueryFilter, SearchIndex, - }, - AccessOptions, ClientStorage, StorageEventLogs, - }, + storage::{AccessOptions, ClientStorage, StorageEventLogs}, vault::{ secret::{Secret, SecretId, SecretMeta, SecretRow}, Summary, Vault, VaultId, @@ -43,19 +37,19 @@ use tokio::{ sync::{Mutex, RwLock}, }; +#[cfg(feature = "search")] +use crate::sdk::storage::search::{ + AccountStatistics, ArchiveFilter, Document, DocumentCount, DocumentView, + QueryFilter, SearchIndex, +}; + #[cfg(feature = "archive")] use crate::sdk::account::archive::{Inventory, RestoreOptions}; -#[cfg(feature = "device")] -use crate::sdk::device::{ - DeviceManager, DevicePublicKey, DeviceSigner, TrustedDevice, -}; - -#[cfg(feature = "device")] use indexmap::IndexSet; #[cfg(feature = "listen")] -use crate::client::WebSocketHandle; +use crate::WebSocketHandle; #[cfg(feature = "contacts")] use crate::sdk::account::ContactImportProgress; @@ -68,15 +62,17 @@ use crate::sdk::account::security_report::{ #[cfg(feature = "migrate")] use crate::sdk::migrate::import::ImportTarget; -use super::{ - file_transfers::{FileTransferSettings, FileTransfersHandle}, - remote::Remotes, -}; -use crate::client::{Error, RemoteBridge, RemoteSync, Result}; +use super::remote::Remotes; +use crate::{Error, RemoteBridge, RemoteSync, Result}; #[cfg(feature = "files")] -use crate::client::{ - account::file_transfers::{FileTransfers, InflightTransfers}, +use crate::{ + account::file_transfers::{ + FileTransferSettings, FileTransfers, FileTransfersHandle, + InflightTransfers, + }, + protocol::FileOperation, + sdk::storage::files::FileMutationEvent, HttpClient, }; @@ -182,7 +178,6 @@ impl NetworkAccount { } /// Revoke a device. - #[cfg(feature = "device")] pub async fn revoke_device( &mut self, device_key: &crate::sdk::device::DevicePublicKey, @@ -237,7 +232,6 @@ impl NetworkAccount { if !self.is_authenticated().await { hasher.update(docs_path.as_bytes()); } else { - #[cfg(feature = "device")] { let device_signer = self.device_signer().await?; let device_public_key = device_signer.public_key(); @@ -265,9 +259,12 @@ impl NetworkAccount { ) -> Result>> { let remote = self.remote_bridge(&origin).await?; + #[cfg(feature = "files")] if let Some(file_transfers) = self.file_transfers.as_mut() { file_transfers.add_client(remote.client().clone()).await; }; + + #[cfg(feature = "files")] { let mut remotes = self.remotes.write().await; if let Some(handle) = &self.file_transfer_handle { @@ -322,6 +319,7 @@ impl NetworkAccount { let mut remotes = self.remotes.write().await; let remote = remotes.remove(origin); if let Some(remote) = &remote { + #[cfg(feature = "files")] if let Some(file_transfers) = self.file_transfers.as_mut() { file_transfers.remove_client(remote.client()).await; } @@ -563,6 +561,7 @@ impl NetworkAccount { } /// Convert file mutation events into file transfer queue entries. + #[cfg(feature = "files")] async fn queue_file_mutation_events( &self, events: &[FileMutationEvent], @@ -605,7 +604,6 @@ impl Account for NetworkAccount { Ok(account.account_signer().await?) } - #[cfg(feature = "device")] async fn new_device_vault( &mut self, ) -> Result<(DeviceSigner, DeviceManager)> { @@ -613,25 +611,21 @@ impl Account for NetworkAccount { Ok(account.new_device_vault().await?) } - #[cfg(feature = "device")] async fn device_signer(&self) -> Result { let account = self.account.lock().await; Ok(account.device_signer().await?) } - #[cfg(feature = "device")] async fn device_public_key(&self) -> Result { let account = self.account.lock().await; Ok(account.device_public_key().await?) } - #[cfg(feature = "device")] async fn current_device(&self) -> Result { let account = self.account.lock().await; Ok(account.current_device().await?) } - #[cfg(feature = "device")] async fn trusted_devices(&self) -> Result> { let account = self.account.lock().await; Ok(account.trusted_devices().await?) @@ -1065,6 +1059,7 @@ impl Account for NetworkAccount { Ok(()) } + #[cfg(feature = "search")] async fn detached_view( &self, summary: &Summary, @@ -1193,6 +1188,7 @@ impl Account for NetworkAccount { .results .into_iter() .map(|mut result| { + #[cfg(feature = "files")] file_events.append(&mut result.file_events); SecretChange { id: result.id, diff --git a/crates/net/src/client/account/remote.rs b/crates/net/src/account/remote.rs similarity index 94% rename from crates/net/src/client/account/remote.rs rename to crates/net/src/account/remote.rs index d700e774a6..ee57e7e085 100644 --- a/crates/net/src/client/account/remote.rs +++ b/crates/net/src/account/remote.rs @@ -1,12 +1,9 @@ //! Bridge between local storage and a remote server. use crate::{ - client::{ - net::HttpClient, Error, RemoteSync, Result, SyncClient, SyncError, - }, - protocol::sync::{ - self, FileOperation, FileSet, MaybeDiff, Merge, MergeOutcome, Origin, - SyncOptions, SyncPacket, SyncStatus, SyncStorage, TransferOperation, - UpdateSet, + net::HttpClient, + protocol::{ + MaybeDiff, Merge, MergeOutcome, Origin, SyncOptions, SyncPacket, + SyncStatus, SyncStorage, UpdateSet, }, sdk::{ account::{Account, LocalAccount}, @@ -14,13 +11,17 @@ use crate::{ storage::StorageEventLogs, vfs, }, + Error, RemoteSync, Result, SyncClient, SyncError, }; use async_trait::async_trait; use std::{collections::HashMap, sync::Arc}; use tokio::sync::{broadcast, Mutex}; #[cfg(feature = "files")] -use super::file_transfers::FileTransferQueueRequest; +use crate::{ + account::file_transfers::FileTransferQueueRequest, + protocol::{FileOperation, FileSet, TransferOperation}, +}; /// Collection of remote targets for synchronization. pub(crate) type Remotes = HashMap; @@ -54,6 +55,7 @@ impl RemoteBridge { let client = HttpClient::new(origin.clone(), signer, device, connection_id)?; + #[cfg(feature = "files")] let (file_transfer_queue, _) = broadcast::channel::(32); @@ -78,6 +80,8 @@ impl RemoteBridge { let public_account = account.change_set().await?; self.client.create_account(public_account).await?; } + + #[cfg(feature = "files")] self.execute_sync_file_transfers().await?; Ok(()) } @@ -88,7 +92,7 @@ impl RemoteBridge { tracing::debug!("merge_client"); let (needs_sync, local_status, local_changes) = - sync::diff(&*account, remote_status).await?; + sos_protocol::diff(&*account, remote_status).await?; tracing::debug!(needs_sync = %needs_sync, "merge_client"); @@ -114,6 +118,8 @@ impl RemoteBridge { // Compute which external files need to be downloaded // and add to the transfers queue + + #[cfg(feature = "files")] if !outcome.external_files.is_empty() { let paths = account.paths(); // let mut writer = self.transfers.write().await; @@ -159,7 +165,6 @@ impl RemoteBridge { account.merge_account(diff, &mut outcome).await?; } } - #[cfg(feature = "device")] if !maybe_conflict.device { if let Some(MaybeDiff::Diff(diff)) = remote_changes.diff.device @@ -222,6 +227,7 @@ impl RemoteBridge { } } + #[cfg(feature = "files")] async fn execute_sync_file_transfers(&self) -> Result<()> { let external_files = { let account = self.account.lock().await; @@ -280,6 +286,7 @@ impl RemoteSync for RemoteBridge { } } + #[cfg(feature = "files")] async fn sync_file_transfers( &self, options: &SyncOptions, @@ -323,8 +330,8 @@ impl RemoteSync for RemoteBridge { #[cfg(feature = "listen")] mod listen { use crate::{ - client::{ListenOptions, RemoteBridge, WebSocketHandle}, - protocol::ChangeNotification, + protocol::ChangeNotification, ListenOptions, RemoteBridge, + WebSocketHandle, }; use tokio::sync::mpsc; diff --git a/crates/net/src/client/account/sync.rs b/crates/net/src/account/sync.rs similarity index 93% rename from crates/net/src/client/account/sync.rs rename to crates/net/src/account/sync.rs index cf75f489f3..3ed5ed3aaf 100644 --- a/crates/net/src/client/account/sync.rs +++ b/crates/net/src/account/sync.rs @@ -1,33 +1,32 @@ //! Adds sync capability to network account. use crate::{ - client::{NetworkAccount, RemoteSync, SyncClient, SyncError}, - protocol::sync::{ - FileSet, FileTransfersSet, Origin, SyncOptions, SyncStatus, - SyncStorage, UpdateSet, - }, + protocol::{Origin, SyncOptions, SyncStatus, SyncStorage, UpdateSet}, sdk::{ events::{AccountEventLog, FolderEventLog}, storage::StorageEventLogs, vault::VaultId, Result, }, + NetworkAccount, RemoteSync, SyncClient, SyncError, }; use async_trait::async_trait; use std::{collections::HashMap, sync::Arc}; use tokio::sync::RwLock; -#[cfg(feature = "device")] use sos_sdk::events::DeviceEventLog; #[cfg(feature = "files")] -use sos_sdk::events::FileEventLog; +use crate::{ + protocol::{FileSet, FileTransfersSet}, + sdk::events::FileEventLog, +}; /// Server status for all remote origins. -pub type ServerStatus = HashMap>; +pub type ServerStatus = HashMap>; /// Transfer status for all remote origins. -pub type TransferStatus = - HashMap>; +#[cfg(feature = "files")] +pub type TransferStatus = HashMap>; impl NetworkAccount { /// Sync status for remote servers. @@ -119,6 +118,7 @@ impl RemoteSync for NetworkAccount { maybe_error.into_option() } + #[cfg(feature = "files")] async fn sync_file_transfers( &self, options: &SyncOptions, @@ -190,7 +190,6 @@ impl StorageEventLogs for NetworkAccount { account.account_log().await } - #[cfg(feature = "device")] async fn device_log(&self) -> Result>> { let account = self.account.lock().await; account.device_log().await diff --git a/crates/net/src/client/error.rs b/crates/net/src/client/error.rs deleted file mode 100644 index c2e1bf1cab..0000000000 --- a/crates/net/src/client/error.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! Error type for the client module. -use crate::protocol::sync::{MaybeConflict, Origin, SyncError, SyncStatus}; -use http::StatusCode; -use serde_json::Value; -use std::error::Error as StdError; -use std::path::PathBuf; -use thiserror::Error; - -#[cfg(feature = "client")] -use crate::client::CancelReason; - -/// Errors generated by the client module. -#[derive(Debug, Error)] -pub enum Error { - /// Error generated when a path is not a directory. - #[error("path {0} is not a directory")] - NotDirectory(PathBuf), - - /// Error generated when a path is not a file. - #[error("path {0} is not a file")] - NotFile(PathBuf), - - /// Error generated when a file already exists. - #[error("file {0} already exists")] - FileExists(PathBuf), - - /// Error generated when an unexpected response code is received. - #[error("unexpected response status code {0}")] - ResponseCode(StatusCode), - - /// Error generated when an unexpected response code is received. - #[error("unexpected response {1} (code: {0})")] - ResponseJson(StatusCode, Value), - - /// Error generated when an unexpected content type is returend. - #[error("unexpected content type {0}, expected: {1}")] - ContentType(String, String), - - /// Error generated when a return value is expected from a RPC call - /// but the response did not have a result. - #[error("method did not return a value")] - NoReturnValue, - - /// Error generated when a remote origin could not be found. - #[error("origin '{0}' not found")] - OriginNotFound(Origin), - - /// Error generated when a websocket message is not binary. - #[error("not binary message type on websocket")] - NotBinaryWebsocketMessageType, - - /// Error generated attempting to revoke the current device. - #[error("cannot revoke access to this device")] - RevokeDeviceSelf, - - /// Error generated when failing to sync after revoking a device. - #[error("failed to sync after revoking device, {0}")] - RevokeDeviceSync(SyncError), - - /// Error generated force update of an account failed. - #[error("failed to force update, {0}")] - ForceUpdate(SyncError), - - /// Error generated trying to parse a device enrollment sharing URL. - #[deprecated] - #[error("invalid share url for device enrollment")] - InvalidShareUrl, - - /// Error generated when a downloaded file checksum does not - /// match the expected checksum. - #[error("file download checksum mismatch; expected '{0}' but got '{1}'")] - FileChecksumMismatch(String, String), - - /// Error generated when a file transfer is canceled. - /// - /// The boolean flag indicates whether the cancellation was - /// triggered by the user. - - #[cfg(feature = "client")] - #[error("file transfer canceled")] - TransferCanceled(CancelReason), - - /// Overflow error calculating the retry exponential factor. - #[cfg(feature = "client")] - #[error("retry overflow")] - RetryOverflow, - - /// Network retry was canceled possibly by the user. - #[cfg(feature = "client")] - #[error("network retry was canceled")] - RetryCanceled(CancelReason), - - /// Error generated when a soft conflict was detected. - /// - /// A soft conflict may be resolved by searching for a - /// common ancestor commit and merging changes since - /// the common ancestor commit. - #[error("soft conflict")] - SoftConflict { - /// Conflict information. - conflict: MaybeConflict, - /// Local information sent to the remote. - local: SyncStatus, - /// Remote information in the server reply. - remote: SyncStatus, - }, - - /// Error generated when a hard conflict was detected. - /// - /// A hard conflict is triggered after a soft conflict - /// attempted to scan proofs on a remote and was unable - /// to find a common ancestor commit. - #[error("hard conflict")] - HardConflict, - - /// Error generated by the main net library. - #[error(transparent)] - Net(#[from] crate::Error), - - /// Error generated parsing to an integer. - #[error(transparent)] - ParseInt(#[from] std::num::ParseIntError), - - /// Error generated converting a header to a string. - #[error(transparent)] - ToStr(#[from] reqwest::header::ToStrError), - - /// Error generated by the io module. - #[error(transparent)] - Io(#[from] std::io::Error), - - /// Error generated by the JSON library. - #[error(transparent)] - Json(#[from] serde_json::Error), - - /// Error generated attempting to convert from a slice. - #[error(transparent)] - TryFromSlice(#[from] std::array::TryFromSliceError), - - /// Error generated by the SDK library. - #[error(transparent)] - Sdk(#[from] sos_sdk::Error), - - /// Error generated by the HTTP request library. - #[error(transparent)] - Http(#[from] reqwest::Error), - - /// Error generated attempting to parse a URL. - #[error(transparent)] - UrlParse(#[from] url::ParseError), - - /// Error generated attempting to convert to a UTF-8 string. - #[error(transparent)] - Utf8(#[from] std::str::Utf8Error), - - /// Error generated decoding a base58 string. - #[error(transparent)] - Base58Decode(#[from] bs58::decode::Error), - - /// Error generated converting an HTTP status code. - #[error(transparent)] - HttpStatus(#[from] http::status::InvalidStatusCode), - - /// Error generated by the websocket client. - #[cfg(feature = "listen")] - #[error(transparent)] - WebSocket(#[from] tokio_tungstenite::tungstenite::Error), - - /// Error generated when converting to a UUID. - #[error(transparent)] - Uuid(#[from] uuid::Error), - - /// Error generated when parsing from hex. - #[error(transparent)] - Hex(#[from] hex::FromHexError), - - /// Error generated by the wire protocol library. - #[error(transparent)] - Protocol(#[from] crate::protocol::Error), - - /// Error generated by the migrate library. - #[error(transparent)] - #[cfg(feature = "migrate")] - Migrate(#[from] sos_sdk::migrate::Error), -} - -impl Error { - /// Determine if this error is a secret not found. - pub fn is_secret_not_found(&self) -> bool { - matches!(self, Error::Sdk(crate::sdk::Error::SecretNotFound(_))) - } - - /// Determine if this error is a hard conflict. - pub fn is_hard_conflict(&self) -> bool { - matches!(self, Error::HardConflict) - } - - /// Determine if this is a canceled error and - /// whether the cancellation was triggered by the user. - #[cfg(feature = "client")] - pub fn cancellation_reason(&self) -> Option<&CancelReason> { - let source = source_error(self); - if let Some(err) = source.downcast_ref::() { - if let Error::TransferCanceled(reason) = err { - Some(reason) - } else { - None - } - } else { - None - } - } -} - -pub(crate) fn source_error<'a>( - error: &'a (dyn StdError + 'static), -) -> &'a (dyn StdError + 'static) { - let mut source = error; - while let Some(next_source) = source.source() { - source = next_source; - } - source -} diff --git a/crates/net/src/client/mod.rs b/crates/net/src/client/mod.rs deleted file mode 100644 index 2bff0d30c2..0000000000 --- a/crates/net/src/client/mod.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Client user account and types for bridging with remote origins. - -mod account; -mod error; -#[cfg(feature = "hashcheck")] -pub mod hashcheck; -mod net; -#[cfg(all(feature = "device", feature = "pairing"))] -pub mod pairing; -mod sync; - -pub use account::*; -pub use error::Error; -#[cfg(feature = "listen")] -pub use net::{changes, connect, ListenOptions, WebSocketHandle}; -pub use net::{HttpClient, NetworkRetry}; -pub use sync::{RemoteSync, SyncClient, SyncError}; - -/// Result type for the client module. -pub type Result = std::result::Result; - -/// Determine if the offline environment variable is set. -pub fn is_offline() -> bool { - use crate::sdk::constants::SOS_OFFLINE; - std::env::var(SOS_OFFLINE).ok().is_some() -} - -#[cfg(any(feature = "listen", feature = "pairing"))] -mod websocket_request { - use super::Result; - use sos_sdk::url::Url; - use tokio_tungstenite::tungstenite::{ - self, client::IntoClientRequest, handshake::client::generate_key, - }; - - pub(crate) struct WebSocketRequest { - pub(crate) uri: Url, - host: String, - bearer: Option, - origin: url::Origin, - } - - impl WebSocketRequest { - /// Create a new websocket request. - pub fn new(url: &Url, path: &str) -> Result { - let origin = url.origin(); - let host = url.host_str().unwrap().to_string(); - - let mut uri = url.join(path)?; - let scheme = if uri.scheme() == "http" { - "ws" - } else if uri.scheme() == "https" { - "wss" - } else { - panic!("bad url scheme for websocket, requires http(s)"); - }; - - uri.set_scheme(scheme) - .expect("failed to set websocket scheme"); - - Ok(Self { - host, - uri, - origin, - bearer: None, - }) - } - - /// Set bearer authorization. - pub fn set_bearer(&mut self, bearer: String) { - self.bearer = Some(bearer); - } - } - - impl IntoClientRequest for WebSocketRequest { - fn into_client_request( - self, - ) -> std::result::Result, tungstenite::Error> - { - let origin = self.origin.unicode_serialization(); - let mut request = - http::Request::builder().uri(self.uri.to_string()); - if let Some(bearer) = self.bearer { - request = request.header("authorization", bearer); - } - request = request - .header("sec-websocket-key", generate_key()) - .header("sec-websocket-version", "13") - .header("host", self.host) - .header("origin", origin) - .header("connection", "keep-alive, Upgrade") - .header("upgrade", "websocket"); - Ok(request.body(())?) - } - } -} - -#[cfg(any(feature = "listen", feature = "pairing"))] -pub(crate) use websocket_request::WebSocketRequest; diff --git a/crates/net/src/error.rs b/crates/net/src/error.rs index e7db613a4f..77505b46af 100644 --- a/crates/net/src/error.rs +++ b/crates/net/src/error.rs @@ -1,42 +1,213 @@ -//! Error type for the networking library. +//! Error type for the client module. +use crate::CancelReason; +use http::StatusCode; +use serde_json::Value; +use sos_protocol::{MaybeConflict, Origin, SyncError, SyncStatus}; +use std::error::Error as StdError; +use std::path::PathBuf; use thiserror::Error; -/// Errors generated by the networking library. +/// Errors generated by the client module. #[derive(Debug, Error)] pub enum Error { - /// Error generated by the std::io module. + /// Error generated when a path is not a directory. + #[error("path {0} is not a directory")] + NotDirectory(PathBuf), + + /// Error generated when a path is not a file. + #[error("path {0} is not a file")] + NotFile(PathBuf), + + /// Error generated when a file already exists. + #[error("file {0} already exists")] + FileExists(PathBuf), + + /// Error generated when an unexpected response code is received. + #[error("unexpected response status code {0}")] + ResponseCode(StatusCode), + + /// Error generated when an unexpected response code is received. + #[error("unexpected response {1} (code: {0})")] + ResponseJson(StatusCode, Value), + + /// Error generated when an unexpected content type is returend. + #[error("unexpected content type {0}, expected: {1}")] + ContentType(String, String), + + /// Error generated when a return value is expected from a RPC call + /// but the response did not have a result. + #[error("method did not return a value")] + NoReturnValue, + + /// Error generated when a remote origin could not be found. + #[error("origin '{0}' not found")] + OriginNotFound(Origin), + + /// Error generated when a websocket message is not binary. + #[error("not binary message type on websocket")] + NotBinaryWebsocketMessageType, + + /// Error generated attempting to revoke the current device. + #[error("cannot revoke access to this device")] + RevokeDeviceSelf, + + /// Error generated when failing to sync after revoking a device. + #[error("failed to sync after revoking device, {0}")] + RevokeDeviceSync(SyncError), + + /// Error generated force update of an account failed. + #[error("failed to force update, {0}")] + ForceUpdate(SyncError), + + /// Error generated trying to parse a device enrollment sharing URL. + #[deprecated] + #[error("invalid share url for device enrollment")] + InvalidShareUrl, + + /// Error generated when a downloaded file checksum does not + /// match the expected checksum. + #[error("file download checksum mismatch; expected '{0}' but got '{1}'")] + FileChecksumMismatch(String, String), + + /// Error generated when a file transfer is canceled. + /// + /// The boolean flag indicates whether the cancellation was + /// triggered by the user. + + #[error("file transfer canceled")] + TransferCanceled(CancelReason), + + /// Overflow error calculating the retry exponential factor. + #[error("retry overflow")] + RetryOverflow, + + /// Network retry was canceled possibly by the user. + #[error("network retry was canceled")] + RetryCanceled(CancelReason), + + /// Error generated when a soft conflict was detected. + /// + /// A soft conflict may be resolved by searching for a + /// common ancestor commit and merging changes since + /// the common ancestor commit. + #[error("soft conflict")] + SoftConflict { + /// Conflict information. + conflict: MaybeConflict, + /// Local information sent to the remote. + local: SyncStatus, + /// Remote information in the server reply. + remote: SyncStatus, + }, + + /// Error generated when a hard conflict was detected. + /// + /// A hard conflict is triggered after a soft conflict + /// attempted to scan proofs on a remote and was unable + /// to find a common ancestor commit. + #[error("hard conflict")] + HardConflict, + + /// Error generated parsing to an integer. + #[error(transparent)] + ParseInt(#[from] std::num::ParseIntError), + + /// Error generated converting a header to a string. + #[error(transparent)] + ToStr(#[from] reqwest::header::ToStrError), + + /// Error generated by the io module. #[error(transparent)] Io(#[from] std::io::Error), - /// Error generated converting from a slice. + /// Error generated by the JSON library. + #[error(transparent)] + Json(#[from] serde_json::Error), + + /// Error generated attempting to convert from a slice. #[error(transparent)] TryFromSlice(#[from] std::array::TryFromSliceError), - /// Error generated by the core library. + /// Error generated by the SDK library. #[error(transparent)] Sdk(#[from] sos_sdk::Error), - /// Error generate by the ECDSA library. + /// Error generated by the HTTP request library. #[error(transparent)] - Ecdsa(#[from] sos_sdk::k256::ecdsa::Error), + Http(#[from] reqwest::Error), - /// Error generate by the elliptic curve library. + /// Error generated attempting to parse a URL. #[error(transparent)] - Elliptic(#[from] sos_sdk::k256::elliptic_curve::Error), + UrlParse(#[from] url::ParseError), - /// Error generated by the JSON library. + /// Error generated attempting to convert to a UTF-8 string. #[error(transparent)] - Json(#[from] serde_json::Error), + Utf8(#[from] std::str::Utf8Error), + + /// Error generated decoding a base58 string. + #[error(transparent)] + Base58Decode(#[from] bs58::decode::Error), + + /// Error generated converting an HTTP status code. + #[error(transparent)] + HttpStatus(#[from] http::status::InvalidStatusCode), + + /// Error generated by the websocket client. + #[cfg(feature = "listen")] + #[error(transparent)] + WebSocket(#[from] tokio_tungstenite::tungstenite::Error), - /// Error generated by the Base58 library. + /// Error generated when converting to a UUID. #[error(transparent)] - Base58(#[from] bs58::encode::Error), + Uuid(#[from] uuid::Error), - /// Error generated by the protobuf library when encoding. + /// Error generated when parsing from hex. #[error(transparent)] - ProtoBufEncode(#[from] prost::EncodeError), + Hex(#[from] hex::FromHexError), - /// Error generated by the protobuf library when decoding. + /// Error generated by the wire protocol library. #[error(transparent)] - ProtoBufDecode(#[from] prost::DecodeError), + Protocol(#[from] crate::protocol::Error), + + /// Error generated by the migrate library. + #[error(transparent)] + #[cfg(feature = "migrate")] + Migrate(#[from] sos_sdk::migrate::Error), +} + +impl Error { + /// Determine if this error is a secret not found. + pub fn is_secret_not_found(&self) -> bool { + matches!(self, Error::Sdk(crate::sdk::Error::SecretNotFound(_))) + } + + /// Determine if this error is a hard conflict. + pub fn is_hard_conflict(&self) -> bool { + matches!(self, Error::HardConflict) + } + + /// Determine if this is a canceled error and + /// whether the cancellation was triggered by the user. + pub fn cancellation_reason(&self) -> Option<&CancelReason> { + let source = source_error(self); + if let Some(err) = source.downcast_ref::() { + if let Error::TransferCanceled(reason) = err { + Some(reason) + } else { + None + } + } else { + None + } + } +} + +pub(crate) fn source_error<'a>( + error: &'a (dyn StdError + 'static), +) -> &'a (dyn StdError + 'static) { + let mut source = error; + while let Some(next_source) = source.source() { + source = next_source; + } + source } diff --git a/crates/net/src/client/hashcheck.rs b/crates/net/src/hashcheck.rs similarity index 100% rename from crates/net/src/client/hashcheck.rs rename to crates/net/src/hashcheck.rs diff --git a/crates/net/src/lib.rs b/crates/net/src/lib.rs index f9291c3484..b2052a2428 100644 --- a/crates/net/src/lib.rs +++ b/crates/net/src/lib.rs @@ -3,27 +3,111 @@ #![deny(missing_docs)] #![forbid(unsafe_code)] #![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))] -//! Networking library for the [sos-sdk crate](https://docs.rs/sos-sdk/latest/sos_sdk/). +//! Networking support for the [sos-sdk crate](https://docs.rs/sos-sdk/latest/sos_sdk/). //! -//! If the `listen` feature is enabled the server and client are compiled +//! If the `listen` feature is enabled the client is compiled //! with support for sending and listening for change notification over //! a websocket connection. -#[cfg(feature = "client")] -pub mod client; +mod account; mod error; -pub mod protocol; -#[cfg(feature = "server")] -pub mod server; +#[cfg(feature = "hashcheck")] +pub mod hashcheck; +mod net; +#[cfg(feature = "pairing")] +pub mod pairing; +mod sync; -#[cfg(test)] -mod tests; +pub use reqwest; +pub use sos_sdk as sdk; +// FIXME: remove this +pub use sos_protocol as protocol; -/// Result type for the network module. -pub type Result = std::result::Result; +pub use account::*; pub use error::Error; +#[cfg(feature = "listen")] +pub use net::{changes, connect, ListenOptions, WebSocketHandle}; +pub use net::{HttpClient, NetworkRetry}; +pub use sync::{RemoteSync, SyncClient, SyncError}; -#[cfg(feature = "client")] -pub use reqwest; +/// Result type for the client module. +pub type Result = std::result::Result; -pub use sos_sdk as sdk; +/// Determine if the offline environment variable is set. +pub fn is_offline() -> bool { + use crate::sdk::constants::SOS_OFFLINE; + std::env::var(SOS_OFFLINE).ok().is_some() +} + +#[cfg(any(feature = "listen", feature = "pairing"))] +mod websocket_request { + use super::Result; + use sos_sdk::url::Url; + use tokio_tungstenite::tungstenite::{ + self, client::IntoClientRequest, handshake::client::generate_key, + }; + + pub(crate) struct WebSocketRequest { + pub(crate) uri: Url, + host: String, + bearer: Option, + origin: url::Origin, + } + + impl WebSocketRequest { + /// Create a new websocket request. + pub fn new(url: &Url, path: &str) -> Result { + let origin = url.origin(); + let host = url.host_str().unwrap().to_string(); + + let mut uri = url.join(path)?; + let scheme = if uri.scheme() == "http" { + "ws" + } else if uri.scheme() == "https" { + "wss" + } else { + panic!("bad url scheme for websocket, requires http(s)"); + }; + + uri.set_scheme(scheme) + .expect("failed to set websocket scheme"); + + Ok(Self { + host, + uri, + origin, + bearer: None, + }) + } + + /// Set bearer authorization. + pub fn set_bearer(&mut self, bearer: String) { + self.bearer = Some(bearer); + } + } + + impl IntoClientRequest for WebSocketRequest { + fn into_client_request( + self, + ) -> std::result::Result, tungstenite::Error> + { + let origin = self.origin.unicode_serialization(); + let mut request = + http::Request::builder().uri(self.uri.to_string()); + if let Some(bearer) = self.bearer { + request = request.header("authorization", bearer); + } + request = request + .header("sec-websocket-key", generate_key()) + .header("sec-websocket-version", "13") + .header("host", self.host) + .header("origin", origin) + .header("connection", "keep-alive, Upgrade") + .header("upgrade", "websocket"); + Ok(request.body(())?) + } + } +} + +#[cfg(any(feature = "listen", feature = "pairing"))] +pub(crate) use websocket_request::WebSocketRequest; diff --git a/crates/net/src/client/net/http.rs b/crates/net/src/net/http.rs similarity index 97% rename from crates/net/src/client/net/http.rs rename to crates/net/src/net/http.rs index c9906033fa..4f83ad1a7e 100644 --- a/crates/net/src/client/net/http.rs +++ b/crates/net/src/net/http.rs @@ -7,20 +7,17 @@ use serde_json::Value; use tracing::instrument; use crate::{ - client::{CancelReason, Error, Result, SyncClient}, protocol::{ - sync::{ - CreateSet, FileSet, FileTransfersSet, Origin, SyncPacket, - SyncStatus, UpdateSet, - }, - DiffRequest, DiffResponse, PatchRequest, PatchResponse, ScanRequest, - ScanResponse, WireEncodeDecode, + CreateSet, DiffRequest, DiffResponse, Origin, PatchRequest, + PatchResponse, ScanRequest, ScanResponse, SyncPacket, SyncStatus, + UpdateSet, WireEncodeDecode, }, sdk::{ constants::MIME_TYPE_PROTOBUF, sha2::{Digest, Sha256}, signer::{ecdsa::BoxedEcdsaSigner, ed25519::BoxedEd25519Signer}, }, + CancelReason, Error, Result, SyncClient, }; use std::{fmt, path::Path, time::Duration}; use url::Url; @@ -30,19 +27,17 @@ use super::{ }; #[cfg(feature = "listen")] -use crate::protocol::ChangeNotification; - -#[cfg(feature = "listen")] -use super::websocket::WebSocketChangeListener; - -#[cfg(feature = "files")] -use crate::sdk::storage::files::ExternalFile; +use crate::{ + net::websocket::WebSocketChangeListener, protocol::ChangeNotification, + ListenOptions, WebSocketHandle, +}; #[cfg(feature = "files")] -use crate::client::ProgressChannel; - -#[cfg(feature = "listen")] -use crate::client::{ListenOptions, WebSocketHandle}; +use crate::{ + protocol::{FileSet, FileTransfersSet}, + sdk::storage::files::ExternalFile, + ProgressChannel, +}; /// Client that can synchronize with a server over HTTP(S). #[derive(Clone)] @@ -747,6 +742,7 @@ impl SyncClient for HttpClient { Ok(status) } + #[cfg(feature = "files")] #[instrument(skip_all)] async fn compare_files( &self, diff --git a/crates/net/src/client/net/mod.rs b/crates/net/src/net/mod.rs similarity index 99% rename from crates/net/src/client/net/mod.rs rename to crates/net/src/net/mod.rs index 11493d6ce3..18dd195541 100644 --- a/crates/net/src/client/net/mod.rs +++ b/crates/net/src/net/mod.rs @@ -1,6 +1,6 @@ //! HTTP transport trait and implementations. use super::{Error, Result}; -use crate::client::CancelReason; +use crate::CancelReason; use sos_sdk::{ encode, signer::{ diff --git a/crates/net/src/client/net/websocket.rs b/crates/net/src/net/websocket.rs similarity index 98% rename from crates/net/src/client/net/websocket.rs rename to crates/net/src/net/websocket.rs index 3f77913ccb..e83cf133ba 100644 --- a/crates/net/src/client/net/websocket.rs +++ b/crates/net/src/net/websocket.rs @@ -20,10 +20,9 @@ use tokio::{net::TcpStream, sync::watch}; use sos_sdk::signer::{ecdsa::BoxedEcdsaSigner, ed25519::BoxedEd25519Signer}; use crate::{ - client::{ - net::NetworkRetry, CancelReason, Error, Result, WebSocketRequest, - }, - protocol::{sync::Origin, ChangeNotification, WireEncodeDecode}, + net::NetworkRetry, + protocol::{ChangeNotification, Origin, WireEncodeDecode}, + CancelReason, Error, Result, WebSocketRequest, }; use super::{ diff --git a/crates/net/src/client/pairing/enrollment.rs b/crates/net/src/pairing/enrollment.rs similarity index 97% rename from crates/net/src/client/pairing/enrollment.rs rename to crates/net/src/pairing/enrollment.rs index 2890c6a2c1..7d54971f18 100644 --- a/crates/net/src/client/pairing/enrollment.rs +++ b/crates/net/src/pairing/enrollment.rs @@ -1,10 +1,7 @@ //! Enroll a device to an account on a remote server. use crate::{ - client::{ - pairing::{Error, Result}, - HttpClient, NetworkAccount, SyncClient, - }, - protocol::sync::Origin, + pairing::{Error, Result}, + protocol::Origin, sdk::{ account::Account, crypto::AccessKey, @@ -22,13 +19,13 @@ use crate::{ vault::{VaultAccess, VaultId, VaultWriter}, vfs, Paths, }, + HttpClient, NetworkAccount, SyncClient, }; use std::{ collections::{HashMap, HashSet}, path::{Path, PathBuf}, }; -#[cfg(feature = "device")] use crate::sdk::events::{DeviceEventLog, DevicePatch}; /// Enroll a device. @@ -125,7 +122,6 @@ impl DeviceEnrollment { let change_set = self.client.fetch_account().await?; self.create_folders(change_set.folders).await?; self.create_account(change_set.account).await?; - #[cfg(feature = "device")] self.create_device(change_set.device).await?; self.create_identity(change_set.identity).await?; @@ -204,7 +200,6 @@ impl DeviceEnrollment { Ok(()) } - #[cfg(feature = "device")] async fn create_device(&self, patch: DevicePatch) -> Result<()> { let file = self.paths.device_events(); let mut event_log = DeviceEventLog::new_device(file).await?; diff --git a/crates/net/src/client/pairing/error.rs b/crates/net/src/pairing/error.rs similarity index 94% rename from crates/net/src/client/pairing/error.rs rename to crates/net/src/pairing/error.rs index 0acdd8fb24..e0d857874f 100644 --- a/crates/net/src/client/pairing/error.rs +++ b/crates/net/src/pairing/error.rs @@ -1,5 +1,5 @@ //! Error type for the pairing module. -use crate::protocol::sync::SyncError; +use crate::protocol::SyncError; use thiserror::Error; /// Errors generated by the pairing library. @@ -16,7 +16,7 @@ pub enum Error { /// Error generated failing to sync devices patch. #[error("failed to sync devices: {0}")] - DevicePatchSync(SyncError), + DevicePatchSync(SyncError), /// Error generated trying to access device enrollment /// before pairing protocol completion. @@ -36,7 +36,7 @@ pub enum Error { /// Error generated when failing to sync after completing /// device enrollment. #[error("could not sync after device enrollment authentication: '{0}'")] - EnrollSync(SyncError), + EnrollSync(SyncError), /// Error generated when the protocol is in the wrong state /// or a packet payload is not of the expected type. @@ -45,7 +45,7 @@ pub enum Error { /// Error generated by the client library. #[error(transparent)] - Client(#[from] crate::client::Error), + Client(#[from] crate::Error), /// Error generated by the SDK library. #[error(transparent)] diff --git a/crates/net/src/client/pairing/mod.rs b/crates/net/src/pairing/mod.rs similarity index 100% rename from crates/net/src/client/pairing/mod.rs rename to crates/net/src/pairing/mod.rs diff --git a/crates/net/src/client/pairing/share_url.rs b/crates/net/src/pairing/share_url.rs similarity index 100% rename from crates/net/src/client/pairing/share_url.rs rename to crates/net/src/pairing/share_url.rs diff --git a/crates/net/src/client/pairing/websocket.rs b/crates/net/src/pairing/websocket.rs similarity index 99% rename from crates/net/src/client/pairing/websocket.rs rename to crates/net/src/pairing/websocket.rs index 3d16328629..90ecb91dfc 100644 --- a/crates/net/src/client/pairing/websocket.rs +++ b/crates/net/src/pairing/websocket.rs @@ -1,12 +1,10 @@ //! Protocol for pairing devices. use super::{DeviceEnrollment, Error, Result, ServerPairUrl}; use crate::{ - client::{sync::RemoteSync, NetworkAccount, WebSocketRequest}, protocol::{ - pairing_message, - sync::{Origin, SyncOptions}, - PairingConfirm, PairingMessage, PairingReady, PairingRequest, - ProtoMessage, RelayHeader, RelayPacket, RelayPayload, + pairing_message, Origin, PairingConfirm, PairingMessage, + PairingReady, PairingRequest, ProtoMessage, RelayHeader, RelayPacket, + RelayPayload, SyncOptions, }, sdk::{ account::Account, @@ -15,6 +13,8 @@ use crate::{ signer::ecdsa::SingleParty, url::Url, }, + sync::RemoteSync, + NetworkAccount, WebSocketRequest, }; use futures::{ select, @@ -847,7 +847,7 @@ impl<'a> AcceptPairing<'a> { async fn encrypt( transport: &mut TransportState, message: T, -) -> crate::client::pairing::Result { +) -> crate::pairing::Result { let mut plaintext = Vec::new(); message.encode(&mut plaintext)?; let mut contents = vec![0u8; plaintext.len() + TAGLEN]; @@ -860,7 +860,7 @@ async fn decrypt( transport: &mut TransportState, length: usize, message: &[u8], -) -> crate::client::pairing::Result { +) -> crate::pairing::Result { let mut contents = vec![0; length]; transport.read_message(&message[..length], &mut contents)?; let message = &contents[..contents.len() - TAGLEN]; diff --git a/crates/net/src/server/mod.rs b/crates/net/src/server/mod.rs deleted file mode 100644 index 8ce6ff5d79..0000000000 --- a/crates/net/src/server/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Web server implementation. -mod api_docs; -mod authenticate; -mod backend; -mod config; -mod error; -mod handlers; -mod server; -mod storage; - -pub use error::Error; -/// Result type for the server module. -pub type Result = std::result::Result; - -pub use backend::Backend; -pub use config::*; -pub use server::{Server, ServerBackend, ServerState, ServerTransfer, State}; diff --git a/crates/net/src/client/sync.rs b/crates/net/src/sync.rs similarity index 89% rename from crates/net/src/client/sync.rs rename to crates/net/src/sync.rs index 3d58132451..bcb4b6d5ca 100644 --- a/crates/net/src/client/sync.rs +++ b/crates/net/src/sync.rs @@ -1,20 +1,18 @@ use super::Error; use crate::{ - client::{CancelReason, Result}, protocol::{ - sync::{ - CreateSet, Origin, SyncOptions, SyncPacket, SyncStatus, UpdateSet, - }, - DiffRequest, DiffResponse, PatchRequest, PatchResponse, ScanRequest, - ScanResponse, + CreateSet, DiffRequest, DiffResponse, Origin, PatchRequest, + PatchResponse, ScanRequest, ScanResponse, SyncOptions, SyncPacket, + SyncStatus, UpdateSet, }, + CancelReason, Result, }; use async_trait::async_trait; use sos_sdk::storage; use std::path::Path; /// Error type that can be returned from a sync operation. -pub type SyncError = crate::protocol::sync::SyncError; +pub type SyncError = crate::protocol::SyncError; /// Trait for types that can sync accounts with a remote. #[async_trait] @@ -42,6 +40,7 @@ pub trait RemoteSync { /// Updates the file transfers queue with any pending /// uploads or downloads by comparing the local file /// state with the file state on remote server(s). + #[cfg(feature = "files")] async fn sync_file_transfers( &self, options: &SyncOptions, @@ -105,7 +104,7 @@ pub trait SyncClient { &self, file_info: &storage::files::ExternalFile, path: &Path, - progress: crate::client::ProgressChannel, + progress: crate::ProgressChannel, cancel: tokio::sync::watch::Receiver, ) -> Result; @@ -115,7 +114,7 @@ pub trait SyncClient { &self, file_info: &storage::files::ExternalFile, path: &Path, - progress: crate::client::ProgressChannel, + progress: crate::ProgressChannel, cancel: tokio::sync::watch::Receiver, ) -> Result; @@ -145,6 +144,6 @@ pub trait SyncClient { #[cfg(feature = "files")] async fn compare_files( &self, - local_files: crate::protocol::sync::FileSet, - ) -> Result; + local_files: crate::protocol::FileSet, + ) -> Result; } diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml new file mode 100644 index 0000000000..5558f29fd3 --- /dev/null +++ b/crates/protocol/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "sos-protocol" +version = "0.14.1" +edition = "2021" +description = "Networking and sync protocol types for the Save Our Secrets SDK." +homepage = "https://saveoursecrets.com" +license = "MIT OR Apache-2.0" +repository = "https://github.com/saveoursecrets/sdk" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[features] +default = [] +listen = [] +pairing = [] +files = ["sos-sdk/files"] +search = ["sos-sdk/search"] + +[dependencies] +thiserror.workspace = true +tracing.workspace = true +async-trait.workspace = true +serde.workspace = true +uuid.workspace = true +url.workspace = true +futures.workspace = true +indexmap.workspace = true +rs_merkle.workspace = true +prost.workspace = true +tokio = { version = "1", features = ["rt", "macros"] } + +[dependencies.sos-sdk] +version = "0.14.0" +path = "../sdk" + +[dev-dependencies] +anyhow = "1" + +[build-dependencies] +rustc_version = "0.4.0" +prost-build = "0.12.6" +protoc-bin-vendored = "3" diff --git a/crates/protocol/build.rs b/crates/protocol/build.rs new file mode 100644 index 0000000000..de772f2753 --- /dev/null +++ b/crates/protocol/build.rs @@ -0,0 +1,33 @@ +extern crate prost_build; +use rustc_version::{version_meta, Channel}; + +fn main() { + // Set cfg flags depending on release channel + let channel = match version_meta().unwrap().channel { + Channel::Stable => "CHANNEL_STABLE", + Channel::Beta => "CHANNEL_BETA", + Channel::Nightly => "CHANNEL_NIGHTLY", + Channel::Dev => "CHANNEL_DEV", + }; + println!("cargo:rustc-cfg={}", channel); + + std::env::set_var( + "PROTOC", + protoc_bin_vendored::protoc_bin_path().unwrap(), + ); + + prost_build::compile_protos( + &[ + "src/protobuf/common.proto", + "src/protobuf/diff.proto", + "src/protobuf/files.proto", + "src/protobuf/notifications.proto", + "src/protobuf/patch.proto", + "src/protobuf/relay.proto", + "src/protobuf/scan.proto", + "src/protobuf/sync.proto", + ], + &["src"], + ) + .unwrap(); +} diff --git a/crates/net/src/protocol/bindings/common.rs b/crates/protocol/src/bindings/common.rs similarity index 97% rename from crates/net/src/protocol/bindings/common.rs rename to crates/protocol/src/bindings/common.rs index 308ee4a19e..86c847af79 100644 --- a/crates/net/src/protocol/bindings/common.rs +++ b/crates/protocol/src/bindings/common.rs @@ -1,16 +1,15 @@ include!(concat!(env!("OUT_DIR"), "/common.rs")); use crate::{ - protocol::{ - decode_uuid, encode_uuid, sync::EventLogType, Error, ProtoBinding, - Result, - }, + decode_uuid, encode_uuid, sdk::{ commit::{CommitHash, CommitProof, CommitState}, events::{CheckedPatch, EventRecord}, time::{Duration, OffsetDateTime}, UtcDateTime, }, + sync::EventLogType, + Error, ProtoBinding, Result, }; use rs_merkle::{algorithms::Sha256, MerkleProof}; @@ -214,7 +213,6 @@ impl TryFrom for EventLogType { match name { "Identity" => EventLogType::Identity, "Account" => EventLogType::Account, - #[cfg(feature = "device")] "Device" => EventLogType::Device, #[cfg(feature = "files")] "Files" => EventLogType::Files, @@ -245,7 +243,6 @@ impl From for WireEventLogType { WireEventLogTypeSystem::from_str_name("Account").unwrap() as i32 } - #[cfg(feature = "device")] EventLogType::Device => { WireEventLogTypeSystem::from_str_name("Device").unwrap() as i32 diff --git a/crates/net/src/protocol/bindings/diff.rs b/crates/protocol/src/bindings/diff.rs similarity index 97% rename from crates/net/src/protocol/bindings/diff.rs rename to crates/protocol/src/bindings/diff.rs index 61005c04d5..ffc5355197 100644 --- a/crates/net/src/protocol/bindings/diff.rs +++ b/crates/protocol/src/bindings/diff.rs @@ -1,11 +1,11 @@ include!(concat!(env!("OUT_DIR"), "/diff.rs")); use crate::{ - protocol::{sync::EventLogType, Error, ProtoBinding, Result}, sdk::{ commit::{CommitHash, CommitProof}, events::EventRecord, }, + Error, EventLogType, ProtoBinding, Result, }; /// Request commit diff from an event log. diff --git a/crates/net/src/protocol/bindings/files.rs b/crates/protocol/src/bindings/files.rs similarity index 94% rename from crates/net/src/protocol/bindings/files.rs rename to crates/protocol/src/bindings/files.rs index 47ada310c2..caecd5d8b3 100644 --- a/crates/net/src/protocol/bindings/files.rs +++ b/crates/protocol/src/bindings/files.rs @@ -4,15 +4,12 @@ include!(concat!(env!("OUT_DIR"), "/files.rs")); mod files { use super::*; use crate::{ - protocol::{ - decode_uuid, encode_uuid, - sync::{FileSet, FileTransfersSet}, - Error, ProtoBinding, Result, - }, + decode_uuid, encode_uuid, sdk::{ storage::files::{ExternalFile, ExternalFileName}, vault::{secret::SecretId, VaultId}, }, + Error, FileSet, FileTransfersSet, ProtoBinding, Result, }; use indexmap::IndexSet; diff --git a/crates/net/src/protocol/bindings/mod.rs b/crates/protocol/src/bindings/mod.rs similarity index 94% rename from crates/net/src/protocol/bindings/mod.rs rename to crates/protocol/src/bindings/mod.rs index 4bdce20ec3..8288a365ac 100644 --- a/crates/net/src/protocol/bindings/mod.rs +++ b/crates/protocol/src/bindings/mod.rs @@ -14,7 +14,8 @@ pub use diff::{DiffRequest, DiffResponse}; pub use notifications::ChangeNotification; pub use patch::{PatchRequest, PatchResponse}; #[cfg(feature = "pairing")] -pub(crate) use relay::{ +#[doc(hidden)] +pub use relay::{ pairing_message, PairingConfirm, PairingMessage, PairingReady, PairingRequest, RelayHeader, RelayPacket, RelayPayload, }; diff --git a/crates/net/src/protocol/bindings/notifications.rs b/crates/protocol/src/bindings/notifications.rs similarity index 96% rename from crates/net/src/protocol/bindings/notifications.rs rename to crates/protocol/src/bindings/notifications.rs index 7a1b4e570a..d873735492 100644 --- a/crates/net/src/protocol/bindings/notifications.rs +++ b/crates/protocol/src/bindings/notifications.rs @@ -1,6 +1,6 @@ include!(concat!(env!("OUT_DIR"), "/notifications.rs")); -use crate::protocol::{sync::MergeOutcome, Error, ProtoBinding, Result}; +use crate::{Error, MergeOutcome, ProtoBinding, Result}; use sos_sdk::{commit::CommitHash, signer::ecdsa::Address}; /// Notification sent by the server when changes were made. diff --git a/crates/net/src/protocol/bindings/patch.rs b/crates/protocol/src/bindings/patch.rs similarity index 97% rename from crates/net/src/protocol/bindings/patch.rs rename to crates/protocol/src/bindings/patch.rs index e950536721..11b59203b0 100644 --- a/crates/net/src/protocol/bindings/patch.rs +++ b/crates/protocol/src/bindings/patch.rs @@ -1,11 +1,11 @@ include!(concat!(env!("OUT_DIR"), "/patch.rs")); use crate::{ - protocol::{sync::EventLogType, Error, ProtoBinding, Result}, sdk::{ commit::{CommitHash, CommitProof}, events::{CheckedPatch, EventRecord}, }, + Error, EventLogType, ProtoBinding, Result, }; /// Request to patch an event log from a specific commit. diff --git a/crates/net/src/protocol/bindings/relay.rs b/crates/protocol/src/bindings/relay.rs similarity index 89% rename from crates/net/src/protocol/bindings/relay.rs rename to crates/protocol/src/bindings/relay.rs index cc8e25d242..e5d1c56439 100644 --- a/crates/net/src/protocol/bindings/relay.rs +++ b/crates/protocol/src/bindings/relay.rs @@ -1,6 +1,6 @@ include!(concat!(env!("OUT_DIR"), "/relay.rs")); -use crate::protocol::{ProtoMessage, Result}; +use crate::{Error, ProtoMessage, Result}; // Must match the protobuf enum variants const HANDSHAKE: &str = "Handshake"; @@ -13,8 +13,8 @@ impl RelayPacket { } /// Encode a packet prefixed with the target public key. - #[cfg(feature = "client")] - pub(crate) async fn encode_prefixed(self) -> Result> { + #[doc(hidden)] + pub async fn encode_prefixed(self) -> Result> { let mut recipient = self.header.as_ref().unwrap().to_public_key.clone(); let key_length = recipient.len() as u16; @@ -31,11 +31,8 @@ impl RelayPacket { /// Decode an encoded packet into a public key and /// protobuf packet bytes. - #[cfg(feature = "server")] - pub(crate) fn decode_split( - packet: Vec, - ) -> Result<(Vec, Vec)> { - use crate::protocol::Error; + #[doc(hidden)] + pub fn decode_split(packet: Vec) -> Result<(Vec, Vec)> { let amount = std::mem::size_of::(); if packet.len() > amount { let key_length = &packet[0..amount]; diff --git a/crates/net/src/protocol/bindings/scan.rs b/crates/protocol/src/bindings/scan.rs similarity index 96% rename from crates/net/src/protocol/bindings/scan.rs rename to crates/protocol/src/bindings/scan.rs index bc362fd613..90f3046463 100644 --- a/crates/net/src/protocol/bindings/scan.rs +++ b/crates/protocol/src/bindings/scan.rs @@ -1,8 +1,7 @@ include!(concat!(env!("OUT_DIR"), "/scan.rs")); use crate::{ - protocol::{sync::EventLogType, Error, ProtoBinding, Result}, - sdk::commit::CommitProof, + sdk::commit::CommitProof, Error, EventLogType, ProtoBinding, Result, }; /// Request commit proofs from an event log. diff --git a/crates/net/src/protocol/bindings/sync.rs b/crates/protocol/src/bindings/sync.rs similarity index 92% rename from crates/net/src/protocol/bindings/sync.rs rename to crates/protocol/src/bindings/sync.rs index eb3fe92d9c..04ed641c90 100644 --- a/crates/net/src/protocol/bindings/sync.rs +++ b/crates/protocol/src/bindings/sync.rs @@ -1,18 +1,13 @@ include!(concat!(env!("OUT_DIR"), "/sync.rs")); use crate::{ - protocol::{ - decode_uuid, encode_uuid, - sync::{ - CreateSet, MaybeDiff, MergeOutcome, Origin, SyncCompare, - SyncDiff, SyncPacket, SyncStatus, UpdateSet, - }, - Error, ProtoBinding, Result, - }, + decode_uuid, encode_uuid, sdk::{ commit::Comparison, events::{Diff, EventRecord, Patch}, }, + CreateSet, Error, MaybeDiff, MergeOutcome, Origin, ProtoBinding, Result, + SyncCompare, SyncDiff, SyncPacket, SyncStatus, UpdateSet, }; use indexmap::{IndexMap, IndexSet}; use std::collections::HashMap; @@ -65,7 +60,6 @@ impl TryFrom for SyncStatus { root: value.root.unwrap().try_into()?, identity: value.identity.unwrap().try_into()?, account: value.account.unwrap().try_into()?, - #[cfg(feature = "device")] device: value.device.unwrap().try_into()?, #[cfg(feature = "files")] files, @@ -80,10 +74,7 @@ impl From for WireSyncStatus { root: Some(value.root.into()), identity: Some(value.identity.into()), account: Some(value.account.into()), - #[cfg(feature = "device")] device: Some(value.device.into()), - #[cfg(not(feature = "device"))] - device: None, #[cfg(feature = "files")] files: value.files.map(|s| s.into()), #[cfg(not(feature = "files"))] @@ -264,7 +255,6 @@ impl TryFrom for CreateSet { Ok(Self { identity: value.identity.unwrap().try_into()?, account: value.account.unwrap().try_into()?, - #[cfg(feature = "device")] device: value.device.unwrap().try_into()?, #[cfg(feature = "files")] files: value.files.unwrap().try_into()?, @@ -278,10 +268,7 @@ impl From for WireCreateSet { Self { identity: Some(value.identity.into()), account: Some(value.account.into()), - #[cfg(feature = "device")] device: Some(value.device.into()), - #[cfg(not(feature = "device"))] - device: None, #[cfg(feature = "files")] files: Some(value.files.into()), #[cfg(not(feature = "files"))] @@ -318,7 +305,6 @@ impl TryFrom for UpdateSet { None }; - #[cfg(feature = "device")] let device = if let Some(device) = value.device { Some(device.try_into()?) } else { @@ -342,7 +328,6 @@ impl TryFrom for UpdateSet { Ok(Self { identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, @@ -356,10 +341,7 @@ impl From for WireUpdateSet { Self { identity: value.identity.map(|d| d.into()), account: value.account.map(|d| d.into()), - #[cfg(feature = "device")] device: value.device.map(|d| d.into()), - #[cfg(not(feature = "device"))] - device: None, #[cfg(feature = "files")] files: value.files.map(|d| d.into()), #[cfg(not(feature = "files"))] @@ -396,7 +378,6 @@ impl TryFrom for SyncDiff { None }; - #[cfg(feature = "device")] let device = if let Some(device) = value.device { Some(device.try_into()?) } else { @@ -420,7 +401,6 @@ impl TryFrom for SyncDiff { Ok(Self { identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, @@ -434,10 +414,7 @@ impl From for WireSyncDiff { Self { identity: value.identity.map(|d| d.into()), account: value.account.map(|d| d.into()), - #[cfg(feature = "device")] device: value.device.map(|d| d.into()), - #[cfg(not(feature = "device"))] - device: None, #[cfg(feature = "files")] files: value.files.map(|d| d.into()), #[cfg(not(feature = "files"))] @@ -474,7 +451,6 @@ impl TryFrom for SyncCompare { None }; - #[cfg(feature = "device")] let device = if let Some(device) = value.device { Some(device.try_into()?) } else { @@ -498,7 +474,6 @@ impl TryFrom for SyncCompare { Ok(Self { identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, @@ -512,10 +487,7 @@ impl From for WireSyncCompare { Self { identity: value.identity.map(|d| d.into()), account: value.account.map(|d| d.into()), - #[cfg(feature = "device")] device: value.device.map(|d| d.into()), - #[cfg(not(feature = "device"))] - device: None, #[cfg(feature = "files")] files: value.files.map(|d| d.into()), #[cfg(not(feature = "files"))] @@ -581,7 +553,6 @@ impl TryFrom for MergeOutcome { changes: value.changes, identity: value.identity, account: value.account, - #[cfg(feature = "device")] device: value.device, #[cfg(feature = "files")] files: value.files, @@ -598,10 +569,7 @@ impl From for WireMergeOutcome { changes: value.changes, identity: value.identity, account: value.account, - #[cfg(feature = "device")] device: value.device, - #[cfg(not(feature = "device"))] - device: 0, #[cfg(feature = "files")] files: value.files, #[cfg(not(feature = "files"))] diff --git a/crates/net/src/protocol/error.rs b/crates/protocol/src/error.rs similarity index 100% rename from crates/net/src/protocol/error.rs rename to crates/protocol/src/error.rs diff --git a/crates/net/src/protocol/mod.rs b/crates/protocol/src/lib.rs similarity index 87% rename from crates/net/src/protocol/mod.rs rename to crates/protocol/src/lib.rs index 5da44ba8d0..9ff6837bd2 100644 --- a/crates/net/src/protocol/mod.rs +++ b/crates/protocol/src/lib.rs @@ -1,4 +1,7 @@ -//! Types for the wire protocol. +#![deny(missing_docs)] +#![forbid(unsafe_code)] +#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))] +//! Networking and sync protocol types for [Save Our Secrets](https://saveoursecrets.com). // There are two layers to the types in this module; the wire // types which are defined in the protobuf files are prefixed @@ -19,13 +22,19 @@ mod bindings; mod error; -pub mod sync; +mod sync; pub use bindings::*; pub use error::Error; +pub use sync::*; use prost::{bytes::Buf, Message}; +#[cfg(test)] +mod tests; + +pub use sos_sdk as sdk; + /// Result type for the wire protocol. pub type Result = std::result::Result; @@ -33,11 +42,14 @@ pub type Result = std::result::Result; /// /// A blanket implementation adds this to any [prost::Message] /// and runs the encoding and decoding using `spawn_blocking`. -pub(crate) trait ProtoMessage { +#[doc(hidden)] +pub trait ProtoMessage { /// Encode this message. + #[allow(async_fn_in_trait)] async fn encode_proto(self) -> Result>; /// Decode a message. + #[allow(async_fn_in_trait)] async fn decode_proto(buffer: B) -> Result where B: Buf + Send + 'static, @@ -74,11 +86,14 @@ trait ProtoBinding { } /// Trait for wire protocol encoding and decoding. -pub(crate) trait WireEncodeDecode { +#[doc(hidden)] +pub trait WireEncodeDecode { /// Encode this request. + #[allow(async_fn_in_trait)] async fn encode(self) -> Result>; /// Decode this request. + #[allow(async_fn_in_trait)] async fn decode(buffer: B) -> Result where B: Buf + Send + 'static, diff --git a/crates/net/src/protocol/protobuf/common.proto b/crates/protocol/src/protobuf/common.proto similarity index 100% rename from crates/net/src/protocol/protobuf/common.proto rename to crates/protocol/src/protobuf/common.proto diff --git a/crates/net/src/protocol/protobuf/diff.proto b/crates/protocol/src/protobuf/diff.proto similarity index 100% rename from crates/net/src/protocol/protobuf/diff.proto rename to crates/protocol/src/protobuf/diff.proto diff --git a/crates/net/src/protocol/protobuf/files.proto b/crates/protocol/src/protobuf/files.proto similarity index 100% rename from crates/net/src/protocol/protobuf/files.proto rename to crates/protocol/src/protobuf/files.proto diff --git a/crates/net/src/protocol/protobuf/notifications.proto b/crates/protocol/src/protobuf/notifications.proto similarity index 100% rename from crates/net/src/protocol/protobuf/notifications.proto rename to crates/protocol/src/protobuf/notifications.proto diff --git a/crates/net/src/protocol/protobuf/patch.proto b/crates/protocol/src/protobuf/patch.proto similarity index 100% rename from crates/net/src/protocol/protobuf/patch.proto rename to crates/protocol/src/protobuf/patch.proto diff --git a/crates/net/src/protocol/protobuf/relay.proto b/crates/protocol/src/protobuf/relay.proto similarity index 100% rename from crates/net/src/protocol/protobuf/relay.proto rename to crates/protocol/src/protobuf/relay.proto diff --git a/crates/net/src/protocol/protobuf/scan.proto b/crates/protocol/src/protobuf/scan.proto similarity index 100% rename from crates/net/src/protocol/protobuf/scan.proto rename to crates/protocol/src/protobuf/scan.proto diff --git a/crates/net/src/protocol/protobuf/sync.proto b/crates/protocol/src/protobuf/sync.proto similarity index 100% rename from crates/net/src/protocol/protobuf/sync.proto rename to crates/protocol/src/protobuf/sync.proto diff --git a/crates/net/src/protocol/sync/folder.rs b/crates/protocol/src/sync/folder.rs similarity index 96% rename from crates/net/src/protocol/sync/folder.rs rename to crates/protocol/src/sync/folder.rs index 62da855e77..4b570ed697 100644 --- a/crates/net/src/protocol/sync/folder.rs +++ b/crates/protocol/src/sync/folder.rs @@ -1,9 +1,14 @@ //! Implements merging for folders. + +// Ideally we want this code to be in the `sos-net` +// crate but we also need to share some traits with the +// server so we have to implement here otherwise we +// hit the problem with foreign trait implementations. + use async_trait::async_trait; use futures::io::{AsyncRead, AsyncSeek, AsyncWrite}; use crate::{ - protocol::sync::FolderMergeOptions, sdk::{ events::{ CheckedPatch, EventLogExt, FolderDiff, FolderReducer, LogEvent, @@ -14,6 +19,7 @@ use crate::{ vault::secret::SecretRow, Result, }, + FolderMergeOptions, }; /// Merge operations for the identity folder. @@ -109,6 +115,7 @@ where .decrypt_secret(vault_commit, None) .await?; + #[allow(irrefutable_let_patterns)] let mut urn = if let FolderMergeOptions::Urn(_, _) = &options { meta.urn().cloned() @@ -195,6 +202,7 @@ where } } WriteEvent::DeleteSecret(id) => { + #[allow(irrefutable_let_patterns)] let mut urn = if let FolderMergeOptions::Urn(_, _) = &options { if let Some((meta, _, _)) = diff --git a/crates/net/src/protocol/sync/local_account.rs b/crates/protocol/src/sync/local_account.rs similarity index 97% rename from crates/net/src/protocol/sync/local_account.rs rename to crates/protocol/src/sync/local_account.rs index 0d9b663943..992b725c9a 100644 --- a/crates/net/src/protocol/sync/local_account.rs +++ b/crates/protocol/src/sync/local_account.rs @@ -1,9 +1,11 @@ //! Implements merging into a local account. +//! + +// Ideally we want this code to be in the `sos-net` +// crate but we also need to share some traits with the +// server so we have to implement here otherwise we +// hit the problem with foreign trait implementations. use crate::{ - protocol::sync::{ - FolderMerge, FolderMergeOptions, ForceMerge, IdentityFolderMerge, - Merge, MergeOutcome, SyncStatus, SyncStorage, - }, sdk::{ account::{Account, LocalAccount}, commit::{CommitState, CommitTree, Comparison}, @@ -16,11 +18,12 @@ use crate::{ vault::{Vault, VaultId}, Error, Result, }, + FolderMerge, FolderMergeOptions, ForceMerge, IdentityFolderMerge, Merge, + MergeOutcome, SyncStatus, SyncStorage, }; use async_trait::async_trait; use indexmap::IndexMap; -#[cfg(feature = "device")] use crate::sdk::events::{DeviceDiff, DeviceReducer}; #[cfg(feature = "files")] @@ -70,7 +73,6 @@ impl ForceMerge for LocalAccount { Ok(()) } - #[cfg(feature = "device")] async fn force_merge_device( &mut self, diff: DeviceDiff, @@ -286,7 +288,6 @@ impl Merge for LocalAccount { event_log.tree().compare(&state.1) } - #[cfg(feature = "device")] async fn merge_device( &mut self, diff: DeviceDiff, @@ -330,7 +331,6 @@ impl Merge for LocalAccount { Ok(checked_patch) } - #[cfg(feature = "device")] async fn compare_device( &self, state: &CommitState, @@ -498,7 +498,6 @@ impl SyncStorage for LocalAccount { reader.tree().commit_state()? }; - #[cfg(feature = "device")] let device = { let reader = storage.device_log.read().await; reader.tree().commit_state()? @@ -532,7 +531,6 @@ impl SyncStorage for LocalAccount { let mut root_commits = vec![ identity.1.root().into(), account.1.root().into(), - #[cfg(feature = "device")] device.1.root().into(), ]; #[cfg(feature = "files")] @@ -553,7 +551,6 @@ impl SyncStorage for LocalAccount { root, identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, diff --git a/crates/net/src/protocol/sync/mod.rs b/crates/protocol/src/sync/mod.rs similarity index 100% rename from crates/net/src/protocol/sync/mod.rs rename to crates/protocol/src/sync/mod.rs diff --git a/crates/net/src/protocol/sync/primitives.rs b/crates/protocol/src/sync/primitives.rs similarity index 97% rename from crates/net/src/protocol/sync/primitives.rs rename to crates/protocol/src/sync/primitives.rs index 451eb7a1d9..e492ab925a 100644 --- a/crates/net/src/protocol/sync/primitives.rs +++ b/crates/protocol/src/sync/primitives.rs @@ -1,8 +1,4 @@ //! Synchronization types that are used internally. -use crate::protocol::sync::{ - CreateSet, MaybeDiff, MergeOutcome, Origin, SyncCompare, SyncDiff, - SyncStatus, -}; use crate::sdk::{ commit::{CommitState, Comparison}, events::{AccountDiff, CheckedPatch, EventLogExt, FolderDiff}, @@ -10,11 +6,14 @@ use crate::sdk::{ vault::VaultId, Error, Result, }; +use crate::{ + CreateSet, MaybeDiff, MergeOutcome, Origin, SyncCompare, SyncDiff, + SyncStatus, +}; use async_trait::async_trait; use indexmap::IndexMap; use std::{collections::HashMap, fmt}; -#[cfg(feature = "device")] use crate::sdk::events::DeviceDiff; #[cfg(feature = "files")] @@ -89,7 +88,6 @@ pub struct MaybeConflict { /// Whether the account log might be conflicted. pub account: bool, /// Whether the device log might be conflicted. - #[cfg(feature = "device")] pub device: bool, /// Whether the files log might be conflicted. #[cfg(feature = "files")] @@ -101,12 +99,7 @@ pub struct MaybeConflict { impl MaybeConflict { /// Check for any conflicts. pub fn has_conflicts(&self) -> bool { - let mut has_conflicts = self.identity || self.account; - - #[cfg(feature = "device")] - { - has_conflicts = has_conflicts || self.device; - } + let mut has_conflicts = self.identity || self.account || self.device; #[cfg(feature = "files")] { @@ -136,7 +129,6 @@ pub struct SyncComparison { /// Comparison of the account event log. pub account: Comparison, /// Comparison of the device event log. - #[cfg(feature = "device")] pub device: Comparison, /// Comparison of the files event log. #[cfg(feature = "files")] @@ -165,7 +157,6 @@ impl SyncComparison { reader.tree().compare(&remote_status.account.1)? }; - #[cfg(feature = "device")] let device = { let device = storage.device_log().await?; let reader = device.read().await; @@ -208,7 +199,6 @@ impl SyncComparison { remote_status, identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, @@ -316,7 +306,6 @@ impl SyncComparison { } } - #[cfg(feature = "device")] match self.device { Comparison::Equal => {} Comparison::Contains(_) => { @@ -528,7 +517,6 @@ pub trait SyncStorage: StorageEventLogs { reader.diff_events(None).await? }; - #[cfg(feature = "device")] let device = { let log = self.device_log().await?; let reader = log.read().await; @@ -555,7 +543,6 @@ pub trait SyncStorage: StorageEventLogs { identity, account, folders, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, @@ -587,7 +574,6 @@ pub trait ForceMerge { ) -> Result<()>; /// Force merge changes to the devices event log. - #[cfg(feature = "device")] async fn force_merge_device( &mut self, diff: DeviceDiff, @@ -641,7 +627,6 @@ pub trait Merge { ) -> Result; /// Merge changes to the devices event log. - #[cfg(feature = "device")] async fn merge_device( &mut self, diff: DeviceDiff, @@ -649,7 +634,6 @@ pub trait Merge { ) -> Result; /// Compare the device events. - #[cfg(feature = "device")] async fn compare_device(&self, state: &CommitState) -> Result; @@ -693,11 +677,8 @@ pub trait Merge { compare.account = Some(self.compare_account(&remote_status.account).await?); - #[cfg(feature = "device")] - { - compare.device = - Some(self.compare_device(&remote_status.device).await?); - } + compare.device = + Some(self.compare_device(&remote_status.device).await?); #[cfg(feature = "files")] if let Some(files) = &remote_status.files { @@ -747,7 +728,6 @@ pub trait Merge { None => {} } - #[cfg(feature = "device")] match diff.device { Some(MaybeDiff::Diff(diff)) => { self.merge_device(diff, outcome).await?; diff --git a/crates/net/src/protocol/sync/transfer.rs b/crates/protocol/src/sync/transfer.rs similarity index 100% rename from crates/net/src/protocol/sync/transfer.rs rename to crates/protocol/src/sync/transfer.rs diff --git a/crates/net/src/protocol/sync/transport.rs b/crates/protocol/src/sync/transport.rs similarity index 96% rename from crates/net/src/protocol/sync/transport.rs rename to crates/protocol/src/sync/transport.rs index c9cc93f0b9..55718f9951 100644 --- a/crates/net/src/protocol/sync/transport.rs +++ b/crates/protocol/src/sync/transport.rs @@ -1,11 +1,11 @@ //! Synchronization types that are sent //! between the client and server. -use crate::protocol::sync::MaybeConflict; use crate::sdk::{ commit::{CommitHash, CommitState, Comparison}, events::{AccountDiff, AccountPatch, FolderDiff, FolderPatch}, vault::VaultId, }; +use crate::sync::MaybeConflict; use indexmap::{IndexMap, IndexSet}; use serde::{Deserialize, Serialize}; use std::{ @@ -15,7 +15,6 @@ use std::{ }; use url::Url; -#[cfg(feature = "device")] use crate::sdk::events::{DeviceDiff, DevicePatch}; #[cfg(feature = "files")] @@ -32,7 +31,6 @@ pub enum EventLogType { /// Account event log. Account, /// Device event log. - #[cfg(feature = "device")] Device, /// Files event log. #[cfg(feature = "files")] @@ -113,7 +111,6 @@ pub struct SyncStatus { /// Account log commit state. pub account: CommitState, /// Device log commit state. - #[cfg(feature = "device")] pub device: CommitState, /// Files log commit state. #[cfg(feature = "files")] @@ -139,7 +136,6 @@ pub struct SyncCompare { /// Account log comparison. pub account: Option, /// Device log comparison. - #[cfg(feature = "device")] pub device: Option, /// Files log comparison. #[cfg(feature = "files")] @@ -162,7 +158,6 @@ impl SyncCompare { .as_ref() .map(|c| matches!(c, Comparison::Unknown)) .unwrap_or(false), - #[cfg(feature = "device")] device: self .device .as_ref() @@ -202,7 +197,6 @@ pub struct SyncDiff { /// Diff of the account event log. pub account: Option>, /// Diff of the device event log. - #[cfg(feature = "device")] pub device: Option>, /// Diff of the files event log. #[cfg(feature = "files")] @@ -219,7 +213,6 @@ pub struct CreateSet { /// Account event logs. pub account: AccountPatch, /// Device event logs. - #[cfg(feature = "device")] pub device: DevicePatch, /// File event logs. #[cfg(feature = "files")] @@ -242,7 +235,6 @@ pub struct UpdateSet { /// Account event log. pub account: Option, /// Device event log. - #[cfg(feature = "device")] pub device: Option, /// Files event log. #[cfg(feature = "files")] @@ -261,7 +253,6 @@ pub struct MergeOutcome { /// Number of changes to the account event log. pub account: u64, /// Number of changes to the device event log. - #[cfg(feature = "device")] pub device: u64, /// Number of changes to the file event log. #[cfg(feature = "files")] diff --git a/crates/net/src/tests/mod.rs b/crates/protocol/src/tests/mod.rs similarity index 100% rename from crates/net/src/tests/mod.rs rename to crates/protocol/src/tests/mod.rs diff --git a/crates/net/src/tests/protocol.rs b/crates/protocol/src/tests/protocol.rs similarity index 96% rename from crates/net/src/tests/protocol.rs rename to crates/protocol/src/tests/protocol.rs index d0fb3db8ca..f7112450c9 100644 --- a/crates/net/src/tests/protocol.rs +++ b/crates/protocol/src/tests/protocol.rs @@ -3,14 +3,6 @@ use anyhow::Result; use prost::bytes::Bytes; use crate::{ - protocol::{ - sync::{ - CreateSet, EventLogType, MaybeDiff, MergeOutcome, Origin, - SyncCompare, SyncDiff, SyncPacket, SyncStatus, UpdateSet, - }, - DiffRequest, DiffResponse, PatchRequest, PatchResponse, ScanRequest, - ScanResponse, WireEncodeDecode, - }, sdk::{ commit::{CommitHash, CommitProof, CommitState}, events::{CheckedPatch, EventRecord, FolderDiff}, @@ -18,6 +10,12 @@ use crate::{ vault::VaultId, UtcDateTime, }, + sync::{ + CreateSet, EventLogType, MaybeDiff, MergeOutcome, Origin, + SyncCompare, SyncDiff, SyncPacket, SyncStatus, UpdateSet, + }, + DiffRequest, DiffResponse, PatchRequest, PatchResponse, ScanRequest, + ScanResponse, WireEncodeDecode, }; const HASH: &str = @@ -232,7 +230,7 @@ async fn encode_decode_merge_outcom() -> Result<()> { #[cfg(feature = "listen")] #[tokio::test] async fn encode_decode_change_notification() -> Result<()> { - use crate::protocol::ChangeNotification; + use crate::ChangeNotification; let outcome = MergeOutcome { changes: 7, ..Default::default() @@ -359,8 +357,8 @@ async fn encode_decode_update_set() -> Result<()> { #[tokio::test] async fn encode_decode_change_files() -> Result<()> { use crate::{ - protocol::sync::{FileSet, FileTransfersSet}, sdk::{storage::files::ExternalFile, vault::secret::SecretId}, + sync::{FileSet, FileTransfersSet}, }; use indexmap::IndexSet; diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 2655acd4b3..79dbbe3850 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sos-sdk" -version = "0.13.1" +version = "0.14.1" edition = "2021" description = "Distributed, encrypted database for private secrets." homepage = "https://saveoursecrets.com" @@ -16,14 +16,11 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] -default = ["account", "archive", "audit", "logs", "search"] +default = ["account", "audit", "logs"] account = [] archive = ["dep:async_zip"] audit = [] contacts = [] -device = [ - "dep:whoami", -] files = [] interactive-keychain-tests = [] logs = ["rev_buf_reader", "tracing-appender", "tracing-subscriber"] @@ -93,9 +90,9 @@ mime_guess = { version = "2" } sanitize-filename = "0.5" futures-util = "0.3" async-stream = "0.3" +whoami = { version = "1.5" } anyhow = {version = "1", optional = true } vsss-rs = {version = "3", optional = true } -whoami = { version = "1.5", optional = true } tracing-appender = { version = "0.2", optional = true } tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"], optional = true } rev_buf_reader = { version = "0.3", optional = true } diff --git a/crates/sdk/src/account/account.rs b/crates/sdk/src/account/account.rs index 2efd3793f1..a96dd86859 100644 --- a/crates/sdk/src/account/account.rs +++ b/crates/sdk/src/account/account.rs @@ -18,9 +18,8 @@ use crate::{ identity::{AccountRef, FolderKeys, Identity, PublicIdentity}, signer::ecdsa::{Address, BoxedEcdsaSigner}, storage::{ - paths::FileLock, - search::{DocumentCount, SearchIndex}, - AccessOptions, AccountPack, ClientStorage, StorageEventLogs, + paths::FileLock, AccessOptions, AccountPack, ClientStorage, + StorageEventLogs, }, vault::{ secret::{Secret, SecretId, SecretMeta, SecretRow, SecretType}, @@ -30,19 +29,20 @@ use crate::{ vfs, Error, Paths, Result, UtcDateTime, }; +#[cfg(feature = "search")] +use crate::storage::search::{DocumentCount, SearchIndex}; + #[cfg(feature = "audit")] use crate::audit::{AuditData, AuditEvent}; #[cfg(feature = "archive")] use crate::account::archive::{Inventory, RestoreOptions}; -#[cfg(feature = "device")] use crate::{ device::{DeviceManager, DevicePublicKey, DeviceSigner, TrustedDevice}, events::DeviceEventLog, }; -#[cfg(feature = "device")] use indexmap::IndexSet; #[cfg(feature = "files")] @@ -235,31 +235,26 @@ pub trait Account { /// Create a new in-memory device vault. /// /// The password for the vault is saved to the identity folder. - #[cfg(feature = "device")] async fn new_device_vault( &mut self, ) -> std::result::Result<(DeviceSigner, DeviceManager), Self::Error>; /// Signing key for the device. - #[cfg(feature = "device")] async fn device_signer( &self, ) -> std::result::Result; /// Public key for the device signing key. - #[cfg(feature = "device")] async fn device_public_key( &self, ) -> std::result::Result; /// Current device information. - #[cfg(feature = "device")] async fn current_device( &self, ) -> std::result::Result; /// Collection of trusted devices. - #[cfg(feature = "device")] async fn trusted_devices( &self, ) -> std::result::Result, Self::Error>; @@ -478,6 +473,7 @@ pub trait Account { /// /// This is useful for time travel; browsing the event /// history at a particular point in time. + #[cfg(feature = "search")] async fn detached_view( &self, summary: &Summary, @@ -632,6 +628,7 @@ pub trait Account { /// If the secret exists and is not a file secret it will be /// converted to a file secret so take care to ensure you only /// use this on file secrets. + #[cfg(feature = "files")] async fn update_file( &mut self, secret_id: &SecretId, @@ -804,6 +801,7 @@ pub trait Account { /// Read-only view created from a specific event log commit. pub struct DetachedView { keeper: Gatekeeper, + #[cfg(feature = "search")] index: Arc>, } @@ -814,6 +812,7 @@ impl DetachedView { } /// Search index for the detached view. + #[cfg(feature = "search")] pub fn index(&self) -> Arc> { Arc::clone(&self.index) } @@ -829,7 +828,6 @@ pub struct AccountData { pub identity: String, /// Account folders. pub folders: Vec, - #[cfg(feature = "device")] /// Identifier of the device public key. pub device_id: String, } @@ -899,7 +897,6 @@ impl LocalAccount { signer.address()?, Some(data_dir), identity_log, - #[cfg(feature = "device")] user.identity()?.devices()?.current_device(None), ) .await?; @@ -1495,7 +1492,6 @@ impl LocalAccount { address, data_dir.clone(), identity_log, - #[cfg(feature = "device")] new_account.user.identity()?.devices()?.current_device(None), ) .await?; @@ -1541,12 +1537,10 @@ impl Account for LocalAccount { Ok(self.user()?.identity()?.signer().clone()) } - #[cfg(feature = "device")] async fn device_signer(&self) -> Result { Ok(self.user()?.identity()?.device().clone()) } - #[cfg(feature = "device")] async fn new_device_vault( &mut self, ) -> Result<(DeviceSigner, DeviceManager)> { @@ -1560,12 +1554,10 @@ impl Account for LocalAccount { Ok((signer, manager)) } - #[cfg(feature = "device")] async fn device_public_key(&self) -> Result { Ok(self.user()?.identity()?.device().public_key()) } - #[cfg(feature = "device")] async fn current_device(&self) -> Result { Ok(self .authenticated @@ -1576,7 +1568,6 @@ impl Account for LocalAccount { .current_device(None)) } - #[cfg(feature = "device")] async fn trusted_devices(&self) -> Result> { let storage = self.storage().await?; let reader = storage.read().await; @@ -1761,9 +1752,12 @@ impl Account for LocalAccount { let mut writer = storage.write().await; writer.lock().await; - tracing::debug!("clear search index"); - // Remove the search index - writer.index_mut()?.clear().await; + #[cfg(feature = "search")] + { + tracing::debug!("clear search index"); + // Remove the search index + writer.index_mut()?.clear().await; + } tracing::debug!("sign out user identity"); // Forget private identity information @@ -1862,7 +1856,6 @@ impl Account for LocalAccount { .recipient() .to_string(), folders: reader.list_folders().to_vec(), - #[cfg(feature = "device")] device_id: self.device_public_key().await?.to_string(), }) } @@ -1983,6 +1976,7 @@ impl Account for LocalAccount { Ok(()) } + #[cfg(feature = "search")] async fn detached_view( &self, summary: &Summary, @@ -2346,6 +2340,7 @@ impl Account for LocalAccount { Ok((result, to)) } + #[cfg(feature = "files")] async fn update_file( &mut self, secret_id: &SecretId, @@ -3192,7 +3187,6 @@ impl StorageEventLogs for LocalAccount { Ok(Arc::clone(&storage.account_log)) } - #[cfg(feature = "device")] async fn device_log(&self) -> Result>> { let storage = self.storage().await?; let storage = storage.read().await; diff --git a/crates/sdk/src/account/sync.rs b/crates/sdk/src/account/sync.rs index f2ad032005..a8ed56605c 100644 --- a/crates/sdk/src/account/sync.rs +++ b/crates/sdk/src/account/sync.rs @@ -14,7 +14,6 @@ use crate::{ use async_trait::async_trait; use indexmap::IndexMap; -#[cfg(feature = "device")] use crate::{events::DeviceReducer, sync::DeviceDiff}; #[cfg(feature = "files")] @@ -64,7 +63,6 @@ impl ForceMerge for LocalAccount { Ok(()) } - #[cfg(feature = "device")] async fn force_merge_device( &mut self, diff: DeviceDiff, @@ -280,7 +278,6 @@ impl Merge for LocalAccount { event_log.tree().compare(&state.1) } - #[cfg(feature = "device")] async fn merge_device( &mut self, diff: DeviceDiff, @@ -324,7 +321,6 @@ impl Merge for LocalAccount { Ok(checked_patch) } - #[cfg(feature = "device")] async fn compare_device( &self, state: &CommitState, @@ -482,7 +478,6 @@ impl SyncStorage for LocalAccount { reader.tree().commit_state()? }; - #[cfg(feature = "device")] let device = { let reader = storage.device_log.read().await; reader.tree().commit_state()? @@ -516,7 +511,6 @@ impl SyncStorage for LocalAccount { let mut root_commits = vec![ identity.1.root().into(), account.1.root().into(), - #[cfg(feature = "device")] device.1.root().into(), ]; #[cfg(feature = "files")] @@ -537,7 +531,6 @@ impl SyncStorage for LocalAccount { root, identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, diff --git a/crates/sdk/src/encoding/v1/events.rs b/crates/sdk/src/encoding/v1/events.rs index 6dbc5775f6..d2914c90cc 100644 --- a/crates/sdk/src/encoding/v1/events.rs +++ b/crates/sdk/src/encoding/v1/events.rs @@ -8,7 +8,6 @@ use crate::{ UtcDateTime, }; -#[cfg(feature = "device")] use crate::events::DeviceEvent; #[cfg(feature = "files")] @@ -380,7 +379,6 @@ impl Decodable for AccountEvent { } } -#[cfg(feature = "device")] #[async_trait] impl Encodable for DeviceEvent { async fn encode( @@ -404,7 +402,6 @@ impl Encodable for DeviceEvent { } } -#[cfg(feature = "device")] #[async_trait] impl Decodable for DeviceEvent { async fn decode( diff --git a/crates/sdk/src/events/log/file.rs b/crates/sdk/src/events/log/file.rs index 2e9bed22ee..e5cd6a8515 100644 --- a/crates/sdk/src/events/log/file.rs +++ b/crates/sdk/src/events/log/file.rs @@ -35,7 +35,6 @@ use futures::io::{ AsyncWriteExt, BufReader, Cursor, }; -#[cfg(feature = "device")] use crate::events::DeviceEvent; #[cfg(feature = "files")] @@ -85,7 +84,6 @@ pub type MemoryFolderLog = pub type AccountEventLog = DiscEventLog; /// Event log for devices. -#[cfg(feature = "device")] pub type DeviceEventLog = DiscEventLog; /// Event log for changes to a folder. @@ -924,7 +922,6 @@ impl EventLog { } } -#[cfg(feature = "device")] impl EventLog { /// Create a new device event log file. pub async fn new_device(path: impl AsRef) -> Result { diff --git a/crates/sdk/src/events/log/mod.rs b/crates/sdk/src/events/log/mod.rs index 93b7384cd8..da5c7994a4 100644 --- a/crates/sdk/src/events/log/mod.rs +++ b/crates/sdk/src/events/log/mod.rs @@ -8,12 +8,6 @@ mod file; pub mod patch; mod reducer; -#[cfg(feature = "device")] -pub use file::DeviceEventLog; - -#[cfg(feature = "device")] -pub use reducer::DeviceReducer; - #[cfg(feature = "files")] pub use file::FileEventLog; @@ -21,10 +15,11 @@ pub use file::FileEventLog; pub use reducer::FileReducer; pub use file::{ - AccountEventLog, DiscData, DiscEventLog, DiscLog, EventLogExt, - FolderEventLog, MemoryData, MemoryEventLog, MemoryFolderLog, MemoryLog, + AccountEventLog, DeviceEventLog, DiscData, DiscEventLog, DiscLog, + EventLogExt, FolderEventLog, MemoryData, MemoryEventLog, MemoryFolderLog, + MemoryLog, }; -pub use reducer::FolderReducer; +pub use reducer::{DeviceReducer, FolderReducer}; /// Record for a row in the event log. #[derive(Default, Debug, Clone, Eq, PartialEq)] diff --git a/crates/sdk/src/events/log/patch.rs b/crates/sdk/src/events/log/patch.rs index 64e0b37b99..4ad3836023 100644 --- a/crates/sdk/src/events/log/patch.rs +++ b/crates/sdk/src/events/log/patch.rs @@ -6,7 +6,6 @@ use crate::{ use binary_stream::futures::{Decodable, Encodable}; use std::marker::PhantomData; -#[cfg(feature = "device")] use crate::events::DeviceEvent; #[cfg(feature = "files")] @@ -19,7 +18,6 @@ pub type AccountPatch = Patch; pub type FolderPatch = Patch; /// Patch of device events. -#[cfg(feature = "device")] pub type DevicePatch = Patch; /// Patch of file events. @@ -119,7 +117,6 @@ pub struct Diff { pub type AccountDiff = Diff; /// Diff between device events logs. -#[cfg(feature = "device")] pub type DeviceDiff = Diff; /// Diff between file events logs. diff --git a/crates/sdk/src/events/log/reducer.rs b/crates/sdk/src/events/log/reducer.rs index 681919a349..530ddc2c43 100644 --- a/crates/sdk/src/events/log/reducer.rs +++ b/crates/sdk/src/events/log/reducer.rs @@ -193,7 +193,6 @@ impl FolderReducer { } } -#[cfg(feature = "device")] mod device { use crate::{ device::TrustedDevice, @@ -246,7 +245,6 @@ mod device { } } -#[cfg(feature = "device")] pub use device::DeviceReducer; #[cfg(feature = "files")] diff --git a/crates/sdk/src/events/mod.rs b/crates/sdk/src/events/mod.rs index 2555c84c26..7f8f391de0 100644 --- a/crates/sdk/src/events/mod.rs +++ b/crates/sdk/src/events/mod.rs @@ -16,7 +16,6 @@ use async_trait::async_trait; use binary_stream::futures::{Decodable, Encodable}; mod account; -#[cfg(feature = "device")] mod device; mod event; #[cfg(feature = "files")] @@ -32,7 +31,6 @@ pub use self::log::{ MemoryFolderLog, MemoryLog, }; -#[cfg(feature = "device")] pub use self::log::{DeviceEventLog, DeviceReducer}; #[cfg(feature = "files")] @@ -42,7 +40,6 @@ pub use self::log::FileEventLog; pub use self::log::FileReducer; pub use account::AccountEvent; -#[cfg(feature = "device")] pub use device::DeviceEvent; pub use event::Event; #[cfg(feature = "files")] diff --git a/crates/sdk/src/identity/identity.rs b/crates/sdk/src/identity/identity.rs index 0674b50327..63bb43a41f 100644 --- a/crates/sdk/src/identity/identity.rs +++ b/crates/sdk/src/identity/identity.rs @@ -22,7 +22,6 @@ use std::{ }; use urn::Urn; -#[cfg(feature = "device")] use crate::device::DeviceManager; /// Collection of folder access keys. @@ -84,7 +83,6 @@ impl Identity { } /// Device manager. - #[cfg(feature = "device")] pub fn devices(&self) -> Result<&DeviceManager> { self.identity .as_ref() @@ -207,7 +205,6 @@ impl Identity { self.identity = Some(DiscIdentityFolder::login(file, key).await?); // Lazily create or retrieve a device specific signing key - #[cfg(feature = "device")] { let identity = self.identity.as_mut().unwrap(); identity.ensure_device_vault(&self.paths).await?; diff --git a/crates/sdk/src/identity/identity_folder.rs b/crates/sdk/src/identity/identity_folder.rs index f52882dced..dcba0b9436 100644 --- a/crates/sdk/src/identity/identity_folder.rs +++ b/crates/sdk/src/identity/identity_folder.rs @@ -43,7 +43,6 @@ use std::{ use tokio::sync::RwLock; use urn::Urn; -#[cfg(feature = "device")] use crate::device::{DeviceManager, DeviceSigner}; /// Number of words to use when generating passphrases for vaults. @@ -74,7 +73,6 @@ where pub index: UrnLookup, private_identity: PrivateIdentity, - #[cfg(feature = "device")] pub(super) devices: Option, } @@ -125,13 +123,11 @@ where /// # Panics /// /// If the device manager has not been initialized. - #[cfg(feature = "device")] pub fn device(&self) -> &DeviceSigner { self.devices.as_ref().unwrap().signer() } /// Device manager. - #[cfg(feature = "device")] pub fn devices(&self) -> Result<&DeviceManager> { self.devices.as_ref().ok_or(Error::NotAuthenticated) } @@ -147,7 +143,6 @@ where /// Ensure that the account has a vault for storing device specific /// information such as the private key used to identify a machine. - #[cfg(feature = "device")] pub(super) async fn ensure_device_vault( &mut self, paths: &Paths, @@ -172,13 +167,11 @@ where Ok(()) } - #[cfg(feature = "device")] fn device_urn(&self) -> Result { use crate::constants::DEVICE_KEY_URN; Ok(DEVICE_KEY_URN.parse()?) } - #[cfg(feature = "device")] async fn read_device_vault( &mut self, paths: &Paths, @@ -229,7 +222,6 @@ where } #[doc(hidden)] - #[cfg(feature = "device")] pub async fn create_device_vault( &mut self, paths: &Paths, @@ -455,7 +447,6 @@ where self.index = Default::default(); // Lock the devices vault - #[cfg(feature = "device")] if let Some(devices) = self.devices.as_mut() { devices.sign_out(); } @@ -640,7 +631,6 @@ impl IdentityFolder { folder, index, private_identity, - #[cfg(feature = "device")] devices: None, }) } @@ -670,7 +660,6 @@ impl IdentityFolder { folder, index, private_identity, - #[cfg(feature = "device")] devices: None, }) } @@ -705,7 +694,6 @@ impl IdentityFolder { folder, index, private_identity, - #[cfg(feature = "device")] devices: None, }) } diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 890f8900d3..025b22c163 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -30,7 +30,6 @@ //! //! * `account` Local account management. //! * `audit` Audit trail logs. -//! * `device` Device signing keys and device management. //! * `files` Store external encrypted files. //! * `recovery` Primitives for social recovery. //! * `search` In-memory search index. @@ -71,7 +70,6 @@ pub mod commit; pub mod constants; pub mod crypto; mod date_time; -#[cfg(feature = "device")] pub mod device; pub mod encoding; mod error; diff --git a/crates/sdk/src/prelude.rs b/crates/sdk/src/prelude.rs index 491ddea034..de813de743 100644 --- a/crates/sdk/src/prelude.rs +++ b/crates/sdk/src/prelude.rs @@ -14,7 +14,6 @@ pub use crate::audit::*; pub use crate::commit::*; pub use crate::constants::*; pub use crate::crypto::*; -#[cfg(feature = "device")] pub use crate::device::*; pub use crate::events::*; pub use crate::formats::*; diff --git a/crates/sdk/src/storage/client.rs b/crates/sdk/src/storage/client.rs index 5767ede8b3..49feff4237 100644 --- a/crates/sdk/src/storage/client.rs +++ b/crates/sdk/src/storage/client.rs @@ -32,7 +32,6 @@ use crate::account::archive::RestoreTargets; #[cfg(feature = "audit")] use crate::audit::AuditEvent; -#[cfg(feature = "device")] use crate::{ device::{DevicePublicKey, TrustedDevice}, events::{DeviceEvent, DeviceEventLog, DeviceReducer}, @@ -90,11 +89,9 @@ pub struct ClientStorage { pub cache: HashMap, /// Device event log. - #[cfg(feature = "device")] pub device_log: Arc>, /// Reduced collection of devices. - #[cfg(feature = "device")] pub devices: IndexSet, /// File event log. @@ -112,7 +109,7 @@ impl ClientStorage { address: Address, data_dir: Option, identity_log: Arc>, - #[cfg(feature = "device")] device: TrustedDevice, + device: TrustedDevice, ) -> Result { let data_dir = if let Some(data_dir) = data_dir { data_dir @@ -121,14 +118,7 @@ impl ClientStorage { }; let dirs = Paths::new(data_dir, address.to_string()); - Self::new_paths( - Arc::new(dirs), - address, - identity_log, - #[cfg(feature = "device")] - device, - ) - .await + Self::new_paths(Arc::new(dirs), address, identity_log, device).await } /// Create new storage backed by files on disc. @@ -136,7 +126,7 @@ impl ClientStorage { paths: Arc, address: Address, identity_log: Arc>, - #[cfg(feature = "device")] device: TrustedDevice, + device: TrustedDevice, ) -> Result { if !vfs::metadata(paths.documents_dir()).await?.is_dir() { return Err(Error::NotDirectory( @@ -151,7 +141,6 @@ impl ClientStorage { event_log.load_tree().await?; let account_log = Arc::new(RwLock::new(event_log)); - #[cfg(feature = "device")] let (device_log, devices) = Self::initialize_device_log(&paths, device).await?; @@ -168,9 +157,7 @@ impl ClientStorage { account_log, #[cfg(feature = "search")] index: Some(AccountSearch::new()), - #[cfg(feature = "device")] device_log: Arc::new(RwLock::new(device_log)), - #[cfg(feature = "device")] devices, #[cfg(feature = "files")] file_log: Arc::new(RwLock::new(file_log)), @@ -184,7 +171,6 @@ impl ClientStorage { &self.address } - #[cfg(feature = "device")] async fn initialize_device_log( paths: &Paths, device: TrustedDevice, @@ -214,7 +200,6 @@ impl ClientStorage { } /// Collection of trusted devices. - #[cfg(feature = "device")] pub fn devices(&self) -> &IndexSet { &self.devices } @@ -1378,7 +1363,6 @@ impl ClientStorage { } } -#[cfg(feature = "device")] impl ClientStorage { /// List trusted devices. pub fn list_trusted_devices(&self) -> Vec<&TrustedDevice> { diff --git a/crates/sdk/src/storage/mod.rs b/crates/sdk/src/storage/mod.rs index 4d2e159ed0..258eac4975 100644 --- a/crates/sdk/src/storage/mod.rs +++ b/crates/sdk/src/storage/mod.rs @@ -21,7 +21,6 @@ pub use client::ClientStorage; pub use folder::{DiscFolder, Folder, MemoryFolder}; pub use paths::FileLock; -#[cfg(feature = "device")] use crate::events::DeviceEventLog; #[cfg(feature = "files")] @@ -112,7 +111,6 @@ pub trait StorageEventLogs { async fn account_log(&self) -> Result>>; /// Clone of the device log. - #[cfg(feature = "device")] async fn device_log(&self) -> Result>>; /// Clone of the file log. diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml new file mode 100644 index 0000000000..ff55321c55 --- /dev/null +++ b/crates/server/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "sos-server" +version = "0.14.1" +edition = "2021" +description = "Server for the Save Our Secrets sync protocol." +homepage = "https://saveoursecrets.com" +license = "AGPL-3.0" +repository = "https://github.com/saveoursecrets/sdk" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[features] +default = ["listen", "files", "audit", "pairing"] +listen = ["sos-protocol/listen"] +files = ["sos-protocol/files"] +pairing = ["sos-protocol/pairing"] +audit = [] + +[dependencies] +tokio-util.workspace = true +thiserror.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +async-trait.workspace = true +http.workspace = true +serde_json.workspace = true +serde.workspace = true +uuid.workspace = true +hex.workspace = true +url.workspace = true +futures.workspace = true +bs58.workspace = true +indexmap.workspace = true +colored.workspace = true +binary-stream.workspace = true +toml.workspace = true +clap.workspace = true + +axum = { version = "0.7", features = ["ws", "original-uri"] } +axum-extra = {version = "0.9", features = ["typed-header"] } +axum-macros = { version = "0.4" } +axum-server = { version = "0.6", features = ["tls-rustls"] } +tower = { version = "0.4" } +tower-http = { version = "0.5", features = ["cors", "trace"] } +tokio-stream = { version = "0.1" } +utoipa = { version = "4", features = ["uuid"] } +utoipa-rapidoc = { version = "3", features = ["axum"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "macros"] } + +[dependencies.sos-protocol] +version = "0.14.1" +path = "../protocol" + +[dependencies.sos-cli-helpers] +version = "0.1.0" +path = "../cli_helpers" + +[build-dependencies] +rustc_version = "0.4.0" diff --git a/crates/server/build.rs b/crates/server/build.rs new file mode 100644 index 0000000000..20f4205502 --- /dev/null +++ b/crates/server/build.rs @@ -0,0 +1,12 @@ +use rustc_version::{version_meta, Channel}; + +fn main() { + // Set cfg flags depending on release channel + let channel = match version_meta().unwrap().channel { + Channel::Stable => "CHANNEL_STABLE", + Channel::Beta => "CHANNEL_BETA", + Channel::Nightly => "CHANNEL_NIGHTLY", + Channel::Dev => "CHANNEL_DEV", + }; + println!("cargo:rustc-cfg={}", channel); +} diff --git a/crates/net/src/server/api_docs.rs b/crates/server/src/api_docs.rs similarity index 87% rename from crates/net/src/server/api_docs.rs rename to crates/server/src/api_docs.rs index 5bc4ce7337..b38c3a6693 100644 --- a/crates/net/src/server/api_docs.rs +++ b/crates/server/src/api_docs.rs @@ -1,17 +1,17 @@ -use crate::server::handlers::{account, files}; +use crate::handlers::account; use utoipa::{openapi::security::*, Modify, OpenApi, ToSchema}; #[derive(ToSchema)] #[allow(dead_code)] -struct CreateSet(crate::protocol::sync::CreateSet); +struct CreateSet(sos_protocol::CreateSet); #[derive(ToSchema)] #[allow(dead_code)] -struct SyncStatus(crate::protocol::sync::SyncStatus); +struct SyncStatus(sos_protocol::SyncStatus); #[derive(ToSchema)] #[allow(dead_code)] -struct SyncPacket(crate::protocol::sync::SyncPacket); +struct SyncPacket(sos_protocol::SyncPacket); #[derive(OpenApi)] #[openapi( @@ -41,10 +41,10 @@ struct SyncPacket(crate::protocol::sync::SyncPacket); account::event_diff, account::event_patch, account::delete_account, - files::receive_file, - files::send_file, - files::move_file, - files::delete_file, + // files::receive_file, + // files::send_file, + // files::move_file, + // files::delete_file, ), components( schemas( diff --git a/crates/net/src/server/authenticate.rs b/crates/server/src/authenticate.rs similarity index 98% rename from crates/net/src/server/authenticate.rs rename to crates/server/src/authenticate.rs index 1d573a454f..476b3a7a03 100644 --- a/crates/net/src/server/authenticate.rs +++ b/crates/server/src/authenticate.rs @@ -2,7 +2,7 @@ //! from a signature given in bearer authorization data. use axum_extra::headers::{authorization::Bearer, Authorization}; -use sos_sdk::{ +use sos_protocol::sdk::{ decode, signer::{ ecdsa::{self, recover_address, Address, BinaryEcdsaSignature}, diff --git a/crates/net/src/server/backend.rs b/crates/server/src/backend.rs similarity index 98% rename from crates/net/src/server/backend.rs rename to crates/server/src/backend.rs index 39db8ceaba..b804f04d11 100644 --- a/crates/net/src/server/backend.rs +++ b/crates/server/src/backend.rs @@ -1,6 +1,5 @@ use super::{Error, Result}; -use crate::{ - protocol::sync::{CreateSet, MergeOutcome, SyncStorage, UpdateSet}, +use sos_protocol::{ sdk::{ signer::{ ecdsa::Address, @@ -9,6 +8,7 @@ use crate::{ storage::DiscFolder, vfs, Paths, }, + CreateSet, MergeOutcome, SyncStorage, UpdateSet, }; use std::{ collections::HashMap, @@ -17,7 +17,7 @@ use std::{ }; use tokio::sync::RwLock; -use crate::server::storage::filesystem::ServerStorage; +use crate::storage::filesystem::ServerStorage; /// Account storage. pub struct AccountStorage { diff --git a/crates/net/src/server/config.rs b/crates/server/src/config.rs similarity index 98% rename from crates/net/src/server/config.rs rename to crates/server/src/config.rs index 01c7d71c14..1602a5c6ad 100644 --- a/crates/net/src/server/config.rs +++ b/crates/server/src/config.rs @@ -9,7 +9,7 @@ use url::Url; use super::backend::Backend; use super::{Error, Result}; -use sos_sdk::{signer::ecdsa::Address, vfs}; +use sos_protocol::sdk::{signer::ecdsa::Address, vfs}; /// Configuration for the web server. #[derive(Default, Debug, Serialize, Deserialize)] diff --git a/crates/net/src/server/error.rs b/crates/server/src/error.rs similarity index 93% rename from crates/net/src/server/error.rs rename to crates/server/src/error.rs index ca5b6285a5..acc10799fa 100644 --- a/crates/net/src/server/error.rs +++ b/crates/server/src/error.rs @@ -1,11 +1,11 @@ //! Error type for the server. -use crate::sdk::signer::ecdsa::Address; use axum::{ body::Body, http::StatusCode, response::{IntoResponse, Json, Response}, }; use serde_json::{json, Value}; +use sos_protocol::sdk::signer::ecdsa::Address; use std::path::PathBuf; use thiserror::Error; @@ -69,17 +69,17 @@ pub enum Error { #[error("file upload checksum mismatch; expected '{0}' but got '{1}'")] FileChecksumMismatch(String, String), - /// Error generated by main net library. + /// Error generated by the protocol library. #[error(transparent)] - Net(#[from] crate::Error), + Protocol(#[from] sos_protocol::Error), - /// Error generated converting from a slice. + /// Error generated by the SDK library. #[error(transparent)] - TryFromSlice(#[from] std::array::TryFromSliceError), + Sdk(#[from] sos_protocol::sdk::Error), - /// Error generated by the core library. + /// Error generated converting from a slice. #[error(transparent)] - Core(#[from] sos_sdk::Error), + TryFromSlice(#[from] std::array::TryFromSliceError), /// Error generated attempting to parse a URL. #[error(transparent)] @@ -111,7 +111,7 @@ pub enum Error { /// Error generate by the ECDSA library. #[error(transparent)] - Ecdsa(#[from] sos_sdk::k256::ecdsa::Error), + Ecdsa(#[from] sos_protocol::sdk::k256::ecdsa::Error), /// Error generate by the JSON library. #[error(transparent)] @@ -128,10 +128,6 @@ pub enum Error { /// Error generated by the HTTP library. #[error(transparent)] Http(#[from] axum::http::Error), - - /// Error generated by the wire protocol library. - #[error(transparent)] - Protocol(#[from] crate::protocol::Error), } impl Error { diff --git a/crates/net/src/server/handlers/account.rs b/crates/server/src/handlers/account.rs similarity index 97% rename from crates/net/src/server/handlers/account.rs rename to crates/server/src/handlers/account.rs index 464494860b..d4f4306f80 100644 --- a/crates/net/src/server/handlers/account.rs +++ b/crates/server/src/handlers/account.rs @@ -13,7 +13,7 @@ use axum_extra::{ //use axum_macros::debug_handler; use super::BODY_LIMIT; -use crate::server::{handlers::ConnectionQuery, ServerBackend, ServerState}; +use crate::{handlers::ConnectionQuery, ServerBackend, ServerState}; use std::sync::Arc; @@ -586,10 +586,15 @@ pub(crate) async fn sync_account( mod handlers { use super::Caller; use crate::{ - protocol::sync::{ - self, CreateSet, EventLogType, Merge, MergeOutcome, SyncPacket, - SyncStorage, UpdateSet, - }, + backend::AccountStorage, Error, Result, ServerBackend, ServerState, + }; + use axum::body::Bytes; + use binary_stream::futures::{Decodable, Encodable}; + use http::{ + header::{self, HeaderMap, HeaderValue}, + StatusCode, + }; + use sos_protocol::{ sdk::{ constants::MIME_TYPE_PROTOBUF, events::{ @@ -598,22 +603,9 @@ mod handlers { }, storage::StorageEventLogs, }, - }; - use crate::{ - protocol::{ - DiffRequest, DiffResponse, PatchRequest, PatchResponse, - ScanRequest, ScanResponse, WireEncodeDecode, - }, - server::{ - backend::AccountStorage, Error, Result, ServerBackend, - ServerState, - }, - }; - use axum::body::Bytes; - use binary_stream::futures::{Decodable, Encodable}; - use http::{ - header::{self, HeaderMap, HeaderValue}, - StatusCode, + CreateSet, DiffRequest, DiffResponse, EventLogType, Merge, + MergeOutcome, PatchRequest, PatchResponse, ScanRequest, ScanResponse, + SyncPacket, SyncStorage, UpdateSet, WireEncodeDecode, }; use tokio::sync::RwLock; @@ -621,15 +613,15 @@ mod handlers { use std::sync::Arc; #[cfg(feature = "files")] - use sos_sdk::events::{FileDiff, FileEvent}; + use sos_protocol::sdk::events::{FileDiff, FileEvent}; - #[cfg(feature = "device")] - use sos_sdk::events::{DeviceDiff, DeviceEvent}; + use sos_protocol::sdk::events::{DeviceDiff, DeviceEvent}; #[cfg(feature = "listen")] - use crate::{ - protocol::ChangeNotification, server::handlers::send_notification, - }; + use sos_protocol::ChangeNotification; + + #[cfg(feature = "listen")] + use crate::handlers::send_notification; pub(super) async fn account_exists( _state: ServerState, @@ -758,7 +750,6 @@ mod handlers { let event_log = log.read().await; scan_log(&req, &*event_log).await? } - #[cfg(feature = "device")] EventLogType::Device => { let reader = account.read().await; let log = reader.storage.device_log().await?; @@ -882,7 +873,6 @@ mod handlers { let event_log = log.read().await; diff_log(&req, &*event_log).await? } - #[cfg(feature = "device")] EventLogType::Device => { let reader = account.read().await; let log = reader.storage.device_log().await?; @@ -998,7 +988,6 @@ mod handlers { records, ) } - #[cfg(feature = "device")] EventLogType::Device => { let patch = Patch::::new(req.patch); let mut writer = account.write().await; @@ -1135,7 +1124,6 @@ mod handlers { let mut event_log = log.write().await; event_log.apply_records(records).await?; } - #[cfg(feature = "device")] EventLogType::Device => { let log = reader.storage.device_log().await?; let mut event_log = log.write().await; @@ -1189,7 +1177,7 @@ mod handlers { let (local_status, diff) = { let reader = account.read().await; let (_, local_status, diff) = - sync::diff(&reader.storage, remote_status).await?; + sos_protocol::diff(&reader.storage, remote_status).await?; (local_status, diff) }; diff --git a/crates/net/src/server/handlers/files.rs b/crates/server/src/handlers/files.rs similarity index 97% rename from crates/net/src/server/handlers/files.rs rename to crates/server/src/handlers/files.rs index 688653e47b..fbe57cbc9a 100644 --- a/crates/net/src/server/handlers/files.rs +++ b/crates/server/src/handlers/files.rs @@ -14,15 +14,15 @@ use axum_extra::{ //use axum_macros::debug_handler; use super::BODY_LIMIT; + +use sos_protocol::sdk::{ + storage::files::{ExternalFile, ExternalFileName}, + vault::{secret::SecretId, VaultId}, +}; + use crate::{ - sdk::{ - storage::files::{ExternalFile, ExternalFileName}, - vault::{secret::SecretId, VaultId}, - }, - server::{ - handlers::{authenticate_endpoint, ConnectionQuery}, - ServerBackend, ServerState, ServerTransfer, - }, + handlers::{authenticate_endpoint, ConnectionQuery}, + ServerBackend, ServerState, ServerTransfer, }; use serde::Deserialize; use std::sync::Arc; @@ -358,19 +358,18 @@ pub(crate) async fn compare_files( mod handlers { use super::MoveFileQuery; - use crate::{ - protocol::{ - sync::{FileSet, FileTransfersSet}, - WireEncodeDecode, - }, + use sos_protocol::{ sdk::{ + constants::MIME_TYPE_PROTOBUF, sha2::{Digest, Sha256}, storage::files::{list_external_files, ExternalFileName}, vault::{secret::SecretId, VaultId}, }, - server::{ - handlers::Caller, Error, Result, ServerBackend, ServerState, - }, + FileSet, FileTransfersSet, WireEncodeDecode, + }; + + use crate::{ + handlers::Caller, Error, Result, ServerBackend, ServerState, }; use axum::{ body::{Body, Bytes}, @@ -380,7 +379,6 @@ mod handlers { use futures::TryStreamExt; use http::header::{self, HeaderMap, HeaderValue}; use indexmap::IndexSet; - use sos_sdk::constants::MIME_TYPE_PROTOBUF; use std::{path::PathBuf, sync::Arc}; use tokio::{ fs::File, diff --git a/crates/net/src/server/handlers/mod.rs b/crates/server/src/handlers/mod.rs similarity index 95% rename from crates/net/src/server/handlers/mod.rs rename to crates/server/src/handlers/mod.rs index b8d3d582a8..c298710541 100644 --- a/crates/net/src/server/handlers/mod.rs +++ b/crates/server/src/handlers/mod.rs @@ -6,32 +6,31 @@ use axum::{ //use axum_macros::debug_handler; -use crate::server::{ +use crate::{ authenticate::{self, BearerToken}, Error, Result, ServerBackend, }; use axum_extra::headers::{authorization::Bearer, Authorization}; use serde::Deserialize; use serde_json::json; -use sos_sdk::signer::ecdsa::Address; +use sos_protocol::sdk::signer::ecdsa::Address; pub mod account; -pub mod files; -#[cfg(feature = "listen")] -pub(crate) mod websocket; +#[cfg(feature = "files")] +pub mod files; #[cfg(feature = "pairing")] pub(crate) mod relay; +pub(crate) mod websocket; // 32MB limit for the body size const BODY_LIMIT: usize = 33554432; #[cfg(feature = "listen")] -use crate::{ - protocol::{ChangeNotification, WireEncodeDecode}, - server::{ServerState, State}, -}; +use sos_protocol::{ChangeNotification, WireEncodeDecode}; + +use crate::server::{ServerState, State}; /// Query string for connections. #[derive(Debug, Deserialize, Clone)] @@ -52,6 +51,7 @@ pub(crate) async fn api() -> impl IntoResponse { } /// Get the number of websocket connections. +#[cfg(feature = "listen")] pub(crate) async fn connections( Extension(state): Extension, ) -> impl IntoResponse { diff --git a/crates/net/src/server/handlers/relay.rs b/crates/server/src/handlers/relay.rs similarity index 98% rename from crates/net/src/server/handlers/relay.rs rename to crates/server/src/handlers/relay.rs index f74e0bc388..0004d367a2 100644 --- a/crates/net/src/server/handlers/relay.rs +++ b/crates/server/src/handlers/relay.rs @@ -1,5 +1,4 @@ //! Relay forwards packets between peers over a websocket connection. -use crate::protocol::RelayPacket; use axum::{ extract::{ ws::{Message, WebSocket, WebSocketUpgrade}, @@ -10,6 +9,7 @@ use axum::{ }; use futures::{stream::SplitSink, SinkExt, StreamExt}; use serde::Deserialize; +use sos_protocol::RelayPacket; use std::{collections::HashMap, sync::Arc}; use tokio::sync::Mutex; diff --git a/crates/net/src/server/handlers/websocket.rs b/crates/server/src/handlers/websocket.rs similarity index 98% rename from crates/net/src/server/handlers/websocket.rs rename to crates/server/src/handlers/websocket.rs index d6a6826218..8352f28395 100644 --- a/crates/net/src/server/handlers/websocket.rs +++ b/crates/server/src/handlers/websocket.rs @@ -15,12 +15,12 @@ use futures::{ SinkExt, StreamExt, }; -use sos_sdk::signer::ecdsa::Address; +use sos_protocol::sdk::signer::ecdsa::Address; use std::{collections::HashMap, sync::Arc}; use tokio::sync::{broadcast, watch}; use super::{authenticate_endpoint, Caller, ConnectionQuery}; -use crate::server::{Result, ServerBackend, ServerState}; +use crate::{Result, ServerBackend, ServerState}; /// State for the websocket connection for a single /// authenticated client. diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs new file mode 100644 index 0000000000..730405116a --- /dev/null +++ b/crates/server/src/lib.rs @@ -0,0 +1,31 @@ +#![deny(missing_docs)] +#![forbid(unsafe_code)] +#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))] + +//! Server for the [Save Our Secrets](https://saveoursecrets.com) +//! sync protocol. +//! +//! If the `listen` feature is enabled the server is compiled +//! with support for sending change notifications over +//! a websocket connection. + +mod api_docs; +mod authenticate; +mod backend; +mod config; +mod error; +mod handlers; +mod server; +mod storage; + +pub use error::Error; + +/// Result type for the server module. +pub type Result = std::result::Result; + +pub use backend::Backend; +pub use config::*; +pub use server::{Server, ServerBackend, ServerState, State}; + +#[cfg(feature = "files")] +pub use server::ServerTransfer; diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs new file mode 100644 index 0000000000..4fb4a4bd21 --- /dev/null +++ b/crates/server/src/main.rs @@ -0,0 +1,126 @@ +use sos_server::Result; + +#[tokio::main] +async fn main() -> Result<()> { + use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + tracing_subscriber::registry() + .with(tracing_subscriber::EnvFilter::new( + std::env::var("RUST_LOG").unwrap_or_else(|_| "sos=info".into()), + )) + .with(tracing_subscriber::fmt::layer().without_time()) + .init(); + + if let Err(e) = cli::run().await { + sos_cli_helpers::messages::fail(e.to_string()); + } + + Ok(()) +} + +mod cli { + use crate::Result; + use clap::{CommandFactory, Parser, Subcommand}; + use sos_cli_helpers::CommandTree; + use std::path::PathBuf; + + #[derive(Parser, Debug)] + #[clap(name = "sos-server", author, version, about, long_about = None)] + pub struct SosServer { + #[clap(subcommand)] + cmd: Command, + } + + #[derive(Debug, Subcommand)] + pub enum Command { + /// Create a configuration file. + Init { + /// Path to the storage folder. + #[clap(short, long)] + path: Option, + + /// Config file to write. + config: PathBuf, + }, + /// Start a server. + Start { + /// Bind to host:port. + #[clap(short, long, default_value = "0.0.0.0:5053")] + bind: String, + + /// Config file to load. + config: PathBuf, + }, + } + + pub async fn run() -> Result<()> { + // Support JSON output of command tree + if std::env::var("SOS_CLI_JSON").ok().is_some() { + let cmd = SosServer::command(); + let tree: CommandTree = (&cmd).into(); + serde_json::to_writer_pretty(std::io::stdout(), &tree)?; + std::process::exit(0); + } + + let args = SosServer::parse(); + + match args.cmd { + Command::Init { config, path } => { + service::init(config, path).await?; + } + Command::Start { bind, config } => { + service::start(bind, config).await?; + } + } + + Ok(()) + } + + mod service { + use axum_server::Handle; + use sos_protocol::sdk::vfs; + use sos_server::{ + Error, Result, Server, ServerConfig, State, StorageConfig, + }; + use std::{net::SocketAddr, path::PathBuf, str::FromStr, sync::Arc}; + use tokio::sync::RwLock; + + /// Initialize default server configuration. + pub async fn init( + output: PathBuf, + mut path: Option, + ) -> Result<()> { + if vfs::try_exists(&output).await? { + return Err(Error::FileExists(output)); + } + + let mut config: ServerConfig = Default::default(); + if let Some(path) = path.take() { + config.storage = StorageConfig { path }; + } + + let content = toml::to_string_pretty(&config)?; + vfs::write(output, content.as_bytes()).await?; + Ok(()) + } + + /// Start a web server. + pub async fn start(bind: String, config: PathBuf) -> Result<()> { + let config = ServerConfig::load(&config).await?; + let backend = config.backend().await?; + + let state = Arc::new(RwLock::new(State { + config, + sockets: Default::default(), + })); + + let handle = Handle::new(); + + let addr = SocketAddr::from_str(&bind)?; + let server = Server::new(backend.directory()).await?; + server + .start(addr, state, Arc::new(RwLock::new(backend)), handle) + .await?; + Ok(()) + } + } +} diff --git a/crates/net/src/server/server.rs b/crates/server/src/server.rs similarity index 85% rename from crates/net/src/server/server.rs rename to crates/server/src/server.rs index e024f64b87..862802d114 100644 --- a/crates/net/src/server/server.rs +++ b/crates/server/src/server.rs @@ -1,16 +1,8 @@ -use super::{ +use crate::{ config::TlsConfig, - handlers::{ - account, api, connections, - files::{self, file_operation_lock}, - home, - websocket::WebSocketAccount, - }, + handlers::{account, api, home, websocket::WebSocketAccount}, Backend, Result, ServerConfig, }; -use crate::sdk::{ - signer::ecdsa::Address, storage::files::ExternalFile, UtcDateTime, -}; use axum::{ extract::Extension, http::{ @@ -24,7 +16,9 @@ use axum::{ }; use axum_server::{tls_rustls::RustlsConfig, Handle}; use colored::Colorize; -use sos_sdk::storage::FileLock; +use sos_protocol::sdk::{ + signer::ecdsa::Address, storage::FileLock, UtcDateTime, +}; use std::{ collections::{HashMap, HashSet}, net::SocketAddr, @@ -41,6 +35,9 @@ use tracing::Level; #[cfg(feature = "listen")] use super::handlers::websocket::upgrade; +#[cfg(feature = "files")] +use sos_protocol::sdk::storage::files::ExternalFile; + #[cfg(feature = "pairing")] use super::handlers::relay::{upgrade as relay_upgrade, RelayState}; @@ -59,9 +56,11 @@ pub type ServerState = Arc>; pub type ServerBackend = Arc>; /// Transfer operations in progress. +#[cfg(feature = "files")] pub type TransferOperations = HashSet; /// State for the file transfer operations. +#[cfg(feature = "files")] pub type ServerTransfer = Arc>; /// Web server implementation. @@ -240,21 +239,28 @@ impl Server { get(account::event_proofs) .post(account::event_diff) .patch(account::event_patch), - ) - .route("/sync/files", post(files::compare_files)) - .route( - "/sync/file/:vault_id/:secret_id/:file_name", - put(files::receive_file) - .post(files::move_file) - .get(files::send_file) - .delete(files::delete_file) - .route_layer(middleware::from_fn( - file_operation_lock, - )), ); + #[cfg(feature = "files")] + { + use super::handlers::files::{self, file_operation_lock}; + router = router + .route("/sync/files", post(files::compare_files)) + .route( + "/sync/file/:vault_id/:secret_id/:file_name", + put(files::receive_file) + .post(files::move_file) + .get(files::send_file) + .delete(files::delete_file) + .route_layer(middleware::from_fn( + file_operation_lock, + )), + ); + } + #[cfg(feature = "listen")] { + use super::handlers::connections; router = router .route("/sync/connections", get(connections)) .route("/sync/changes", get(upgrade)); @@ -268,12 +274,6 @@ impl Server { router }; - #[cfg(feature = "pairing")] - let relay: RelayState = Arc::new(Mutex::new(HashMap::new())); - - let file_operations: ServerTransfer = - Arc::new(RwLock::new(HashSet::new())); - let mut v1 = v1.layer(cors).layer( TraceLayer::new_for_http() .on_request(DefaultOnRequest::new().level(Level::TRACE)) @@ -282,13 +282,18 @@ impl Server { #[cfg(feature = "pairing")] { + let relay: RelayState = Arc::new(Mutex::new(HashMap::new())); v1 = v1.layer(Extension(relay)); } - v1 = v1 - .layer(Extension(backend)) - .layer(Extension(file_operations)) - .layer(Extension(state)); + v1 = v1.layer(Extension(backend)).layer(Extension(state)); + + #[cfg(feature = "files")] + { + let file_operations: ServerTransfer = + Arc::new(RwLock::new(HashSet::new())); + v1 = v1.layer(Extension(file_operations)); + } let app = Router::new() .route("/", get(home)) @@ -310,7 +315,7 @@ impl Server { ), )] pub async fn openapi() -> impl IntoResponse { - let value = crate::server::api_docs::openapi(); + let value = crate::api_docs::openapi(); Json(serde_json::json!(&value)) } diff --git a/crates/net/src/server/storage/filesystem/mod.rs b/crates/server/src/storage/filesystem/mod.rs similarity index 95% rename from crates/net/src/server/storage/filesystem/mod.rs rename to crates/server/src/storage/filesystem/mod.rs index 22e1f727ae..d78518db1c 100644 --- a/crates/net/src/server/storage/filesystem/mod.rs +++ b/crates/server/src/storage/filesystem/mod.rs @@ -1,5 +1,5 @@ //! Server storage backed by the filesystem. -use crate::sdk::{ +use sos_protocol::sdk::{ constants::VAULT_EXT, decode, encode, events::{ @@ -15,22 +15,18 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc}; use tokio::sync::RwLock; #[cfg(feature = "audit")] -use crate::sdk::audit::AuditEvent; +use sos_protocol::sdk::audit::AuditEvent; -#[cfg(feature = "device")] -use crate::sdk::{ +use sos_protocol::sdk::{ device::{DevicePublicKey, TrustedDevice}, events::{DeviceEventLog, DeviceReducer}, }; -#[cfg(feature = "device")] -use std::collections::HashSet; - -#[cfg(feature = "device")] use indexmap::IndexSet; +use std::collections::HashSet; #[cfg(feature = "files")] -use crate::sdk::events::{FileEvent, FileEventLog}; +use sos_protocol::sdk::events::{FileEvent, FileEventLog}; mod sync; @@ -52,11 +48,9 @@ pub struct ServerStorage { pub(super) cache: HashMap>>, /// Device event log. - #[cfg(feature = "device")] pub(super) device_log: Arc>, /// Reduced collection of devices. - #[cfg(feature = "device")] pub(super) devices: IndexSet, /// File event log. @@ -100,7 +94,6 @@ impl ServerStorage { event_log.load_tree().await?; let account_log = Arc::new(RwLock::new(event_log)); - #[cfg(feature = "device")] let (device_log, devices) = Self::initialize_device_log(&*paths).await?; @@ -113,9 +106,7 @@ impl ServerStorage { paths, identity_log, account_log, - #[cfg(feature = "device")] device_log: Arc::new(RwLock::new(device_log)), - #[cfg(feature = "device")] devices, #[cfg(feature = "files")] file_log: Arc::new(RwLock::new(file_log)), @@ -137,7 +128,6 @@ impl ServerStorage { Arc::clone(&self.account_log) } - #[cfg(feature = "device")] async fn initialize_device_log( paths: &Paths, ) -> Result<(DeviceEventLog, IndexSet)> { @@ -153,6 +143,8 @@ impl ServerStorage { #[cfg(feature = "files")] async fn initialize_file_log(paths: &Paths) -> Result { + use sos_protocol::sdk::storage::files::list_external_files; + let log_file = paths.file_events(); let needs_init = !vfs::try_exists(&log_file).await?; let mut event_log = FileEventLog::new_file(log_file).await?; @@ -160,9 +152,7 @@ impl ServerStorage { tracing::debug!(needs_init = %needs_init, "file_log"); if needs_init { - let files = - crate::sdk::storage::files::list_external_files(paths) - .await?; + let files = list_external_files(paths).await?; let events: Vec = files.into_iter().map(|f| f.into()).collect(); @@ -360,7 +350,6 @@ impl ServerStorage { } } -#[cfg(feature = "device")] impl ServerStorage { /// List the public keys of trusted devices. pub fn list_device_keys(&self) -> HashSet<&DevicePublicKey> { diff --git a/crates/net/src/server/storage/filesystem/sync.rs b/crates/server/src/storage/filesystem/sync.rs similarity index 97% rename from crates/net/src/server/storage/filesystem/sync.rs rename to crates/server/src/storage/filesystem/sync.rs index 47a0593b84..a77dc6df69 100644 --- a/crates/net/src/server/storage/filesystem/sync.rs +++ b/crates/server/src/storage/filesystem/sync.rs @@ -1,10 +1,8 @@ //! Synchronization helpers. use super::ServerStorage; -use crate::{ - protocol::sync::{ - CreateSet, ForceMerge, Merge, MergeOutcome, SyncStatus, SyncStorage, - UpdateSet, - }, +use async_trait::async_trait; +use indexmap::IndexMap; +use sos_protocol::{ sdk::{ commit::{CommitState, CommitTree, Comparison}, encode, @@ -17,17 +15,16 @@ use crate::{ vault::{VaultAccess, VaultId, VaultWriter}, vfs, Error, Paths, Result, }, + CreateSet, ForceMerge, Merge, MergeOutcome, SyncStatus, SyncStorage, + UpdateSet, }; -use async_trait::async_trait; -use indexmap::IndexMap; use std::sync::Arc; use tokio::sync::RwLock; -#[cfg(feature = "device")] -use crate::sdk::events::{DeviceDiff, DeviceEventLog, DeviceReducer}; +use sos_protocol::sdk::events::{DeviceDiff, DeviceEventLog, DeviceReducer}; #[cfg(feature = "files")] -use crate::sdk::events::{FileDiff, FileEventLog}; +use sos_protocol::sdk::events::{FileDiff, FileEventLog}; impl ServerStorage { /// Create a new vault file on disc and the associated @@ -78,7 +75,6 @@ impl ServerStorage { writer.patch_unchecked(&account_data.account).await?; } - #[cfg(feature = "device")] { let mut writer = self.device_log.write().await; writer.patch_unchecked(&account_data.device).await?; @@ -137,7 +133,6 @@ impl ServerStorage { self.force_merge_account(diff, outcome).await?; } - #[cfg(feature = "device")] if let Some(diff) = update_set.device.take() { self.force_merge_device(diff, outcome).await?; } @@ -211,7 +206,6 @@ impl ForceMerge for ServerStorage { Ok(()) } - #[cfg(feature = "device")] async fn force_merge_device( &mut self, diff: DeviceDiff, @@ -417,7 +411,6 @@ impl Merge for ServerStorage { reader.tree().compare(&state.1) } - #[cfg(feature = "device")] async fn merge_device( &mut self, diff: DeviceDiff, @@ -452,7 +445,6 @@ impl Merge for ServerStorage { Ok(checked_patch) } - #[cfg(feature = "device")] async fn compare_device( &self, state: &CommitState, @@ -559,7 +551,6 @@ impl StorageEventLogs for ServerStorage { Ok(Arc::clone(&self.account_log)) } - #[cfg(feature = "device")] async fn device_log(&self) -> Result>> { Ok(Arc::clone(&self.device_log)) } @@ -602,7 +593,6 @@ impl SyncStorage for ServerStorage { reader.tree().commit_state()? }; - #[cfg(feature = "device")] let device = { let reader = self.device_log.read().await; reader.tree().commit_state()? @@ -633,7 +623,6 @@ impl SyncStorage for ServerStorage { let mut root_commits = vec![ identity.1.root().into(), account.1.root().into(), - #[cfg(feature = "device")] device.1.root().into(), ]; #[cfg(feature = "files")] @@ -655,7 +644,6 @@ impl SyncStorage for ServerStorage { root, identity, account, - #[cfg(feature = "device")] device, #[cfg(feature = "files")] files, diff --git a/crates/net/src/server/storage/mod.rs b/crates/server/src/storage/mod.rs similarity index 100% rename from crates/net/src/server/storage/mod.rs rename to crates/server/src/storage/mod.rs diff --git a/crates/sos/Cargo.toml b/crates/sos/Cargo.toml new file mode 100644 index 0000000000..963b4eba6d --- /dev/null +++ b/crates/sos/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "sos" +version = "0.14.1" +edition = "2021" +description = "Distributed, encrypted database for private secrets." +homepage = "https://saveoursecrets.com" +license = "MIT OR Apache-2.0" +authors = ["saveoursecrets-developers "] +categories = [ + "command-line-utilities", + "cryptography::cryptocurrencies", + "authentication" +] + +[features] +default = [] +enable-cli-tests = [] + +[dependencies] +csv-async.workspace = true +binary-stream.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +serde_json.workspace = true +thiserror.workspace = true +async-recursion.workspace = true +futures.workspace = true +parking_lot.workspace = true +once_cell.workspace = true +toml.workspace = true +serde.workspace = true +enum-iterator.workspace = true +clap.workspace = true +human_bytes = "0.4" +tempfile = "3.5" +shell-words = "1" +terminal-banner = { version = "0.4.1", features = ["color"] } +unicode-width = "0.1" +kdam = { version = "0.5", features = ["rich", "spinner"] } +num_cpus = "1" +crossterm = "0.27" +ctrlc = "3" + +axum-server = { version = "0.6", features = ["tls-rustls"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync"] } +arboard = "3" +rustyline = "14" +rustyline-derive = "0.10" + +[dependencies.sos-net] +version = "0.14.1" +features = ["full"] +path = "../net" + +[dependencies.sos-cli-helpers] +version = "0.1.0" +path = "../cli_helpers" diff --git a/crates/sos/src/cli/mod.rs b/crates/sos/src/cli/mod.rs new file mode 100644 index 0000000000..d91419520b --- /dev/null +++ b/crates/sos/src/cli/mod.rs @@ -0,0 +1 @@ +pub mod sos; diff --git a/src/cli/sos.rs b/crates/sos/src/cli/sos.rs similarity index 100% rename from src/cli/sos.rs rename to crates/sos/src/cli/sos.rs diff --git a/src/commands/account.rs b/crates/sos/src/commands/account.rs similarity index 99% rename from src/commands/account.rs rename to crates/sos/src/commands/account.rs index d43fba8d89..6b5ee6ccdd 100644 --- a/src/commands/account.rs +++ b/crates/sos/src/commands/account.rs @@ -1,7 +1,6 @@ use clap::Subcommand; use enum_iterator::all; use sos_net::{ - client::NetworkAccount, sdk::{ account::{ archive::{ @@ -14,6 +13,7 @@ use sos_net::{ migrate::import::{ImportFormat, ImportTarget}, vfs, Paths, }, + NetworkAccount, }; use std::{path::PathBuf, sync::Arc}; use tokio::io::BufReader; diff --git a/src/commands/audit.rs b/crates/sos/src/commands/audit.rs similarity index 100% rename from src/commands/audit.rs rename to crates/sos/src/commands/audit.rs diff --git a/src/commands/changes.rs b/crates/sos/src/commands/changes.rs similarity index 100% rename from src/commands/changes.rs rename to crates/sos/src/commands/changes.rs diff --git a/src/commands/check.rs b/crates/sos/src/commands/check.rs similarity index 100% rename from src/commands/check.rs rename to crates/sos/src/commands/check.rs diff --git a/src/commands/device.rs b/crates/sos/src/commands/device.rs similarity index 98% rename from src/commands/device.rs rename to crates/sos/src/commands/device.rs index c49634e20e..5ebb047c05 100644 --- a/src/commands/device.rs +++ b/crates/sos/src/commands/device.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use tokio::sync::RwLock; use sos_net::{ - client::NetworkAccount, sdk::{account::Account, device::TrustedDevice, identity::AccountRef}, + NetworkAccount, }; use crate::{ diff --git a/src/commands/environment.rs b/crates/sos/src/commands/environment.rs similarity index 100% rename from src/commands/environment.rs rename to crates/sos/src/commands/environment.rs diff --git a/src/commands/events.rs b/crates/sos/src/commands/events.rs similarity index 100% rename from src/commands/events.rs rename to crates/sos/src/commands/events.rs diff --git a/src/commands/folder.rs b/crates/sos/src/commands/folder.rs similarity index 100% rename from src/commands/folder.rs rename to crates/sos/src/commands/folder.rs diff --git a/src/commands/mod.rs b/crates/sos/src/commands/mod.rs similarity index 100% rename from src/commands/mod.rs rename to crates/sos/src/commands/mod.rs diff --git a/src/commands/preferences.rs b/crates/sos/src/commands/preferences.rs similarity index 100% rename from src/commands/preferences.rs rename to crates/sos/src/commands/preferences.rs diff --git a/src/commands/secret.rs b/crates/sos/src/commands/secret.rs similarity index 100% rename from src/commands/secret.rs rename to crates/sos/src/commands/secret.rs diff --git a/src/commands/security_report.rs b/crates/sos/src/commands/security_report.rs similarity index 99% rename from src/commands/security_report.rs rename to crates/sos/src/commands/security_report.rs index 7b7084b7e4..be9079e42e 100644 --- a/src/commands/security_report.rs +++ b/crates/sos/src/commands/security_report.rs @@ -3,7 +3,7 @@ use crate::{ Error, Result, }; use sos_net::{ - client::hashcheck, + hashcheck, sdk::{ account::{ security_report::{SecurityReportOptions, SecurityReportRow}, diff --git a/src/commands/server.rs b/crates/sos/src/commands/server.rs similarity index 97% rename from src/commands/server.rs rename to crates/sos/src/commands/server.rs index 6f982ffcc2..7b8cddecbd 100644 --- a/src/commands/server.rs +++ b/crates/sos/src/commands/server.rs @@ -7,9 +7,9 @@ use crate::{ }; use clap::Subcommand; use sos_net::{ - client::RemoteSync, - protocol::sync::{Origin, SyncOptions}, + protocol::{Origin, SyncOptions}, sdk::{identity::AccountRef, url::Url}, + RemoteSync, }; #[derive(Subcommand, Debug)] diff --git a/src/commands/shell/cli.rs b/crates/sos/src/commands/shell/cli.rs similarity index 99% rename from src/commands/shell/cli.rs rename to crates/sos/src/commands/shell/cli.rs index 9e79919b1a..e54a8cffa1 100644 --- a/src/commands/shell/cli.rs +++ b/crates/sos/src/commands/shell/cli.rs @@ -3,10 +3,10 @@ use std::sync::Arc; use terminal_banner::{Banner, Padding}; use sos_net::{ - client::NetworkAccount, sdk::{ account::Account, identity::AccountRef, vault::FolderRef, vfs, Paths, }, + NetworkAccount, }; use tokio::sync::RwLock; diff --git a/src/commands/shell/mod.rs b/crates/sos/src/commands/shell/mod.rs similarity index 100% rename from src/commands/shell/mod.rs rename to crates/sos/src/commands/shell/mod.rs diff --git a/src/commands/shell/repl.rs b/crates/sos/src/commands/shell/repl.rs similarity index 100% rename from src/commands/shell/repl.rs rename to crates/sos/src/commands/shell/repl.rs diff --git a/src/commands/shell/welcome.txt b/crates/sos/src/commands/shell/welcome.txt similarity index 100% rename from src/commands/shell/welcome.txt rename to crates/sos/src/commands/shell/welcome.txt diff --git a/src/commands/sync.rs b/crates/sos/src/commands/sync.rs similarity index 98% rename from src/commands/sync.rs rename to crates/sos/src/commands/sync.rs index a61abe48e5..e7782fbde2 100644 --- a/src/commands/sync.rs +++ b/crates/sos/src/commands/sync.rs @@ -4,8 +4,7 @@ use crate::{ }; use clap::Subcommand; use sos_net::{ - client::{NetworkAccount, RemoteSync}, - protocol::sync::{Origin, SyncOptions, SyncStatus, SyncStorage}, + protocol::{Origin, SyncOptions, SyncStatus, SyncStorage}, sdk::{ account::Account, commit::{CommitState, CommitTree, Comparison}, @@ -14,6 +13,7 @@ use sos_net::{ storage::StorageEventLogs, url::Url, }, + NetworkAccount, RemoteSync, }; #[derive(Subcommand, Debug)] diff --git a/src/commands/tools.rs b/crates/sos/src/commands/tools.rs similarity index 100% rename from src/commands/tools.rs rename to crates/sos/src/commands/tools.rs diff --git a/src/error.rs b/crates/sos/src/error.rs similarity index 95% rename from src/error.rs rename to crates/sos/src/error.rs index 91fcf6e605..6b796931b0 100644 --- a/src/error.rs +++ b/crates/sos/src/error.rs @@ -1,6 +1,5 @@ use sos_net::{ - client, - protocol::sync::SyncError, + protocol::SyncError, sdk::{vault::secret::SecretRef, vcard4}, }; use std::path::PathBuf; @@ -35,7 +34,7 @@ pub enum Error { /// Error performing an initial sync with a server. #[error(r#"initial sync has errors: {0}"#)] - InitialSync(SyncError), + InitialSync(SyncError), /// Sync failed. #[error(r#"sync failed"#)] @@ -187,14 +186,6 @@ pub enum Error { #[error(transparent)] Net(#[from] sos_net::Error), - /// Error generated by the networking client module. - #[error(transparent)] - NetClient(#[from] sos_net::client::Error), - - /// Error generated by the networking server module. - #[error(transparent)] - NetServer(#[from] sos_net::server::Error), - /// Error generated parsing a URL. #[error(transparent)] UrlParse(#[from] sos_net::sdk::url::ParseError), diff --git a/src/helpers/account.rs b/crates/sos/src/helpers/account.rs similarity index 99% rename from src/helpers/account.rs rename to crates/sos/src/helpers/account.rs index 77424a1e42..e4d2b638da 100644 --- a/src/helpers/account.rs +++ b/crates/sos/src/helpers/account.rs @@ -2,7 +2,6 @@ use std::{borrow::Cow, sync::Arc}; use sos_net::{ - client::NetworkAccount, sdk::{ account::{Account, AccountLocked, SigninOptions}, constants::DEFAULT_VAULT_NAME, @@ -14,6 +13,7 @@ use sos_net::{ vault::{FolderRef, Summary}, Paths, }, + NetworkAccount, }; use terminal_banner::{Banner, Padding}; use tokio::sync::{mpsc, RwLock}; diff --git a/src/helpers/editor.rs b/crates/sos/src/helpers/editor.rs similarity index 100% rename from src/helpers/editor.rs rename to crates/sos/src/helpers/editor.rs diff --git a/src/helpers/mod.rs b/crates/sos/src/helpers/mod.rs similarity index 97% rename from src/helpers/mod.rs rename to crates/sos/src/helpers/mod.rs index f738005c38..a32ba2de79 100644 --- a/src/helpers/mod.rs +++ b/crates/sos/src/helpers/mod.rs @@ -7,10 +7,11 @@ use tokio::sync::broadcast::Sender; pub(crate) mod account; pub(crate) mod editor; -pub(crate) mod messages; pub(crate) mod readline; pub(crate) mod secret; +pub use sos_cli_helpers::messages; + pub use account::USER; /// Is a progress monitor running? diff --git a/src/helpers/readline.rs b/crates/sos/src/helpers/readline.rs similarity index 100% rename from src/helpers/readline.rs rename to crates/sos/src/helpers/readline.rs diff --git a/src/helpers/secret.rs b/crates/sos/src/helpers/secret.rs similarity index 100% rename from src/helpers/secret.rs rename to crates/sos/src/helpers/secret.rs diff --git a/src/lib.rs b/crates/sos/src/lib.rs similarity index 51% rename from src/lib.rs rename to crates/sos/src/lib.rs index 566c9d447e..7869b19e65 100644 --- a/src/lib.rs +++ b/crates/sos/src/lib.rs @@ -1,8 +1,7 @@ //! Command line tools for [Save Our Secrets](https://saveoursecrets.com). //! -//! This crate contains the binaries for the `sos` client and -//! the `sos-server` reference server; more information is on the -//! [command line tools](https://saveoursecrets.com/command-line-tools/) downloads page. +//! This crate contains the binary for the `sos`; more information is on the +//! [command line tools](https://saveoursecrets.com/command-line-tools/) downloads page; for the server binary see the [sos-server](https://docs.rs/sos-server/) crate. //! //! See the [CLI documentation](https://saveoursecrets.com/docs/cli/) for usage information or browse the [online help manual](https://saveoursecrets.com/docs/cli/help/); the libraries are available at [sos-sdk](https://docs.rs/sos-sdk/) and [sos-net](https://docs.rs/sos-net/). #![deny(missing_docs)] @@ -17,7 +16,9 @@ mod error; pub(crate) mod helpers; #[doc(hidden)] -pub use helpers::{messages::*, USER}; +pub use helpers::USER; + +pub use sos_cli_helpers::*; #[doc(hidden)] pub use error::Error; @@ -25,22 +26,3 @@ pub use error::Error; /// Result type for the executable library. #[doc(hidden)] pub type Result = std::result::Result; - -/// Command tree used to print help output for the website. -#[doc(hidden)] -#[derive(Debug, serde::Serialize, serde::Deserialize)] -pub struct CommandTree { - /// Name of the command. - pub name: String, - /// Subcommands. - pub commands: Vec, -} - -impl From<&clap::Command> for CommandTree { - fn from(value: &clap::Command) -> Self { - CommandTree { - name: value.get_name().to_string(), - commands: value.get_subcommands().map(|c| c.into()).collect(), - } - } -} diff --git a/src/bin/sos.rs b/crates/sos/src/main.rs similarity index 91% rename from src/bin/sos.rs rename to crates/sos/src/main.rs index 191bb3a0d9..c100bae028 100644 --- a/src/bin/sos.rs +++ b/crates/sos/src/main.rs @@ -1,5 +1,6 @@ #[cfg(not(target_arch = "wasm32"))] -use sos::{fail, warn, Result, USER}; +use sos::{Result, USER}; +use sos_cli_helpers::messages::{fail, warn}; #[cfg(not(target_arch = "wasm32"))] #[tokio::main] diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 99264997bf..3f935b852f 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml @@ -14,6 +14,7 @@ futures.workspace = true tempfile.workspace = true anyhow = "1" sos-net = { path = "../net", features = ["full"] } +sos-server = { path = "../server" } tokio = { version = "1", default-features = false, features = ["rt", "fs", "io-util", "sync"] } axum-server = { version = "0.6", features = ["tls-rustls"] } pretty_assertions = "1.4" diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 082d7afd98..b1f642f477 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -15,11 +15,12 @@ use std::{ use tokio::sync::{oneshot, RwLock}; use sos_net::{ - protocol::sync::Origin, + protocol::Origin, sdk::{signer::ecdsa::Address, url::Url, vfs, Paths}, - server::{Server, ServerConfig, State}, }; +use sos_server::{Server, ServerConfig, State}; + mod helpers; pub mod mock; mod network; diff --git a/crates/test_utils/src/network.rs b/crates/test_utils/src/network.rs index 18e1ded630..4e92ddfda7 100644 --- a/crates/test_utils/src/network.rs +++ b/crates/test_utils/src/network.rs @@ -3,11 +3,7 @@ use anyhow::Result; use copy_dir::copy_dir; use secrecy::SecretString; use sos_net::{ - client::{ - InflightNotification, InflightTransfers, ListenOptions, - NetworkAccount, RemoteBridge, RemoteSync, SyncClient, - }, - protocol::sync::{Origin, SyncStorage}, + protocol::{Origin, SyncStorage}, sdk::{ account::{Account, AccountBuilder}, constants::{FILES_DIR, VAULT_EXT}, @@ -20,6 +16,8 @@ use sos_net::{ vault::{Summary, VaultId}, vfs, Paths, }, + InflightNotification, InflightTransfers, ListenOptions, NetworkAccount, + RemoteBridge, RemoteSync, SyncClient, }; use std::{path::PathBuf, sync::Arc, time::Duration}; use tokio::sync::Mutex; diff --git a/crates/test_utils/src/pairing.rs b/crates/test_utils/src/pairing.rs index f06de89daa..6522b041a6 100644 --- a/crates/test_utils/src/pairing.rs +++ b/crates/test_utils/src/pairing.rs @@ -2,11 +2,9 @@ use crate::SimulatedDevice; use anyhow::Result; use futures::{stream::FuturesUnordered, Future, StreamExt}; use sos_net::{ - client::{ - pairing::{self, AcceptPairing, OfferPairing}, - NetworkAccount, - }, + pairing::{self, AcceptPairing, OfferPairing}, sdk::prelude::*, + NetworkAccount, }; use std::pin::Pin; use tokio::sync::mpsc; diff --git a/crates/vfs/CHANGELOG.md b/crates/vfs/CHANGELOG.md new file mode 100644 index 0000000000..f0c422deb4 --- /dev/null +++ b/crates/vfs/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.2.3](https://github.com/saveoursecrets/sdk/compare/sos-vfs-v0.2.2...sos-vfs-v0.2.3) - 2024-06-21 + +### Other +- Improve integrity checks ([#439](https://github.com/saveoursecrets/sdk/pull/439)) +- Device vault fix ([#367](https://github.com/saveoursecrets/sdk/pull/367)) diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index c16d344046..32767420ec 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sos-vfs" -version = "0.2.2" +version = "0.2.3" edition = "2021" description = "Virtual file system same as tokio::fs." homepage = "https://saveoursecrets.com" diff --git a/scripts/ci/prepare-executables.sh b/scripts/ci/prepare-executables.sh index 9156b7339c..f6f7ce9cd1 100755 --- a/scripts/ci/prepare-executables.sh +++ b/scripts/ci/prepare-executables.sh @@ -9,5 +9,5 @@ echo "$EXES" mkdir -p $BIN_DIR cp -f $EXES $BIN_DIR -cp LICENSE-APACHE LICENSE-MIT COPYRIGHT $BIN_DIR +cp LICENSE-AGPL LICENSE-APACHE LICENSE-MIT COPYRIGHT $BIN_DIR ls -la $BIN_DIR diff --git a/src/bin/sos_server.rs b/src/bin/sos_server.rs deleted file mode 100644 index 890f3384d9..0000000000 --- a/src/bin/sos_server.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[cfg(not(target_arch = "wasm32"))] -use sos::{fail, Result}; - -#[cfg(not(target_arch = "wasm32"))] -#[tokio::main] -async fn main() -> Result<()> { - use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - tracing_subscriber::registry() - .with(tracing_subscriber::EnvFilter::new( - std::env::var("RUST_LOG").unwrap_or_else(|_| "sos=info".into()), - )) - .with(tracing_subscriber::fmt::layer().without_time()) - .init(); - - if let Err(e) = sos::cli::sos_server::run().await { - fail(e.to_string()); - } - - Ok(()) -} - -#[cfg(target_arch = "wasm32")] -fn main() {} diff --git a/src/cli/mod.rs b/src/cli/mod.rs deleted file mode 100644 index ffe5065e1d..0000000000 --- a/src/cli/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod sos; -pub mod sos_server; diff --git a/src/cli/sos_server.rs b/src/cli/sos_server.rs deleted file mode 100644 index f01871fd5c..0000000000 --- a/src/cli/sos_server.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::{CommandTree, Result}; -use clap::{CommandFactory, Parser, Subcommand}; -use std::path::PathBuf; - -#[derive(Parser, Debug)] -#[clap(name = "sos-server", author, version, about, long_about = None)] -pub struct SosServer { - #[clap(subcommand)] - cmd: Command, -} - -#[derive(Debug, Subcommand)] -pub enum Command { - /// Create a configuration file. - Init { - /// Path to the storage folder. - #[clap(short, long)] - path: Option, - - /// Config file to write. - config: PathBuf, - }, - /// Start a server. - Start { - /// Bind to host:port. - #[clap(short, long, default_value = "0.0.0.0:5053")] - bind: String, - - /// Config file to load. - config: PathBuf, - }, -} - -pub async fn run() -> Result<()> { - // Support JSON output of command tree - if std::env::var("SOS_CLI_JSON").ok().is_some() { - let cmd = SosServer::command(); - let tree: CommandTree = (&cmd).into(); - serde_json::to_writer_pretty(std::io::stdout(), &tree)?; - std::process::exit(0); - } - - let args = SosServer::parse(); - - match args.cmd { - Command::Init { config, path } => { - service::init(config, path).await?; - } - Command::Start { bind, config } => { - service::start(bind, config).await?; - } - } - - Ok(()) -} - -mod service { - use axum_server::Handle; - use sos_net::{ - sdk::vfs, - server::{Error, Result, Server, ServerConfig, State, StorageConfig}, - }; - use std::{net::SocketAddr, path::PathBuf, str::FromStr, sync::Arc}; - use tokio::sync::RwLock; - - /// Initialize default server configuration. - pub async fn init( - output: PathBuf, - mut path: Option, - ) -> Result<()> { - if vfs::try_exists(&output).await? { - return Err(Error::FileExists(output)); - } - - let mut config: ServerConfig = Default::default(); - if let Some(path) = path.take() { - config.storage = StorageConfig { path }; - } - - let content = toml::to_string_pretty(&config)?; - vfs::write(output, content.as_bytes()).await?; - Ok(()) - } - - /// Start a web server. - pub async fn start(bind: String, config: PathBuf) -> Result<()> { - let config = ServerConfig::load(&config).await?; - let backend = config.backend().await?; - - let state = Arc::new(RwLock::new(State { - config, - sockets: Default::default(), - })); - - let handle = Handle::new(); - - let addr = SocketAddr::from_str(&bind)?; - let server = Server::new(backend.directory()).await?; - server - .start(addr, state, Arc::new(RwLock::new(backend)), handle) - .await?; - Ok(()) - } -} diff --git a/src/commands/convert.rs b/src/commands/convert.rs deleted file mode 100644 index 874d756119..0000000000 --- a/src/commands/convert.rs +++ /dev/null @@ -1,83 +0,0 @@ -use clap::Subcommand; -use sos_net::sdk::{ - account::Account, - crypto::{AccessKey, Cipher, KeyDerivation}, - identity::AccountRef, -}; -use terminal_banner::{Banner, Padding}; - -use crate::{ - helpers::{ - account::resolve_user_with_password, - messages::{info, success}, - readline::read_flag, - }, - Result, -}; - -#[derive(Subcommand, Debug)] -pub enum Command { - /// Convert the cipher for an account. - Cipher { - /// Account name or address. - #[clap(short, long)] - account: Option, - - /// Key derivation function. - #[clap(short, long)] - kdf: Option, - - /// Convert to this cipher. - cipher: Cipher, - }, -} - -pub async fn run(cmd: Command) -> Result<()> { - match cmd { - Command::Cipher { - account, - cipher, - kdf, - } => { - let (user, password) = - resolve_user_with_password(account.as_ref(), false).await?; - let mut owner = user.write().await; - - let banner = Banner::new() - .padding(Padding::one()) - .text("CONVERT CIPHER".into()) - .newline() - .text( - "Changing a cipher is a risky operation, be sure you understand the risks.".into()) - .newline() - .text( - "* Vault and event logs will be overwritten".into()) - .text( - "* Event history is compacted".into()) - .text( - "* Sync will overwrite data on servers".into()); - - let result = banner.render(); - println!("{}", result); - - let prompt = - format!(r#"Convert to cipher "{}" (y/n)? "#, &cipher); - if read_flag(Some(&prompt))? { - let access_key: AccessKey = password.into(); - let conversion = owner - .change_cipher(&access_key, &cipher, kdf.clone()) - .await?; - if conversion.is_empty() { - info(format!( - "no files to convert, all folders use {} and {}", - cipher, - kdf.unwrap_or_default(), - )); - } else { - success("cipher changed"); - } - } - } - } - Ok(()) -} diff --git a/tests/access_control/allow.rs b/tests/access_control/allow.rs index b565e0aff5..64c577e2d9 100644 --- a/tests/access_control/allow.rs +++ b/tests/access_control/allow.rs @@ -6,12 +6,12 @@ use crate::test_utils::{ }; use http::StatusCode; use sos_net::{ - client::{Error as ClientError, NetworkAccount, RemoteSync}, - protocol::sync::SyncError, - sdk::prelude::*, - server::AccessControlConfig, + protocol::SyncError, sdk::prelude::*, Error as ClientError, + NetworkAccount, RemoteSync, }; +use sos_server::AccessControlConfig; + /// Tests server allow access control. #[tokio::test] async fn access_control_allow() -> Result<()> { diff --git a/tests/access_control/deny.rs b/tests/access_control/deny.rs index 03efe69083..27f56219ad 100644 --- a/tests/access_control/deny.rs +++ b/tests/access_control/deny.rs @@ -6,12 +6,12 @@ use crate::test_utils::{ }; use http::StatusCode; use sos_net::{ - client::{Error as ClientError, NetworkAccount, RemoteSync}, - protocol::sync::SyncError, - sdk::prelude::*, - server::AccessControlConfig, + protocol::SyncError, sdk::prelude::*, Error as ClientError, + NetworkAccount, RemoteSync, }; +use sos_server::AccessControlConfig; + /// Tests server deny access control. #[tokio::test] async fn access_control_deny() -> Result<()> { diff --git a/tests/auto_merge/create_secrets.rs b/tests/auto_merge/create_secrets.rs index b4a688fd60..4d9156ed11 100644 --- a/tests/auto_merge/create_secrets.rs +++ b/tests/auto_merge/create_secrets.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests making conflicting changes to a folder whilst /// a server is offline and resolving the conflicts with diff --git a/tests/auto_merge/delete_secrets.rs b/tests/auto_merge/delete_secrets.rs index 72266300c8..f6c52f5be4 100644 --- a/tests/auto_merge/delete_secrets.rs +++ b/tests/auto_merge/delete_secrets.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests making deletes to a folder whilst /// a server is offline and resolving the conflicts with diff --git a/tests/auto_merge/edit_secrets.rs b/tests/auto_merge/edit_secrets.rs index 851fa568e6..e00d0c1f88 100644 --- a/tests/auto_merge/edit_secrets.rs +++ b/tests/auto_merge/edit_secrets.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests making conflicting edits to a folder whilst /// a server is offline and resolving the conflicts with diff --git a/tests/auto_merge/scan_commits.rs b/tests/auto_merge/scan_commits.rs index c7a89126bd..ecbb931338 100644 --- a/tests/auto_merge/scan_commits.rs +++ b/tests/auto_merge/scan_commits.rs @@ -1,8 +1,9 @@ use crate::test_utils::{mock, simulate_device, spawn, teardown}; use anyhow::Result; use sos_net::{ - client::SyncClient, protocol::sync::EventLogType, protocol::ScanRequest, + protocol::{EventLogType, ScanRequest}, sdk::prelude::*, + SyncClient, }; /// Tests scanning commit hashes on remote servers. diff --git a/tests/diff_merge/folder_create.rs b/tests/diff_merge/folder_create.rs index e34e71ac9a..0ca02fdc11 100644 --- a/tests/diff_merge/folder_create.rs +++ b/tests/diff_merge/folder_create.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/folder_delete.rs b/tests/diff_merge/folder_delete.rs index 1c98ecf773..3df749b994 100644 --- a/tests/diff_merge/folder_delete.rs +++ b/tests/diff_merge/folder_delete.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/folder_import.rs b/tests/diff_merge/folder_import.rs index 09fb3adb52..a9ba2571d0 100644 --- a/tests/diff_merge/folder_import.rs +++ b/tests/diff_merge/folder_import.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/folder_rename.rs b/tests/diff_merge/folder_rename.rs index 0fa37a62da..66c1268af1 100644 --- a/tests/diff_merge/folder_rename.rs +++ b/tests/diff_merge/folder_rename.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/secret_create.rs b/tests/diff_merge/secret_create.rs index 7b1aee4115..5108f54b32 100644 --- a/tests/diff_merge/secret_create.rs +++ b/tests/diff_merge/secret_create.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/secret_delete.rs b/tests/diff_merge/secret_delete.rs index 0b1308e19a..ae35633ab8 100644 --- a/tests/diff_merge/secret_delete.rs +++ b/tests/diff_merge/secret_delete.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/secret_move.rs b/tests/diff_merge/secret_move.rs index cf3abc12e3..e4eea38827 100644 --- a/tests/diff_merge/secret_move.rs +++ b/tests/diff_merge/secret_move.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/diff_merge/secret_update.rs b/tests/diff_merge/secret_update.rs index f7ea0f1186..94486e4217 100644 --- a/tests/diff_merge/secret_update.rs +++ b/tests/diff_merge/secret_update.rs @@ -1,7 +1,7 @@ use crate::test_utils::{copy_account, mock, setup, teardown}; use anyhow::Result; use sos_net::{ - protocol::sync::{diff, Merge, MergeOutcome, SyncStorage}, + protocol::{diff, Merge, MergeOutcome, SyncStorage}, sdk::prelude::*, }; diff --git a/tests/file_transfers/multi_server.rs b/tests/file_transfers/multi_server.rs index 6f5663341d..187561e4ed 100644 --- a/tests/file_transfers/multi_server.rs +++ b/tests/file_transfers/multi_server.rs @@ -7,7 +7,7 @@ use crate::test_utils::{ mock::files::{create_file_secret, update_file_secret}, simulate_device, spawn, teardown, wait_for_num_transfers, }; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests uploading an external file to multiple servers. #[tokio::test] diff --git a/tests/file_transfers/offline_multi.rs b/tests/file_transfers/offline_multi.rs index 092232fe16..11dca684b7 100644 --- a/tests/file_transfers/offline_multi.rs +++ b/tests/file_transfers/offline_multi.rs @@ -8,7 +8,7 @@ use crate::test_utils::{ mock::files::{create_file_secret, update_file_secret}, simulate_device, spawn, teardown, wait_for_file, wait_for_file_not_exist, }; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests uploading an external file to multiple servers /// when the first server is offline. diff --git a/tests/file_transfers/single_server.rs b/tests/file_transfers/single_server.rs index 6fa625beaf..8de9f8f8a7 100644 --- a/tests/file_transfers/single_server.rs +++ b/tests/file_transfers/single_server.rs @@ -7,7 +7,7 @@ use crate::test_utils::{ mock::files::{create_file_secret, update_file_secret}, simulate_device, spawn, teardown, wait_for_num_transfers, }; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests uploading an external file. #[tokio::test] diff --git a/tests/network_account/archive_unarchive.rs b/tests/network_account/archive_unarchive.rs index b36b4db463..15ee64982a 100644 --- a/tests/network_account/archive_unarchive.rs +++ b/tests/network_account/archive_unarchive.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ simulate_device_with_builder, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests moving to and from an archive folder. #[tokio::test] diff --git a/tests/network_account/change_account_password.rs b/tests/network_account/change_account_password.rs index f8f8033531..f5a7229aad 100644 --- a/tests/network_account/change_account_password.rs +++ b/tests/network_account/change_account_password.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests changing the account password and force syncing /// the updated and diverged account data. diff --git a/tests/network_account/change_cipher.rs b/tests/network_account/change_cipher.rs index 98652128d5..ef0852fa4d 100644 --- a/tests/network_account/change_cipher.rs +++ b/tests/network_account/change_cipher.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests changing the account cipher and force syncing /// the updated and diverged account data. diff --git a/tests/network_account/change_folder_password.rs b/tests/network_account/change_folder_password.rs index 6f290a38bf..02311906b3 100644 --- a/tests/network_account/change_folder_password.rs +++ b/tests/network_account/change_folder_password.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests changing a folder password and force syncing /// the updated folder events log. diff --git a/tests/network_account/compact_account.rs b/tests/network_account/compact_account.rs index bd9ca00efa..51757c2f1b 100644 --- a/tests/network_account/compact_account.rs +++ b/tests/network_account/compact_account.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests compacting all the folders in an account and /// syncing the changes to another device. diff --git a/tests/network_account/compact_folder.rs b/tests/network_account/compact_folder.rs index 095b8ba48a..ccfef782e3 100644 --- a/tests/network_account/compact_folder.rs +++ b/tests/network_account/compact_folder.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests compacting a single folders and /// syncing the changes to another device. diff --git a/tests/network_account/delete_account.rs b/tests/network_account/delete_account.rs index 89755e5a3c..4459080bab 100644 --- a/tests/network_account/delete_account.rs +++ b/tests/network_account/delete_account.rs @@ -1,6 +1,6 @@ use crate::test_utils::{simulate_device, spawn, teardown}; use anyhow::Result; -use sos_net::{client::SyncClient, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, SyncClient}; /// Tests creating and then deleting all the account data /// on a remote server. diff --git a/tests/network_account/multiple_remotes.rs b/tests/network_account/multiple_remotes.rs index 1b62fc3fab..7f2e340c3b 100644 --- a/tests/network_account/multiple_remotes.rs +++ b/tests/network_account/multiple_remotes.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, mock, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests syncing a single client with multiple /// remote servers. diff --git a/tests/network_account/multiple_remotes_fallback.rs b/tests/network_account/multiple_remotes_fallback.rs index e3d7c411c2..58f8bd843c 100644 --- a/tests/network_account/multiple_remotes_fallback.rs +++ b/tests/network_account/multiple_remotes_fallback.rs @@ -3,10 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{ - client::{RemoteSync, SyncError}, - sdk::prelude::*, -}; +use sos_net::{sdk::prelude::*, RemoteSync, SyncError}; /// Tests syncing a single client with multiple /// remote servers when one of the servers is offline. diff --git a/tests/network_account/offline_manual.rs b/tests/network_account/offline_manual.rs index e744943578..f9f9e25e5c 100644 --- a/tests/network_account/offline_manual.rs +++ b/tests/network_account/offline_manual.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ sync_pause, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests syncing events between two clients after /// a server goes offline and a client commits changes diff --git a/tests/network_account/rename_account.rs b/tests/network_account/rename_account.rs index 51e956df2e..bb6b5d17b5 100644 --- a/tests/network_account/rename_account.rs +++ b/tests/network_account/rename_account.rs @@ -2,7 +2,7 @@ use crate::test_utils::{ assert_local_remote_events_eq, simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests changing the account name is synced. #[tokio::test] diff --git a/tests/network_account/send_secret_create.rs b/tests/network_account/send_secret_create.rs index d9f21d85f7..26070ff251 100644 --- a/tests/network_account/send_secret_create.rs +++ b/tests/network_account/send_secret_create.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests syncing create secret events between two /// clients. diff --git a/tests/network_account/send_secret_move.rs b/tests/network_account/send_secret_move.rs index e35dd0812a..d929b7dba8 100644 --- a/tests/network_account/send_secret_move.rs +++ b/tests/network_account/send_secret_move.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests syncing move secret events between two /// clients. diff --git a/tests/network_account/websocket_reconnect.rs b/tests/network_account/websocket_reconnect.rs index ef2b19faa2..abd87d748a 100644 --- a/tests/network_account/websocket_reconnect.rs +++ b/tests/network_account/websocket_reconnect.rs @@ -1,9 +1,6 @@ use crate::test_utils::{simulate_device, spawn, teardown}; use anyhow::Result; -use sos_net::{ - client::{HttpClient, ListenOptions, NetworkRetry}, - sdk::prelude::*, -}; +use sos_net::{sdk::prelude::*, HttpClient, ListenOptions, NetworkRetry}; use std::{sync::Arc, time::Duration}; use tokio::sync::Mutex; diff --git a/tests/network_account/websocket_shutdown_explicit.rs b/tests/network_account/websocket_shutdown_explicit.rs index 3d8a725daf..25fa1794b5 100644 --- a/tests/network_account/websocket_shutdown_explicit.rs +++ b/tests/network_account/websocket_shutdown_explicit.rs @@ -1,6 +1,6 @@ use crate::test_utils::{simulate_device, spawn, teardown}; use anyhow::Result; -use sos_net::{client::HttpClient, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, HttpClient}; use std::time::Duration; /// Tests websocket shutdown logic. diff --git a/tests/network_account/websocket_shutdown_signout.rs b/tests/network_account/websocket_shutdown_signout.rs index a0c959db36..ec611688d8 100644 --- a/tests/network_account/websocket_shutdown_signout.rs +++ b/tests/network_account/websocket_shutdown_signout.rs @@ -1,6 +1,6 @@ use crate::test_utils::{simulate_device, spawn, teardown}; use anyhow::Result; -use sos_net::{client::HttpClient, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, HttpClient}; use std::time::Duration; /// Tests websocket shutdown logic on sign out. diff --git a/tests/pairing/device_revoke.rs b/tests/pairing/device_revoke.rs index 3415ab9ccd..6247f8a00d 100644 --- a/tests/pairing/device_revoke.rs +++ b/tests/pairing/device_revoke.rs @@ -4,10 +4,7 @@ use crate::test_utils::{ }; use anyhow::Result; use http::StatusCode; -use sos_net::{ - client::{Error as ClientError, RemoteSync, SyncError}, - sdk::prelude::*, -}; +use sos_net::{sdk::prelude::*, Error as ClientError, RemoteSync, SyncError}; /// Tests pairing a new device and revoking trust in the device. #[tokio::test] diff --git a/tests/pairing/pairing_account_name.rs b/tests/pairing/pairing_account_name.rs index b7b149da40..c656e69a17 100644 --- a/tests/pairing/pairing_account_name.rs +++ b/tests/pairing/pairing_account_name.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests the protocol for pairing devices respects /// an account name that has been changed. diff --git a/tests/pairing/pairing_inverted.rs b/tests/pairing/pairing_inverted.rs index d0ae6e5dff..ffd83a8141 100644 --- a/tests/pairing/pairing_inverted.rs +++ b/tests/pairing/pairing_inverted.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests the protocol for pairing devices using the inverted flow. #[tokio::test] diff --git a/tests/pairing/pairing_protocol.rs b/tests/pairing/pairing_protocol.rs index e3268114b6..1aaa81b2d8 100644 --- a/tests/pairing/pairing_protocol.rs +++ b/tests/pairing/pairing_protocol.rs @@ -3,7 +3,7 @@ use crate::test_utils::{ simulate_device, spawn, teardown, }; use anyhow::Result; -use sos_net::{client::RemoteSync, sdk::prelude::*}; +use sos_net::{sdk::prelude::*, RemoteSync}; /// Tests the protocol for pairing devices. #[tokio::test] diff --git a/tests/pairing/pairing_websocket_shutdown.rs b/tests/pairing/pairing_websocket_shutdown.rs index f2e4fafe0f..8221f8d02e 100644 --- a/tests/pairing/pairing_websocket_shutdown.rs +++ b/tests/pairing/pairing_websocket_shutdown.rs @@ -2,7 +2,7 @@ use crate::test_utils::{simulate_device, spawn, teardown}; use anyhow::Result; use futures::{stream::FuturesUnordered, Future, StreamExt}; use sos_net::{ - client::pairing::{self, OfferPairing}, + pairing::{self, OfferPairing}, sdk::prelude::*, }; use std::pin::Pin;