├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE-AGPL3 ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── ci ├── android_before_install.sh ├── android_install.sh ├── before_deploy.sh ├── cargo_config_template ├── post │ ├── cargo-sweep.sh │ └── kcov │ │ ├── run.sh │ │ └── try-install.sh └── pre │ ├── capnp.sh │ └── cargo-config.sh ├── codecov.yml ├── components ├── app │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── app_conn │ │ ├── buyer.rs │ │ ├── config.rs │ │ ├── mod.rs │ │ ├── routes.rs │ │ └── seller.rs │ │ ├── connect.rs │ │ ├── gen.rs │ │ ├── identity.rs │ │ ├── lib.rs │ │ └── types.rs ├── app_client │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── connect.rs │ │ └── lib.rs ├── app_server │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── lib.rs │ │ ├── server.rs │ │ └── tests │ │ ├── all_apps_closed.rs │ │ ├── funder_command.rs │ │ ├── index_client_command.rs │ │ ├── mod.rs │ │ ├── request_routes.rs │ │ ├── request_send_funds.rs │ │ ├── two_apps.rs │ │ └── utils.rs ├── bin │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── bin │ │ ├── stindex.rs │ │ ├── stmgr.rs │ │ ├── stnode.rs │ │ └── strelay.rs │ │ ├── lib.rs │ │ ├── stindex │ │ ├── mod.rs │ │ ├── net_index.rs │ │ └── stindexlib.rs │ │ ├── stmgrlib.rs │ │ ├── stnode │ │ ├── file_trusted_apps.rs │ │ ├── mod.rs │ │ ├── net_node.rs │ │ └── stnodelib.rs │ │ └── strelay │ │ ├── mod.rs │ │ ├── net_relay.rs │ │ └── strelaylib.rs ├── capnp_conv │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── build.rs │ ├── capnp_conv_derive │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ └── src │ │ │ ├── derive_enum.rs │ │ │ ├── derive_struct.rs │ │ │ ├── lib.rs │ │ │ └── util.rs │ ├── src │ │ └── lib.rs │ └── tests │ │ ├── capnp │ │ └── test.capnp │ │ ├── derive.rs │ │ └── with.rs ├── channeler │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── channeler.rs │ │ ├── connect_pool.rs │ │ ├── connector_utils.rs │ │ ├── inner_loop.rs │ │ ├── lib.rs │ │ ├── listen_pool.rs │ │ ├── listen_pool_state.rs │ │ ├── overwrite_channel.rs │ │ └── types.rs ├── common │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── access_control.rs │ │ ├── async_test_utils.rs │ │ ├── big_array.rs │ │ ├── caller_info.rs │ │ ├── canonical_serialize.rs │ │ ├── conn.rs │ │ ├── define_fixed_bytes.rs │ │ ├── dummy_connector.rs │ │ ├── dummy_listener.rs │ │ ├── futures_compat.rs │ │ ├── int_convert.rs │ │ ├── lib.rs │ │ ├── multi_consumer.rs │ │ ├── mutable_state.rs │ │ ├── never.rs │ │ ├── safe_arithmetic.rs │ │ ├── select_streams.rs │ │ ├── ser_utils │ │ ├── mod.rs │ │ ├── ser_b64.rs │ │ ├── ser_map_b64_any.rs │ │ ├── ser_map_str_any.rs │ │ ├── ser_map_str_str.rs │ │ ├── ser_option_b64.rs │ │ ├── ser_seq_b64.rs │ │ ├── ser_seq_str.rs │ │ ├── ser_string.rs │ │ ├── ser_vec_b64.rs │ │ └── tests.rs │ │ ├── state_service.rs │ │ ├── test_executor.rs │ │ └── transform_pool.rs ├── connection │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ ├── timeout.rs │ │ └── transforms.rs ├── crypto │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── dh.rs │ │ ├── error.rs │ │ ├── hash.rs │ │ ├── hash_lock.rs │ │ ├── identity.rs │ │ ├── lib.rs │ │ ├── nonce_window.rs │ │ ├── rand.rs │ │ ├── sym_encrypt.rs │ │ └── test_utils.rs ├── database │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── atomic_db.rs │ │ ├── database.rs │ │ ├── file_db.rs │ │ └── lib.rs ├── funder │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── ephemeral.rs │ │ ├── freeze_guard_legacy.rs │ │ ├── friend.rs │ │ ├── funder.rs │ │ ├── handler │ │ ├── canceler.rs │ │ ├── handle_control.rs │ │ ├── handle_friend.rs │ │ ├── handle_init.rs │ │ ├── handle_liveness.rs │ │ ├── handler.rs │ │ ├── mod.rs │ │ ├── prepare.rs │ │ ├── sender.rs │ │ ├── state_wrap.rs │ │ ├── tests │ │ │ ├── change_address.rs │ │ │ ├── mod.rs │ │ │ ├── pair_basic.rs │ │ │ ├── pair_inconsistency.rs │ │ │ └── utils.rs │ │ ├── types.rs │ │ └── utils.rs │ │ ├── lib.rs │ │ ├── liveness.rs │ │ ├── mutual_credit │ │ ├── incoming.rs │ │ ├── mod.rs │ │ ├── outgoing.rs │ │ ├── tests.rs │ │ └── types.rs │ │ ├── report.rs │ │ ├── state.rs │ │ ├── tests │ │ ├── funder_basic.rs │ │ ├── funder_error_command.rs │ │ ├── funder_forward_payment.rs │ │ ├── funder_inconsistency_basic.rs │ │ ├── funder_payment_failure.rs │ │ ├── mod.rs │ │ └── utils.rs │ │ ├── token_channel.rs │ │ └── types.rs ├── identity │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── client.rs │ │ ├── identity.rs │ │ ├── lib.rs │ │ └── messages.rs ├── index_client │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── client_session.rs │ │ ├── index_client.rs │ │ ├── lib.rs │ │ ├── seq_friends.rs │ │ ├── seq_map.rs │ │ ├── single_client.rs │ │ ├── spawn.rs │ │ └── tests.rs ├── index_server │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── backoff_connector.rs │ │ ├── graph │ │ ├── bfs.rs │ │ ├── capacity_graph.rs │ │ ├── graph_service.rs │ │ ├── mod.rs │ │ ├── simple_capacity_graph.rs │ │ ├── test_utils.rs │ │ └── utils.rs │ │ ├── lib.rs │ │ ├── server.rs │ │ ├── server_loop.rs │ │ └── verifier │ │ ├── dummy_verifier.rs │ │ ├── hash_clock.rs │ │ ├── mod.rs │ │ ├── ratchet.rs │ │ ├── simple_verifier.rs │ │ └── verifier.rs ├── keepalive │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── keepalive.rs │ │ └── lib.rs ├── lockfile │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ └── lockfile.rs ├── mutual_from │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── src │ │ └── lib.rs │ └── tests │ │ └── tests.rs ├── net │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ ├── tcp_connector.rs │ │ ├── tcp_listener.rs │ │ ├── tests.rs │ │ ├── types.rs │ │ └── utils.rs ├── node │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── lib.rs │ │ ├── node.rs │ │ └── types.rs ├── proto │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── build.rs │ └── src │ │ ├── app_server │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── consts.rs │ │ ├── crypto │ │ ├── mod.rs │ │ └── serialize.rs │ │ ├── file.rs │ │ ├── funder │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── index_client │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── index_server │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── keepalive │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── macros.rs │ │ ├── net │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── proto_ser.rs │ │ ├── relay │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── report │ │ ├── convert.rs │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── schema │ │ ├── app_server.capnp │ │ ├── common.capnp │ │ ├── dh.capnp │ │ ├── funder.capnp │ │ ├── index.capnp │ │ ├── keepalive.capnp │ │ ├── relay.capnp │ │ └── report.capnp │ │ ├── secure_channel │ │ ├── messages.rs │ │ └── mod.rs │ │ ├── ser_string.rs │ │ └── wrapper.rs ├── relay │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── client │ │ ├── client_connector.rs │ │ ├── client_listener.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ └── server │ │ ├── conn_limiter.rs │ │ ├── conn_processor.rs │ │ ├── mod.rs │ │ ├── net_server.rs │ │ ├── server.rs │ │ ├── server_loop.rs │ │ └── types.rs ├── route │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ └── multi_route.rs ├── secure_channel │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ ├── secure_channel.rs │ │ ├── state.rs │ │ └── types.rs ├── signature │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── canonical.rs │ │ ├── lib.rs │ │ ├── signature_buff.rs │ │ └── verify.rs ├── stcompact │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── bin │ │ ├── stcompact.rs │ │ └── stcompact_ser_gen.rs │ │ ├── compact_node │ │ ├── convert.rs │ │ ├── handle_node.rs │ │ ├── handle_user.rs │ │ ├── messages.rs │ │ ├── mod.rs │ │ ├── permission.rs │ │ ├── persist.rs │ │ ├── server.rs │ │ ├── server_init.rs │ │ ├── server_loop.rs │ │ ├── types.rs │ │ └── utils.rs │ │ ├── gen.rs │ │ ├── lib.rs │ │ ├── messages.rs │ │ ├── serialize.rs │ │ ├── server_loop.rs │ │ ├── stcompactlib.rs │ │ └── store │ │ ├── consts.rs │ │ ├── file_store.rs │ │ ├── mod.rs │ │ ├── store.rs │ │ └── tests.rs ├── stctrl │ ├── .gitignore │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── bin │ │ ├── stctrl.rs │ │ └── stverify.rs │ │ ├── buyer.rs │ │ ├── config.rs │ │ ├── file.rs │ │ ├── info.rs │ │ ├── lib.rs │ │ ├── seller.rs │ │ ├── stctrllib.rs │ │ ├── stverifylib.rs │ │ └── utils.rs ├── test │ ├── Cargo.toml │ ├── LICENSE-AGPL3 │ └── src │ │ ├── app_wrapper.rs │ │ ├── cli_tests │ │ ├── basic_cli.rs │ │ ├── mod.rs │ │ └── stctrl_setup.rs │ │ ├── compact_node_wrapper.rs │ │ ├── compact_report_service.rs │ │ ├── compact_server_wrapper.rs │ │ ├── lib.rs │ │ ├── node_report_service.rs │ │ ├── sim_network.rs │ │ ├── tests │ │ ├── compact_node_payment.rs │ │ ├── compact_server_remote_node.rs │ │ ├── handle_error_command.rs │ │ ├── mod.rs │ │ ├── nodes_chain.rs │ │ ├── relay_migration.rs │ │ ├── resolve_inconsistency.rs │ │ ├── serialize.rs │ │ └── two_nodes_payment.rs │ │ └── utils.rs ├── timer │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ │ ├── lib.rs │ │ ├── timer.rs │ │ └── utils.rs └── version │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ └── src │ ├── lib.rs │ └── version_prefix.rs ├── rust-toolchain └── rustfmt.toml /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | *_capnp.rs 3 | target/ 4 | 5 | ## Sphinx documentation build 6 | doc/docs/build 7 | 8 | ## IntelliJ IDEA 9 | *.iml 10 | *.ipr 11 | *.iws 12 | dataSources/ 13 | .idea/ 14 | 15 | .vscode/ 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [workspace] 3 | 4 | members = [ 5 | "components/funder", 6 | "components/channeler", 7 | "components/common", 8 | "components/proto", 9 | "components/crypto", 10 | "components/identity", 11 | "components/timer", 12 | "components/relay", 13 | "components/secure_channel", 14 | "components/keepalive", 15 | "components/app_server", 16 | "components/index_client", 17 | "components/index_server", 18 | "components/database", 19 | "components/node", 20 | "components/net", 21 | "components/version", 22 | "components/bin", 23 | "components/stctrl", 24 | "components/stcompact", 25 | "components/app", 26 | "components/test", 27 | "components/mutual_from", 28 | "components/capnp_conv", 29 | "components/capnp_conv/capnp_conv_derive", 30 | "components/signature", 31 | "components/route", 32 | "components/lockfile", 33 | "components/connection", 34 | "components/app_client", 35 | ] 36 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Offset 2 | 3 | [![Build Status](https://travis-ci.com/freedomlayer/offset.svg?branch=master)](https://travis-ci.com/freedomlayer/offset) 4 | [![codecov](https://codecov.io/gh/freedomlayer/offset/branch/master/graph/badge.svg)](https://codecov.io/gh/freedomlayer/offset) 5 | 6 | **Offset** is a credit card powered by trust between people. 7 | 8 | Warning: Offset is still a work in progress, and is not yet ready for use in 9 | production. 10 | 11 | ## Info 12 | 13 | - [Documentation](https://docs.offsetcredit.org) 14 | - [Blog](https://www.freedomlayer.org/offset/) 15 | 16 | ## License 17 | 18 | - The core crates of Offset are licensed under the AGPL-3.0 license. 19 | - The crates used as interface for building Offset apps are licensed under the MIT 20 | or Apache 2.0, at your option. 21 | 22 | Each crate license info can be found in the corresponding crate directory and in 23 | the crate's `Cargo.toml`. 24 | 25 | 26 | ## Download 27 | 28 | [Releases page](https://github.com/freedomlayer/offset/releases) 29 | 30 | ## Dockerized Offset servers 31 | 32 | [offset_docker](https://github.com/freedomlayer/offset_docker) 33 | 34 | 35 | ## Building Offset 36 | 37 | ### Install dependencies 38 | 39 | - Install [Rust](https://www.rust-lang.org/tools/install). 40 | - Install [capnproto](https://capnproto.org): 41 | - On Ubuntu, run: `sudo apt install capnproto` 42 | - On macOS, run: `brew install canpnp` 43 | 44 | ### Rust toolchain version 45 | 46 | Offset builds on stable! 47 | The toolchain is pinned using the `rust-toolchain` file. 48 | 49 | For testing, run: 50 | 51 | ``` 52 | cargo test 53 | ``` 54 | 55 | To build, run: 56 | 57 | ``` 58 | cargo build --release 59 | ``` 60 | 61 | 62 | ### Development tools 63 | 64 | If you want to hack on Offset, run the following commands to install clippy, 65 | rustfmt and rls: 66 | 67 | ```bash 68 | rustup update 69 | rustup component add clippy 70 | rustup component add rustfmt 71 | rustup component add rls rust-analysis rust-src 72 | ``` 73 | -------------------------------------------------------------------------------- /ci/android_before_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ANDROID_HOME="${HOME}/android-sdk" 4 | export ANDROID_NDK_HOME="${ANDROID_HOME}/ndk-bundle" 5 | export PATH=$PATH:"${ANDROID_HOME}/tools/bin:${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin" 6 | 7 | # Make sure that directories exist: 8 | mkdir -p $ANDROID_HOME 9 | mkdir -p ${HOME}/android-sdk-dl 10 | -------------------------------------------------------------------------------- /ci/android_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 4 | set -eux -o pipefail 5 | 6 | # Android versions: 7 | # See: https://developer.android.com/studio/index.html 8 | # (commandline-tools) 9 | export ANDROID_SDK_VERSION=6200805 10 | export ANDROID_BUILD_TOOLS_VERSION="26.0.2" 11 | export ANDROID_VERSION=26 12 | 13 | # Download and unzip the Android SDK tools (if not already there thanks to the cache mechanism) 14 | # Latest version available here: https://developer.android.com/studio/#command-tools 15 | if test ! -e $HOME/android-sdk-dl/commandlinetools.zip ; then 16 | curl "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip" > "$HOME/android-sdk-dl/commandlinetools.zip" ; 17 | fi 18 | unzip -qq -n $HOME/android-sdk-dl/commandlinetools.zip -d $ANDROID_HOME; 19 | 20 | # Create repositories.cfg ahead of time, see: 21 | # https://stackoverflow.com/questions/43433542/stuck-at-android-repositories-cfg-could-not-be-loaded 22 | mkdir -p $HOME/.android && touch $HOME/.android/repositories.cfg 23 | 24 | # Accept the license: 25 | # See https://stackoverflow.com/a/57797492 for (yes || true) trick explanation: 26 | (yes || true) | $ANDROID_HOME/tools/bin/sdkmanager --sdk_root=${ANDROID_HOME} --licenses > /dev/null 27 | 28 | # Install or update Android SDK components (will not do anything if already up to date thanks to the cache mechanism) 29 | $ANDROID_HOME/tools/bin/sdkmanager --sdk_root=${ANDROID_HOME} \ 30 | "platforms;android-${ANDROID_VERSION}" "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 'ndk-bundle' > /dev/null 31 | # Add rust targets: 32 | rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android 33 | 34 | # Create $HOME/.cargo/config (from template): 35 | cat ci/cargo_config_template | envsubst > $HOME/.cargo/config 36 | 37 | # Add symlinks for clang compilers: 38 | cd "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin" 39 | ln -sf "./aarch64-linux-android${ANDROID_VERSION}-clang" aarch64-linux-android-clang 40 | ln -sf "./armv7a-linux-androideabi${ANDROID_VERSION}-clang" arm-linux-androideabi-clang 41 | ln -sf "./i686-linux-android${ANDROID_VERSION}-clang" i686-linux-android-clang 42 | cd - 43 | 44 | # Make sure rust stable is installed 45 | rustup install stable 46 | 47 | # Install capnp: 48 | ci/pre/capnp.sh 49 | -------------------------------------------------------------------------------- /ci/before_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # package the build artifacts 4 | # Based on https://github.com/BurntSushi/ripgrep/blob/master/.travis.yml 5 | 6 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 7 | set -eux -o pipefail 8 | 9 | # Generate artifacts for release 10 | mk_artifacts() { 11 | cargo build --target "$TARGET" --release 12 | } 13 | 14 | mk_tarball() { 15 | # Create a temporary dir that contains our staging area. 16 | # $tmpdir/$name is what eventually ends up as the deployed archive. 17 | local tmpdir="$(mktemp -d)" 18 | local name="${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}" 19 | local staging="$tmpdir/$name" 20 | mkdir -p "$staging"/bin 21 | # The deployment directory is where the final archive will reside. 22 | # This path is known by the .travis.yml configuration. 23 | local out_dir="$HOME/deployment" 24 | mkdir -p "$out_dir" 25 | # Find the correct (most recent) Cargo "out" directory. The out directory 26 | # contains shell completion files and the man page. 27 | local cargo_out_dir="$(cargo_out_dir "target/$TARGET")" 28 | 29 | # TODO: Strip binaries? 30 | 31 | # Copy the binaries: 32 | cp "target/$TARGET/release/stmgr" "$staging/bin/stmgr" 33 | cp "target/$TARGET/release/strelay" "$staging/bin/strelay" 34 | cp "target/$TARGET/release/stindex" "$staging/bin/stindex" 35 | cp "target/$TARGET/release/stnode" "$staging/bin/stnode" 36 | cp "target/$TARGET/release/stctrl" "$staging/bin/stctrl" 37 | cp "target/$TARGET/release/stcompact" "$staging/bin/stcompact" 38 | 39 | # Copy README file: 40 | cp README.md "$staging/" 41 | 42 | # Copy all licenses: 43 | cp LICENSE-* "$staging/" 44 | 45 | # TODO: Copy man pages? 46 | # TODO: Copy shell completion files. 47 | 48 | (cd "$tmpdir" && tar czf "$out_dir/$name.tar.gz" "$name") 49 | rm -rf "$tmpdir" 50 | } 51 | 52 | main() { 53 | mk_artifacts 54 | mk_tarball 55 | } 56 | 57 | main 58 | -------------------------------------------------------------------------------- /ci/cargo_config_template: -------------------------------------------------------------------------------- 1 | [target.aarch64-linux-android] 2 | ar = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar" 3 | linker = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-clang" 4 | 5 | [target.armv7-linux-androideabi] 6 | ar = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar" 7 | linker = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-clang" 8 | 9 | [target.i686-linux-android] 10 | ar = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android-ar" 11 | linker = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android-clang" 12 | -------------------------------------------------------------------------------- /ci/post/cargo-sweep.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 4 | set -eux -o pipefail 5 | 6 | CARGO_SWEEP_VERSION=0.4.1 7 | 8 | # FOUND_VERSION can be empty, don't set -o pipefail 9 | FOUND_VERSION=$(grep cargo-sweep ~/.cargo/.crates.toml | cut -d' ' -f2) 10 | 11 | # Update cargo-sweep if necessary 12 | if [ "$FOUND_VERSION" != "$CARGO_SWEEP_VERSION" ]; then 13 | cargo install cargo-sweep --vers $CARGO_SWEEP_VERSION --force 14 | fi 15 | 16 | RUST_VERSION=$(head -n 1 rust-toolchain) 17 | echo "Rust toolchain version: $RUST_VERSION" 18 | 19 | # cargo-sweep produces a lot of output 20 | cargo sweep --toolchains "$RUST_VERSION" > /dev/null 21 | -------------------------------------------------------------------------------- /ci/post/kcov/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # CODECOV_TOKEN Must be set at this point. 4 | 5 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 6 | set -eux -o pipefail 7 | 8 | exes=$(find target/${TARGET}/debug/deps/ -maxdepth 1 -executable -type f) 9 | for exe in ${exes}; do 10 | ${HOME}/install/kcov-${TARGET}/bin/kcov \ 11 | --verify \ 12 | --exclude-path=/usr/include \ 13 | --include-pattern="components" \ 14 | target/kcov \ 15 | ${exe} 16 | done 17 | 18 | # DEBUG: Show contents of directory, to see if a report was created: 19 | pwd 20 | ls -la 21 | 22 | # TODO: Change to something safer: 23 | # Automatically reads from CODECOV_TOKEN environment variable: 24 | bash <(curl -s https://codecov.io/bash) 25 | -------------------------------------------------------------------------------- /ci/post/kcov/try-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 4 | set -eux -o pipefail 5 | 6 | export CC=gcc-6 7 | export CXX=g++-6 8 | 9 | KCOV_INSTALL_PREFIX="${HOME}/install/kcov-${TARGET}" 10 | # KCOV_VERSION=${KCOV_VERSION:-34} 11 | KCOV_VERSION="38" 12 | 13 | sudo apt-get install -y libdw-dev 14 | 15 | if [[ -f "$KCOV_INSTALL_PREFIX/bin/kcov" ]]; then 16 | KCOV_INSTALLED_VERSION=$(${KCOV_INSTALL_PREFIX}/bin/kcov --version) 17 | KCOV_INSTALLED_VERSION=${KCOV_INSTALLED_VERSION#*\ } 18 | 19 | if (( $KCOV_INSTALLED_VERSION >= $KCOV_VERSION )); then 20 | echo "Using cached kcov, version: $KCOV_INSTALLED_VERSION" 21 | exit 0 22 | else 23 | rm -rf "$KCOV_INSTALL_PREFIX/bin/kcov" 24 | fi 25 | fi 26 | 27 | # https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md 28 | sudo apt-get install -y cmake binutils-dev libcurl4-openssl-dev \ 29 | zlib1g-dev libiberty-dev 30 | 31 | curl -L https://github.com/SimonKagstrom/kcov/archive/v${KCOV_VERSION}.tar.gz | tar -zxf - 32 | 33 | pushd kcov-${KCOV_VERSION} 34 | 35 | mkdir build 36 | 37 | pushd build 38 | 39 | TARGET=${TARGET} cmake -DCMAKE_INSTALL_PREFIX:PATH="${KCOV_INSTALL_PREFIX}" .. 40 | 41 | make -j2 42 | make install 43 | 44 | ${KCOV_INSTALL_PREFIX}/bin/kcov --version 45 | 46 | popd 47 | popd 48 | -------------------------------------------------------------------------------- /ci/pre/capnp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 4 | set -eux -o pipefail 5 | 6 | CAPNP_INSTALL_PREFIX="${HOME}/install/capnp" 7 | 8 | CAPNP_VERSION="0.7.0" 9 | 10 | export CC="gcc-6" 11 | export CXX="g++-6" 12 | export CPPFLAGS="-std=c++14" 13 | export CXXFLAGS="-std=c++14" 14 | 15 | # Build only if we don't have a cached installation: 16 | if [ ! -d "$CAPNP_INSTALL_PREFIX/lib" ]; then 17 | curl -L https://capnproto.org/capnproto-c++-${CAPNP_VERSION}.tar.gz | tar -zxf - 18 | pushd capnproto-c++-${CAPNP_VERSION} 19 | ./configure --prefix=${CAPNP_INSTALL_PREFIX} 20 | make check -j2 21 | sudo make install 22 | popd 23 | fi 24 | 25 | sudo ln -s ${CAPNP_INSTALL_PREFIX}/bin/capnp /usr/local/bin/capnp 26 | -------------------------------------------------------------------------------- /ci/pre/cargo-config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ 4 | set -eux -o pipefail 5 | 6 | # if [[ -f ".cargo/config" ]]; then 7 | # rm .cargo/config 8 | # elif [[ ! -d ".cargo" ]]; then 9 | # mkdir .cargo 10 | # fi 11 | 12 | # echo "[target.$TARGET]" > .cargo/config 13 | # echo "linker= \"$CC\"" >> .cargo/config 14 | 15 | rustup update 16 | rustup component add clippy rustfmt 17 | 18 | # cat .cargo/config 19 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: off 2 | # See https://docs.codecov.io/docs/commit-status for more info: 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | # We do not allow the coverage to go down by 5 percent: 8 | threshold: 5 9 | base: auto 10 | patch: off 11 | -------------------------------------------------------------------------------- /components/app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-app" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0" , package = "offset-signature" } 16 | net = { path = "../net", version = "0.1.0" , package = "offset-net" } 17 | app_client = { path = "../app_client", version = "0.1.0" , package = "offset-app-client" } 18 | connection = { path = "../connection", version = "0.1.0" , package = "offset-connection" } 19 | 20 | log = "0.4" 21 | simple_logger = "1.0.1" 22 | 23 | futures = "0.3.1" 24 | derive_more = "0.14.0" 25 | 26 | [dev-dependencies] 27 | 28 | futures = {version = "0.3.1", features = ["thread-pool"]} 29 | -------------------------------------------------------------------------------- /components/app/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/app/src/app_conn/buyer.rs: -------------------------------------------------------------------------------- 1 | use proto::crypto::{InvoiceId, PaymentId, PublicKey, Uid}; 2 | 3 | use proto::app_server::messages::AppRequest; 4 | use proto::funder::messages::{ 5 | AckClosePayment, CreatePayment, CreateTransaction, Currency, FriendsRoute, 6 | }; 7 | 8 | pub fn create_payment( 9 | payment_id: PaymentId, 10 | invoice_id: InvoiceId, 11 | currency: Currency, 12 | total_dest_payment: u128, 13 | dest_public_key: PublicKey, 14 | ) -> AppRequest { 15 | let create_payment = CreatePayment { 16 | payment_id, 17 | invoice_id, 18 | currency, 19 | total_dest_payment, 20 | dest_public_key, 21 | }; 22 | 23 | AppRequest::CreatePayment(create_payment) 24 | } 25 | 26 | pub fn create_transaction( 27 | payment_id: PaymentId, 28 | request_id: Uid, 29 | route: FriendsRoute, 30 | dest_payment: u128, 31 | fees: u128, 32 | ) -> AppRequest { 33 | let create_transaction = CreateTransaction { 34 | payment_id, 35 | request_id, 36 | route, 37 | dest_payment, 38 | fees, 39 | }; 40 | 41 | AppRequest::CreateTransaction(create_transaction) 42 | } 43 | 44 | pub fn request_close_payment(payment_id: PaymentId) -> AppRequest { 45 | AppRequest::RequestClosePayment(payment_id) 46 | } 47 | 48 | pub fn ack_close_payment(payment_id: PaymentId, ack_uid: Uid) -> AppRequest { 49 | let ack_close_payment = AckClosePayment { 50 | payment_id, 51 | ack_uid, 52 | }; 53 | 54 | AppRequest::AckClosePayment(ack_close_payment) 55 | } 56 | -------------------------------------------------------------------------------- /components/app/src/app_conn/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod buyer; 2 | pub mod config; 3 | pub mod routes; 4 | pub mod seller; 5 | -------------------------------------------------------------------------------- /components/app/src/app_conn/routes.rs: -------------------------------------------------------------------------------- 1 | use proto::crypto::{PublicKey, Uid}; 2 | 3 | use proto::app_server::messages::AppRequest; 4 | use proto::funder::messages::Currency; 5 | use proto::index_server::messages::{Edge, RequestRoutes}; 6 | 7 | pub fn request_routes( 8 | request_routes_id: Uid, 9 | currency: Currency, 10 | capacity: u128, 11 | source: PublicKey, 12 | destination: PublicKey, 13 | opt_exclude: Option<(PublicKey, PublicKey)>, 14 | ) -> AppRequest { 15 | let opt_exclude = opt_exclude.map(|(from_public_key, to_public_key)| Edge { 16 | from_public_key, 17 | to_public_key, 18 | }); 19 | 20 | let request_routes = RequestRoutes { 21 | request_id: request_routes_id, 22 | currency, 23 | capacity, 24 | source, 25 | destination, 26 | opt_exclude, 27 | }; 28 | 29 | AppRequest::RequestRoutes(request_routes) 30 | } 31 | -------------------------------------------------------------------------------- /components/app/src/app_conn/seller.rs: -------------------------------------------------------------------------------- 1 | use proto::crypto::InvoiceId; 2 | 3 | use proto::app_server::messages::AppRequest; 4 | use proto::funder::messages::{AddInvoice, Commit, Currency}; 5 | 6 | pub fn add_invoice( 7 | invoice_id: InvoiceId, 8 | currency: Currency, 9 | total_dest_payment: u128, 10 | ) -> AppRequest { 11 | let add_invoice = AddInvoice { 12 | invoice_id, 13 | currency, 14 | total_dest_payment, 15 | }; 16 | AppRequest::AddInvoice(add_invoice) 17 | } 18 | 19 | pub fn cancel_invoice(invoice_id: InvoiceId) -> AppRequest { 20 | AppRequest::CancelInvoice(invoice_id) 21 | } 22 | 23 | pub fn commit_invoice(commit: Commit) -> AppRequest { 24 | AppRequest::CommitInvoice(commit) 25 | } 26 | -------------------------------------------------------------------------------- /components/app/src/connect.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use futures::task::Spawn; 4 | 5 | use common::conn::ConnPair; 6 | use common::int_convert::usize_to_u64; 7 | 8 | use proto::app_server::messages::{AppPermissions, AppServerToApp, AppToAppServer, NodeReport}; 9 | use proto::consts::MAX_FRAME_LENGTH; 10 | use proto::consts::TICK_MS; 11 | use proto::crypto::PublicKey; 12 | use proto::net::messages::NetAddress; 13 | 14 | use crypto::rand::system_random; 15 | 16 | use identity::IdentityClient; 17 | use net::TcpConnector; 18 | use timer::create_timer; 19 | 20 | use app_client::app_connect_to_node; 21 | use connection::create_secure_connector; 22 | 23 | /// A connection of an App to a Node 24 | pub type ConnPairApp = ConnPair; 25 | 26 | pub type AppConnTuple = (AppPermissions, NodeReport, ConnPairApp); 27 | 28 | #[derive(Debug)] 29 | pub struct ConnectError; 30 | 31 | /// Connect to a remote offset-node. 32 | pub async fn connect( 33 | node_public_key: PublicKey, 34 | node_net_address: NetAddress, 35 | app_identity_client: IdentityClient, 36 | spawner: S, 37 | ) -> Result 38 | where 39 | S: Spawn + Clone + Send + 'static, 40 | { 41 | // Obtain secure cryptographic random: 42 | let rng = system_random(); 43 | 44 | // Get a timer client: 45 | let dur = Duration::from_millis(usize_to_u64(TICK_MS).unwrap()); 46 | let timer_client = create_timer(dur, spawner.clone()).map_err(|_| ConnectError)?; 47 | 48 | // A tcp connector, Used to connect to remote servers: 49 | let tcp_connector = TcpConnector::new(MAX_FRAME_LENGTH, spawner.clone()); 50 | 51 | let secure_connector = create_secure_connector( 52 | tcp_connector, 53 | timer_client, 54 | app_identity_client, 55 | rng, 56 | spawner.clone(), 57 | ); 58 | 59 | app_connect_to_node(secure_connector, node_public_key, node_net_address, spawner) 60 | .await 61 | .map_err(|_| ConnectError) 62 | } 63 | -------------------------------------------------------------------------------- /components/app/src/gen.rs: -------------------------------------------------------------------------------- 1 | use crypto::rand::{system_random, RandGen}; 2 | 3 | use proto::crypto::{InvoiceId, PaymentId, Uid}; 4 | 5 | // TODO: Use Gen trait here instead? 6 | 7 | /// Generate a random uid 8 | pub fn gen_uid() -> Uid { 9 | // Obtain secure cryptographic random: 10 | let mut rng = system_random(); 11 | 12 | Uid::rand_gen(&mut rng) 13 | } 14 | 15 | /// Generate a random InvoiceId: 16 | pub fn gen_invoice_id() -> InvoiceId { 17 | // Obtain secure cryptographic random: 18 | let mut rng = system_random(); 19 | 20 | InvoiceId::rand_gen(&mut rng) 21 | } 22 | 23 | /// Generate a random PaymentId: 24 | pub fn gen_payment_id() -> PaymentId { 25 | // Obtain secure cryptographic random: 26 | let mut rng = system_random(); 27 | 28 | PaymentId::rand_gen(&mut rng) 29 | } 30 | -------------------------------------------------------------------------------- /components/app/src/identity.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::Path; 3 | 4 | use futures::task::{Spawn, SpawnExt}; 5 | 6 | use derive_more::From; 7 | 8 | use identity::{create_identity, IdentityClient}; 9 | 10 | use crypto::identity::SoftwareEd25519Identity; 11 | 12 | use proto::file::IdentityFile; 13 | use proto::ser_string::{deserialize_from_string, StringSerdeError}; 14 | 15 | #[derive(Debug, From)] 16 | pub enum IdentityFromFileError { 17 | LoadFileError, 18 | LoadIdentityError, 19 | CreateIdentityError, 20 | StringSerdeError(StringSerdeError), 21 | IoError(std::io::Error), 22 | } 23 | 24 | pub fn identity_from_file( 25 | idfile_path: &Path, 26 | spawner: S, 27 | ) -> Result 28 | where 29 | S: Spawn, 30 | { 31 | // Parse identity file: 32 | let identity_file: IdentityFile = deserialize_from_string(&fs::read_to_string(&idfile_path)?)?; 33 | let identity = SoftwareEd25519Identity::from_private_key(&identity_file.private_key) 34 | .map_err(|_| IdentityFromFileError::LoadIdentityError)?; 35 | 36 | // Spawn identity service: 37 | let (sender, identity_loop) = create_identity(identity); 38 | spawner 39 | .spawn(identity_loop) 40 | .map_err(|_| IdentityFromFileError::CreateIdentityError)?; 41 | Ok(IdentityClient::new(sender)) 42 | } 43 | -------------------------------------------------------------------------------- /components/app/src/types.rs: -------------------------------------------------------------------------------- 1 | use common::mutable_state::MutableState; 2 | use proto::app_server::messages::{NodeReport, NodeReportMutateError, ReportMutations}; 3 | 4 | /// Given a type which is a MutableState, we convert it to a type 5 | /// that is a MutableState for batches of mutations of the same mutation type. 6 | #[derive(Debug, Clone)] 7 | pub struct BatchNodeReport(pub NodeReport); 8 | 9 | impl MutableState for BatchNodeReport { 10 | type Mutation = ReportMutations; 11 | type MutateError = NodeReportMutateError; 12 | 13 | fn mutate(&mut self, node_report_mutations: &Self::Mutation) -> Result<(), Self::MutateError> { 14 | for mutation in &node_report_mutations.mutations { 15 | self.0.mutate(mutation)?; 16 | } 17 | Ok(()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/app_client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-app-client" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | proto = { path = "../proto", version = "0.1.0", package = "offset-proto" } 12 | 13 | futures = "0.3.1" 14 | 15 | [dev-dependencies] 16 | 17 | futures = {version = "0.3.1", features = ["thread-pool"]} 18 | -------------------------------------------------------------------------------- /components/app_client/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/app_client/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | mod connect; 12 | 13 | pub use self::connect::{app_connect_to_node, AppConnectError}; 14 | -------------------------------------------------------------------------------- /components/app_server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-app-server" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | 16 | log = "0.4" 17 | futures = "0.3.1" 18 | im = "14.1.0" 19 | 20 | [dev-dependencies] 21 | 22 | futures = {version = "0.3.1", features = ["thread-pool"]} 23 | -------------------------------------------------------------------------------- /components/app_server/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate common; 16 | 17 | mod server; 18 | 19 | #[cfg(test)] 20 | mod tests; 21 | 22 | pub use self::server::{app_server_loop, AppServerError, ConnPairServer, IncomingAppConnection}; 23 | -------------------------------------------------------------------------------- /components/app_server/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod all_apps_closed; 2 | mod funder_command; 3 | mod index_client_command; 4 | mod request_routes; 5 | mod request_send_funds; 6 | mod two_apps; 7 | mod utils; 8 | -------------------------------------------------------------------------------- /components/bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-bin" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [lib] 9 | name = "bin" 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "strelay" 14 | path = "src/bin/strelay.rs" 15 | 16 | [[bin]] 17 | name = "stindex" 18 | path = "src/bin/stindex.rs" 19 | 20 | [[bin]] 21 | name = "stnode" 22 | path = "src/bin/stnode.rs" 23 | 24 | [[bin]] 25 | name = "stmgr" 26 | path = "src/bin/stmgr.rs" 27 | 28 | [dependencies] 29 | 30 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 31 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 32 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 33 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 34 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 35 | relay = { path = "../relay", version = "0.1.0" , package = "offset-relay" } 36 | net = { path = "../net", version = "0.1.0" , package = "offset-net" } 37 | index_server = { path = "../index_server", version = "0.1.0" , package = "offset-index-server" } 38 | node = { path = "../node", version = "0.1.0" , package = "offset-node" } 39 | database = { path = "../database", version = "0.1.0" , package = "offset-database" } 40 | connection = { path = "../connection", version = "0.1.0" , package = "offset-connection" } 41 | 42 | serde = {version = "1.0.104", features = ["derive"]} 43 | base64 = "0.10.1" 44 | 45 | log = "0.4" 46 | env_logger = "0.6.0" 47 | futures = {version = "0.3.1", features = ["thread-pool"]} 48 | async-std = "1.6.2" 49 | 50 | structopt = "0.2.15" 51 | 52 | derive_more = "0.99.2" 53 | 54 | [dev-dependencies] 55 | 56 | tempfile = "3.1.0" 57 | -------------------------------------------------------------------------------- /components/bin/src/bin/stindex.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use structopt::StructOpt; 14 | 15 | use bin::stindex::{stindex, IndexServerBinError, StIndexCmd}; 16 | 17 | fn run() -> Result<(), IndexServerBinError> { 18 | env_logger::init(); 19 | 20 | let st_index_cmd = StIndexCmd::from_args(); 21 | stindex(st_index_cmd) 22 | } 23 | 24 | fn main() { 25 | if let Err(e) = run() { 26 | error!("run() error: {:?}", e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/bin/src/bin/stmgr.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use structopt::StructOpt; 14 | 15 | use bin::stmgrlib::{stmgr, StMgrCmd, StmError}; 16 | 17 | fn run() -> Result<(), StmError> { 18 | env_logger::init(); 19 | 20 | let st_mgr_cmd = StMgrCmd::from_args(); 21 | stmgr(st_mgr_cmd) 22 | } 23 | 24 | fn main() { 25 | if let Err(e) = run() { 26 | error!("run() error: {:?}", e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/bin/src/bin/stnode.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use structopt::StructOpt; 14 | 15 | use bin::stnode::{stnode, NodeBinError, StNodeCmd}; 16 | 17 | fn run() -> Result<(), NodeBinError> { 18 | env_logger::init(); 19 | let st_node_cmd = StNodeCmd::from_args(); 20 | stnode(st_node_cmd) 21 | } 22 | 23 | fn main() { 24 | if let Err(e) = run() { 25 | error!("run() error: {:?}", e); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /components/bin/src/bin/strelay.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use structopt::StructOpt; 14 | 15 | use bin::strelay::{strelay, RelayServerBinError, StRelayCmd}; 16 | 17 | fn run() -> Result<(), RelayServerBinError> { 18 | env_logger::init(); 19 | let st_relay_cmd = StRelayCmd::from_args(); 20 | strelay(st_relay_cmd) 21 | } 22 | 23 | fn main() { 24 | if let Err(e) = run() { 25 | error!("run() error: {:?}", e); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /components/bin/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | pub mod stindex; 14 | pub mod stmgrlib; 15 | pub mod stnode; 16 | pub mod strelay; 17 | -------------------------------------------------------------------------------- /components/bin/src/stindex/mod.rs: -------------------------------------------------------------------------------- 1 | mod net_index; 2 | mod stindexlib; 3 | 4 | pub use self::stindexlib::{stindex, IndexServerBinError, StIndexCmd}; 5 | pub use net_index::net_index_server; 6 | -------------------------------------------------------------------------------- /components/bin/src/stnode/file_trusted_apps.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use futures::StreamExt; 4 | 5 | use async_std::fs; 6 | use async_std::path::{Path, PathBuf}; 7 | 8 | use derive_more::From; 9 | 10 | use common::conn::BoxFuture; 11 | 12 | use proto::app_server::messages::AppPermissions; 13 | use proto::crypto::PublicKey; 14 | use proto::file::TrustedAppFile; 15 | use proto::ser_string::{deserialize_from_string, StringSerdeError}; 16 | 17 | use crate::stnode::net_node::TrustedApps; 18 | 19 | #[derive(Debug, From)] 20 | enum FileTrustedAppsError { 21 | AsyncStdIoError(async_std::io::Error), 22 | StringSerdeError(StringSerdeError), 23 | } 24 | 25 | /// Load all trusted applications files from a given directory. 26 | async fn load_trusted_apps( 27 | dir_path: &Path, 28 | ) -> Result, FileTrustedAppsError> { 29 | let mut res_trusted = HashMap::new(); 30 | let mut dir = fs::read_dir(dir_path).await?; 31 | while let Some(entry) = dir.next().await { 32 | let entry = entry?; 33 | let path = entry.path(); 34 | if path.is_dir().await { 35 | continue; 36 | } 37 | 38 | let trusted_app_file: TrustedAppFile = 39 | deserialize_from_string(&fs::read_to_string(&path).await?)?; 40 | res_trusted.insert(trusted_app_file.public_key, trusted_app_file.permissions); 41 | } 42 | Ok(res_trusted) 43 | } 44 | 45 | /// Trusted apps checker that is stored as files in a directory. 46 | /// Directory structure: 47 | /// 48 | /// - root_dir 49 | /// - trusted_app_file1 50 | /// - trusted_app_file2 51 | /// - trusted_app_file3 52 | /// - ... 53 | /// 54 | /// Where each trusted_app_file corresponds to the permissions of one app. 55 | #[derive(Debug, Clone)] 56 | pub struct FileTrustedApps { 57 | trusted_apps_path: PathBuf, 58 | } 59 | 60 | impl FileTrustedApps { 61 | pub fn new(trusted_apps_path: PathBuf) -> Self { 62 | Self { trusted_apps_path } 63 | } 64 | } 65 | 66 | impl TrustedApps for FileTrustedApps { 67 | /// Get the permissions of an app. Returns None if the app is not trusted at all. 68 | fn app_permissions<'a>( 69 | &'a mut self, 70 | app_public_key: &'a PublicKey, 71 | ) -> BoxFuture<'a, Option> { 72 | Box::pin(async move { 73 | let trusted_map = match load_trusted_apps(&self.trusted_apps_path).await { 74 | Ok(trusted_map) => trusted_map, 75 | Err(e) => { 76 | error!("load_trusted_apps() failed: {:?}", e); 77 | return None; 78 | } 79 | }; 80 | trusted_map.get(app_public_key).cloned() 81 | }) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /components/bin/src/stnode/mod.rs: -------------------------------------------------------------------------------- 1 | mod file_trusted_apps; 2 | mod net_node; 3 | mod stnodelib; 4 | 5 | pub use self::net_node::{net_node, NetNodeError, TrustedApps}; 6 | pub use self::stnodelib::{stnode, NodeBinError, StNodeCmd}; 7 | -------------------------------------------------------------------------------- /components/bin/src/strelay/mod.rs: -------------------------------------------------------------------------------- 1 | mod net_relay; 2 | mod strelaylib; 3 | 4 | pub use self::net_relay::net_relay_server; 5 | pub use self::strelaylib::{strelay, RelayServerBinError, StRelayCmd}; 6 | -------------------------------------------------------------------------------- /components/capnp_conv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-capnp-conv" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | log = "0.4" 11 | pretty_env_logger = "0.2" 12 | 13 | offset-capnp-conv-derive = { path = "capnp_conv_derive", version = "0.1.0" } 14 | 15 | capnp = "0.10.0" 16 | derive_more = "0.15.0" 17 | 18 | [build-dependencies] 19 | capnpc = "0.10.0" 20 | 21 | [dev-dependencies] 22 | 23 | byteorder = {version = "1.3.2", features = ["i128"]} 24 | 25 | -------------------------------------------------------------------------------- /components/capnp_conv/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/capnp_conv/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | capnpc::CompilerCommand::new() 3 | .src_prefix("tests/") 4 | .file("tests/capnp/test.capnp") 5 | .run() 6 | .unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /components/capnp_conv/capnp_conv_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-capnp-conv-derive" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | 13 | quote = "0.6.12" 14 | syn = "0.15.38" 15 | proc-macro2 = "0.4" 16 | heck = "0.3.1" 17 | 18 | -------------------------------------------------------------------------------- /components/capnp_conv/capnp_conv_derive/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/capnp_conv/tests/capnp/test.capnp: -------------------------------------------------------------------------------- 1 | @0xc90daeac68e62b2a; 2 | 3 | struct TestStructInner { 4 | innerU8 @0: UInt8; 5 | } 6 | 7 | struct TestUnion { 8 | union { 9 | variantOne @0: UInt64; 10 | variantTwo @1: TestStructInner; 11 | variantThree @2: Void; 12 | variantFour @3: Text; 13 | } 14 | } 15 | 16 | struct ListUnion { 17 | union { 18 | empty @0: Void; 19 | withList @1: List(TestStructInner); 20 | withData @2: Data; 21 | testUnion @3: TestUnion; 22 | inlineInnerUnion: union { 23 | ab @4: UInt32; 24 | cd @5: UInt64; 25 | } 26 | } 27 | } 28 | 29 | struct TestStruct { 30 | myBool @0: Bool; 31 | myInt8 @1: Int8; 32 | myInt16 @2: Int16; 33 | myInt32 @3: Int32; 34 | myInt64 @4: Int64; 35 | myUint8 @5: UInt8; 36 | myUint16 @6: UInt16; 37 | myUint32 @7: UInt32; 38 | myUint64 @8: UInt64; 39 | # my_float32: f32, 40 | # my_float64: f64, 41 | myText @9: Text; 42 | myData @10: Data; 43 | structInner @11: TestStructInner; 44 | myPrimitiveList @12: List(UInt16); 45 | myList @13: List(TestStructInner); 46 | inlineUnion: union { 47 | firstVariant @14: UInt64; 48 | secondVariant @15: TestStructInner; 49 | thirdVariant @16: Void; 50 | } 51 | externalUnion @17: TestUnion; 52 | listUnion @18: ListUnion; 53 | } 54 | 55 | struct FloatStruct { 56 | myFloat32 @0: Float32; 57 | myFloat64 @1: Float64; 58 | } 59 | 60 | struct GenericStruct { 61 | a @0: UInt32; 62 | b @1: UInt64; 63 | c @2: UInt8; 64 | d @3: Data; 65 | e @4: List(TestStructInner); 66 | f @5: TestStructInner; 67 | } 68 | 69 | struct GenericEnum { 70 | union { 71 | varA @0: UInt32; 72 | varB @1: TestStructInner; 73 | varC @2: UInt64; 74 | varD @3: Data; 75 | } 76 | } 77 | 78 | struct InnerGeneric { 79 | a @0: UInt32; 80 | } 81 | 82 | struct ListGeneric { 83 | list @0: List(InnerGeneric); 84 | } 85 | 86 | # A custom made 128 bit data structure. 87 | struct Buffer128 { 88 | x0 @0: UInt64; 89 | x1 @1: UInt64; 90 | } 91 | 92 | # Unsigned 128 bit integer 93 | struct CustomUInt128 { 94 | inner @0: Buffer128; 95 | } 96 | 97 | 98 | struct TestWithStruct { 99 | a @0: CustomUInt128; 100 | b @1: UInt64; 101 | } 102 | 103 | struct TestWithEnum { 104 | union { 105 | varA @0: CustomUInt128; 106 | varB @1: UInt64; 107 | varC @2: Void; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /components/channeler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-channeler" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | relay = { path = "../relay", version = "0.1.0" , package = "offset-relay" } 16 | 17 | log = "0.4" 18 | futures = "0.3.1" 19 | 20 | [dev-dependencies] 21 | 22 | futures = {version = "0.3.1", features = ["thread-pool"]} 23 | -------------------------------------------------------------------------------- /components/channeler/src/connector_utils.rs: -------------------------------------------------------------------------------- 1 | /* 2 | use futures::task::Spawn; 3 | 4 | use crypto::identity::PublicKey; 5 | use crypto::crypto_rand::CryptoRandom; 6 | use timer::TimerClient; 7 | use identity::IdentityClient; 8 | use common::conn::{BoxFuture, Connector, ConnPair}; 9 | // use secure_channel::create_secure_channel; 10 | 11 | 12 | #[derive(Clone)] 13 | pub struct EncryptedConnector { 14 | connector: C, 15 | identity_client: IdentityClient, 16 | rng: R, 17 | timer_client: TimerClient, 18 | ticks_to_rekey: usize, 19 | spawner: S, 20 | } 21 | 22 | 23 | /// Turns a connector into a connector that yields encrypted connections. 24 | /// Addresses are changed from A into (PublicKey, A), 25 | /// where public_key is the identity of the remote side. 26 | impl EncryptedConnector { 27 | #[allow(unused)] 28 | pub fn new(connector: C, 29 | identity_client: IdentityClient, 30 | rng: R, 31 | timer_client: TimerClient, 32 | ticks_to_rekey: usize, 33 | spawner: S) -> EncryptedConnector { 34 | 35 | EncryptedConnector { 36 | connector, 37 | identity_client, 38 | rng, 39 | timer_client, 40 | ticks_to_rekey, 41 | spawner, 42 | } 43 | } 44 | } 45 | 46 | impl Connector for EncryptedConnector 47 | where 48 | R: CryptoRandom + 'static, 49 | C: Connector,RecvItem=Vec> + Send, 50 | A: Clone + Send + 'static, 51 | S: Spawn + Clone + Send, 52 | { 53 | type Address = (PublicKey, A); 54 | type SendItem = Vec; 55 | type RecvItem = Vec; 56 | 57 | fn connect(&mut self, full_address: (PublicKey, A)) 58 | -> BoxFuture<'_, Option>> { 59 | 60 | let (public_key, address) = full_address; 61 | let fut = async move { 62 | let (plain_sender, plain_receiver) = self.connector.connect(address).await?; 63 | let (sender, receiver) = create_secure_channel( 64 | plain_sender, plain_receiver, 65 | self.identity_client.clone(), 66 | Some(public_key.clone()), 67 | self.rng.clone(), 68 | self.timer_client.clone(), 69 | self.ticks_to_rekey, 70 | self.spawner.clone()).await 71 | .ok()?; 72 | Some((sender, receiver)) 73 | }; 74 | Box::pin(fut) 75 | } 76 | } 77 | */ 78 | -------------------------------------------------------------------------------- /components/channeler/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate common; 16 | 17 | mod connect_pool; 18 | mod inner_loop; 19 | // mod connector_utils; 20 | mod channeler; 21 | mod listen_pool; 22 | mod listen_pool_state; 23 | mod overwrite_channel; 24 | mod types; 25 | 26 | pub use self::channeler::{channeler_loop, SpawnChannelerError}; 27 | pub use self::inner_loop::ChannelerError; 28 | -------------------------------------------------------------------------------- /components/channeler/src/types.rs: -------------------------------------------------------------------------------- 1 | use common::access_control::{AccessControl, AccessControlOp}; 2 | 3 | use proto::crypto::PublicKey; 4 | 5 | pub type AccessControlPk = AccessControl; 6 | pub type AccessControlOpPk = AccessControlOp; 7 | -------------------------------------------------------------------------------- /components/common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-common" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | log = "0.4" 10 | 11 | 12 | bytes = "0.5.4" 13 | futures = "0.3.1" 14 | 15 | serde = "1.0.104" 16 | byteorder = "1.1" 17 | 18 | backtrace = "0.3.14" 19 | base64 = "0.10.1" 20 | 21 | [dev-dependencies] 22 | 23 | serde = {version = "1.0.104", features = ["derive"]} 24 | -------------------------------------------------------------------------------- /components/common/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/common/src/access_control.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | // TODO: Possibly move to another place? Maybe proto? 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub enum AccessControlOp { 7 | Add(T), 8 | Remove(T), 9 | } 10 | 11 | #[derive(Clone, Debug, Default)] 12 | pub struct AccessControl { 13 | allowed: HashSet, 14 | } 15 | 16 | impl AccessControl 17 | where 18 | T: std::cmp::Eq + std::hash::Hash, 19 | { 20 | pub fn new() -> AccessControl { 21 | AccessControl { 22 | allowed: HashSet::new(), 23 | } 24 | } 25 | 26 | pub fn apply_op(&mut self, allowed_op: AccessControlOp) { 27 | match allowed_op { 28 | AccessControlOp::Add(item) => { 29 | self.allowed.insert(item); 30 | } 31 | AccessControlOp::Remove(item) => { 32 | self.allowed.remove(&item); 33 | } 34 | } 35 | } 36 | 37 | /// Check if a certain public key is allowed. 38 | pub fn is_allowed(&self, item: &T) -> bool { 39 | self.allowed.contains(item) 40 | } 41 | } 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | use super::*; 46 | 47 | #[test] 48 | fn test_access_control_basic() { 49 | let a_public_key = 0xaa; 50 | let b_public_key = 0xbb; 51 | 52 | let mut ac = AccessControl::new(); 53 | assert!(!ac.is_allowed(&a_public_key)); 54 | assert!(!ac.is_allowed(&b_public_key)); 55 | 56 | // Add a: 57 | ac.apply_op(AccessControlOp::Add(a_public_key.clone())); 58 | assert!(ac.is_allowed(&a_public_key)); 59 | assert!(!ac.is_allowed(&b_public_key)); 60 | 61 | // Add b: 62 | ac.apply_op(AccessControlOp::Add(b_public_key.clone())); 63 | assert!(ac.is_allowed(&a_public_key)); 64 | assert!(ac.is_allowed(&b_public_key)); 65 | 66 | // Remove a: 67 | ac.apply_op(AccessControlOp::Remove(a_public_key.clone())); 68 | assert!(!ac.is_allowed(&a_public_key)); 69 | assert!(ac.is_allowed(&b_public_key)); 70 | 71 | // Remove b: 72 | ac.apply_op(AccessControlOp::Remove(b_public_key.clone())); 73 | assert!(!ac.is_allowed(&a_public_key)); 74 | assert!(!ac.is_allowed(&b_public_key)); 75 | 76 | // Remove b again: 77 | ac.apply_op(AccessControlOp::Remove(b_public_key.clone())); 78 | assert!(!ac.is_allowed(&a_public_key)); 79 | assert!(!ac.is_allowed(&b_public_key)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /components/common/src/async_test_utils.rs: -------------------------------------------------------------------------------- 1 | use futures::{Stream, StreamExt}; 2 | use std::marker::Unpin; 3 | 4 | #[derive(Debug, Eq, PartialEq)] 5 | pub enum ReceiveError { 6 | Closed, 7 | Error, 8 | } 9 | 10 | /// Util function to read one item from a Stream, asynchronously. 11 | pub async fn receive(mut reader: M) -> Option<(T, M)> 12 | where 13 | M: Stream + Unpin, 14 | { 15 | match reader.next().await { 16 | Some(reader_msg) => Some((reader_msg, reader)), 17 | None => None, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/common/src/caller_info.rs: -------------------------------------------------------------------------------- 1 | use backtrace::{self, Symbol}; 2 | use std::path::PathBuf; 3 | 4 | #[derive(Clone, Debug)] 5 | pub struct CallerInfo { 6 | /// The symbol name of the caller (Demangled): 7 | pub name: String, 8 | /// The file that contains the callsite: 9 | pub filename: PathBuf, 10 | /// Line number: 11 | pub lineno: u32, 12 | } 13 | 14 | fn symbol_to_caller_info(symbol: &Symbol) -> Option { 15 | let name = format!("{}", symbol.name()?); 16 | let filename = symbol.filename()?.to_path_buf(); 17 | let lineno = symbol.lineno()?; 18 | 19 | Some(CallerInfo { 20 | name, 21 | filename, 22 | lineno, 23 | }) 24 | } 25 | 26 | /// Get information about the caller, `level` levels above a frame that satisfies some predicate 27 | /// `pred`. 28 | pub fn get_caller_info(mut level: usize, pred: F) -> Option 29 | where 30 | F: Fn(&CallerInfo) -> bool, 31 | { 32 | // Have we already found our function in the stack trace? 33 | let mut pred_found = false; 34 | let mut opt_caller_info = None; 35 | 36 | backtrace::trace(|frame| { 37 | let ip = frame.ip(); 38 | 39 | let mut opt_cur_caller_info = None; 40 | backtrace::resolve(ip, |symbol| { 41 | opt_cur_caller_info = symbol_to_caller_info(&symbol); 42 | }); 43 | 44 | let cur_caller_info = match opt_cur_caller_info { 45 | Some(cur_caller_info) => cur_caller_info, 46 | None => { 47 | opt_caller_info = None; 48 | return false; 49 | } 50 | }; 51 | 52 | pred_found |= pred(&cur_caller_info); 53 | if !pred_found { 54 | // Move on to the next frame: 55 | return true; 56 | } 57 | 58 | // Wanted frame was already found: 59 | if level > 0 { 60 | level = level.saturating_sub(1); 61 | // Move on to the next frame: 62 | return true; 63 | } 64 | // We got to the interesting frame: 65 | 66 | opt_caller_info = Some(cur_caller_info); 67 | 68 | false // Stop iterating 69 | }); 70 | 71 | opt_caller_info 72 | } 73 | 74 | #[cfg(test)] 75 | mod tests { 76 | use super::*; 77 | 78 | #[test] 79 | fn test_get_caller_info() { 80 | // Be careful: Adding new lines inside this test might break it, because 81 | // line numbers are calculated: 82 | let cur_lineno = line!(); 83 | let caller_info = get_caller_info(0, |caller_info| { 84 | caller_info.name.contains("test_get_caller_info") 85 | }) 86 | .unwrap(); 87 | assert!(caller_info.name.contains("test_get_caller_info")); 88 | assert_eq!(caller_info.lineno, cur_lineno + 1); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /components/common/src/canonical_serialize.rs: -------------------------------------------------------------------------------- 1 | use crate::int_convert::usize_to_u64; 2 | use byteorder::{BigEndian, WriteBytesExt}; 3 | 4 | /// Canonically serialize an object 5 | /// This serialization is used for security related applications (For example, signatures and 6 | /// hashing), therefore the serialization result must be the same on any system. 7 | pub trait CanonicalSerialize { 8 | fn canonical_serialize(&self) -> Vec; 9 | } 10 | 11 | impl CanonicalSerialize for Option 12 | where 13 | T: CanonicalSerialize, 14 | { 15 | fn canonical_serialize(&self) -> Vec { 16 | let mut res_data = Vec::new(); 17 | match &self { 18 | None => { 19 | res_data.push(0); 20 | } 21 | Some(t) => { 22 | res_data.push(1); 23 | res_data.extend_from_slice(&t.canonical_serialize()); 24 | } 25 | }; 26 | res_data 27 | } 28 | } 29 | 30 | impl CanonicalSerialize for Vec 31 | where 32 | T: CanonicalSerialize, 33 | { 34 | fn canonical_serialize(&self) -> Vec { 35 | let mut res_data = Vec::new(); 36 | // Write length: 37 | res_data 38 | .write_u64::(usize_to_u64(self.len()).unwrap()) 39 | .unwrap(); 40 | // Write all items: 41 | for t in self.iter() { 42 | res_data.extend_from_slice(&t.canonical_serialize()); 43 | } 44 | res_data 45 | } 46 | } 47 | 48 | impl CanonicalSerialize for String { 49 | fn canonical_serialize(&self) -> Vec { 50 | self.as_bytes().to_vec() 51 | } 52 | } 53 | 54 | // Used mostly for testing: 55 | impl CanonicalSerialize for u32 { 56 | fn canonical_serialize(&self) -> Vec { 57 | let mut res_data = Vec::new(); 58 | res_data.write_u32::(*self).unwrap(); 59 | res_data 60 | } 61 | } 62 | 63 | impl CanonicalSerialize for (T, W) 64 | where 65 | T: CanonicalSerialize, 66 | W: CanonicalSerialize, 67 | { 68 | fn canonical_serialize(&self) -> Vec { 69 | let (t, w) = self; 70 | let mut res_data = Vec::new(); 71 | res_data.extend_from_slice(&t.canonical_serialize()); 72 | res_data.extend_from_slice(&w.canonical_serialize()); 73 | res_data 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /components/common/src/dummy_connector.rs: -------------------------------------------------------------------------------- 1 | use crate::conn::{BoxFuture, FutTransform}; 2 | use futures::channel::{mpsc, oneshot}; 3 | use futures::SinkExt; 4 | 5 | pub struct ConnRequest { 6 | pub address: A, 7 | response_sender: oneshot::Sender, 8 | } 9 | 10 | impl ConnRequest { 11 | pub fn reply(self, response: O) { 12 | self.response_sender.send(response).ok().unwrap(); 13 | } 14 | } 15 | 16 | /// A connector that contains only one pre-created connection. 17 | pub struct DummyConnector { 18 | req_sender: mpsc::Sender>, 19 | } 20 | 21 | impl DummyConnector { 22 | pub fn new(req_sender: mpsc::Sender>) -> Self { 23 | DummyConnector { req_sender } 24 | } 25 | } 26 | 27 | // #[derive(Clone)] does not work for DummyListener when compiling index_client 28 | // Seems like it has a problem with having config_receiver inside ListenRequest. 29 | // O is Option<(Sender, Receiver)> 30 | // where Sender and Receiver are from futures. 31 | // This is a workaround for this issue: 32 | impl Clone for DummyConnector { 33 | fn clone(&self) -> DummyConnector { 34 | DummyConnector { 35 | req_sender: self.req_sender.clone(), 36 | } 37 | } 38 | } 39 | 40 | impl FutTransform for DummyConnector 41 | where 42 | O: Send, 43 | A: Send + Sync, 44 | { 45 | type Input = A; 46 | type Output = O; 47 | 48 | fn transform(&mut self, address: A) -> BoxFuture<'_, Self::Output> { 49 | let (response_sender, response_receiver) = oneshot::channel(); 50 | let conn_request = ConnRequest { 51 | address, 52 | response_sender, 53 | }; 54 | 55 | let fut_conn_pair = async move { 56 | self.req_sender.send(conn_request).await.unwrap(); 57 | response_receiver.await.unwrap() 58 | }; 59 | Box::pin(fut_conn_pair) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /components/common/src/dummy_listener.rs: -------------------------------------------------------------------------------- 1 | use crate::conn::{FutListenerClient, Listener, ListenerClient}; 2 | use futures::{channel::mpsc, SinkExt}; 3 | 4 | pub struct ListenRequest { 5 | pub conn_sender: mpsc::Sender, 6 | pub config_receiver: mpsc::Receiver, 7 | pub arg: AR, 8 | } 9 | 10 | /// A test util: A mock Listener. 11 | pub struct DummyListener { 12 | req_sender: mpsc::Sender>, 13 | } 14 | 15 | // TODO: Why didn't the automatic #[derive(Clone)] works for DummyListener? 16 | // This is a workaround for this issue: 17 | impl Clone for DummyListener { 18 | fn clone(&self) -> DummyListener { 19 | DummyListener { 20 | req_sender: self.req_sender.clone(), 21 | } 22 | } 23 | } 24 | 25 | impl DummyListener 26 | where 27 | CONN: Send + 'static, 28 | CONF: Send + 'static, 29 | AR: Send + 'static, 30 | { 31 | pub fn new( 32 | req_sender: mpsc::Sender>, 33 | ) -> DummyListener { 34 | DummyListener { req_sender } 35 | } 36 | } 37 | 38 | #[derive(Debug)] 39 | pub struct DummyListenerError; 40 | 41 | impl Listener for DummyListener 42 | where 43 | CONN: Send + 'static, 44 | CONF: Send + 'static, 45 | AR: Send + 'static, 46 | { 47 | type Connection = CONN; 48 | type Config = CONF; 49 | type Arg = AR; 50 | type Error = DummyListenerError; 51 | 52 | fn listen( 53 | self, 54 | arg: Self::Arg, 55 | ) -> FutListenerClient { 56 | let (conn_sender, conn_receiver) = mpsc::channel(1); 57 | let (config_sender, config_receiver) = mpsc::channel(1); 58 | 59 | let listen_request = ListenRequest { 60 | conn_sender, 61 | config_receiver, 62 | arg, 63 | }; 64 | 65 | let DummyListener { mut req_sender } = self; 66 | 67 | Box::pin(async move { 68 | req_sender 69 | .send(listen_request) 70 | .await 71 | .map_err(|_| DummyListenerError)?; 72 | 73 | Ok(ListenerClient { 74 | config_sender, 75 | conn_receiver, 76 | }) 77 | }) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /components/common/src/futures_compat.rs: -------------------------------------------------------------------------------- 1 | use futures::sink::{Sink, SinkExt}; 2 | use futures::{stream, Future, FutureExt, StreamExt}; 3 | use std::marker::Unpin; 4 | 5 | // TODO; Is there a better way to do this with the new Futures libraries? 6 | /// A helper function to allow sending into a sink while consuming the sink. 7 | /// Futures 3.0's Sink::send function takes a mutable reference to the sink instead of consuming 8 | /// it. 9 | /// See: https://users.rust-lang.org/t/discarding-unused-cloned-sender-futures-3-0/21228 10 | pub async fn send_to_sink(mut sink: S, item: T) -> Result 11 | where 12 | S: Sink + std::marker::Unpin + 'static, 13 | { 14 | sink.send(item).await?; 15 | Ok(sink) 16 | } 17 | 18 | /// A futures select function that outputs an Unpin future. 19 | pub fn future_select( 20 | a: impl Future + Unpin, 21 | b: impl Future + Unpin, 22 | ) -> impl Future + Unpin { 23 | let s_a = stream::once(a); 24 | let s_b = stream::once(b); 25 | let s = stream::select(s_a, s_b); 26 | s.into_future().map(|(opt_item, _s)| opt_item.unwrap()) 27 | } 28 | -------------------------------------------------------------------------------- /components/common/src/int_convert.rs: -------------------------------------------------------------------------------- 1 | use std::u32; 2 | 3 | #[cfg(any( 4 | target_pointer_width = "8", 5 | target_pointer_width = "16", 6 | target_pointer_width = "32" 7 | ))] 8 | pub fn usize_to_u32(num: usize) -> Option { 9 | Some(num as u32) 10 | } 11 | 12 | #[cfg(target_pointer_width = "64")] 13 | pub fn usize_to_u32(num: usize) -> Option { 14 | if num > u32::MAX as usize { 15 | None 16 | } else { 17 | Some(num as u32) 18 | } 19 | } 20 | 21 | // TODO: Possibly make this function constant? 22 | // TODO: Possibly replace Option with u64 in the future? 23 | #[cfg(any( 24 | target_pointer_width = "8", 25 | target_pointer_width = "16", 26 | target_pointer_width = "32", 27 | target_pointer_width = "64" 28 | ))] 29 | pub fn usize_to_u64(num: usize) -> Option { 30 | Some(num as u64) 31 | } 32 | 33 | #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] 34 | pub fn u32_to_usize(num: u32) -> Option { 35 | Some(num as usize) 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::*; 41 | 42 | #[test] 43 | fn test_usize_to_u32() { 44 | assert_eq!(usize_to_u32(0_usize), Some(0u32)); 45 | assert_eq!(usize_to_u32(1_usize), Some(1u32)); 46 | assert_eq!(usize_to_u32(0xffff_ffff_usize), Some(0xffff_ffffu32)); 47 | assert_eq!(usize_to_u32(0x1_0000_0000_usize), None); 48 | } 49 | 50 | #[test] 51 | fn test_usize_to_u64() { 52 | assert_eq!(usize_to_u64(0usize), Some(0u64)); 53 | assert_eq!(usize_to_u64(1usize), Some(1u64)); 54 | assert_eq!( 55 | usize_to_u64(0xffff_ffff_ffff_ffff_usize), 56 | Some(0xffff_ffff_ffff_ffffu64) 57 | ); 58 | } 59 | 60 | #[test] 61 | fn test_u32_to_usize() { 62 | assert_eq!(u32_to_usize(0u32), Some(0usize)); 63 | assert_eq!(u32_to_usize(1u32), Some(1usize)); 64 | assert_eq!(u32_to_usize(0xffff_ffff_u32), Some(0xffff_ffff_usize)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /components/common/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[cfg(test)] 15 | extern crate serde; 16 | 17 | pub mod int_convert; 18 | pub mod never; 19 | pub mod safe_arithmetic; 20 | #[macro_use] 21 | pub mod big_array; 22 | #[macro_use] 23 | pub mod define_fixed_bytes; 24 | // pub mod async_adapter; 25 | // pub mod frame_codec; 26 | pub mod access_control; 27 | pub mod async_test_utils; 28 | pub mod caller_info; 29 | // pub mod canonical_serialize; 30 | pub mod conn; 31 | pub mod dummy_connector; 32 | pub mod dummy_listener; 33 | pub mod futures_compat; 34 | pub mod multi_consumer; 35 | pub mod mutable_state; 36 | pub mod select_streams; 37 | pub mod state_service; 38 | pub mod transform_pool; 39 | // pub mod wait_spawner; 40 | #[macro_use] 41 | pub mod ser_utils; 42 | pub mod test_executor; 43 | -------------------------------------------------------------------------------- /components/common/src/mutable_state.rs: -------------------------------------------------------------------------------- 1 | pub trait MutableState { 2 | type Mutation; 3 | type MutateError; 4 | 5 | fn mutate(&mut self, mutation: &Self::Mutation) -> Result<(), Self::MutateError>; 6 | } 7 | -------------------------------------------------------------------------------- /components/common/src/never.rs: -------------------------------------------------------------------------------- 1 | // A shim allowing to have Never type on stable rust. 2 | // Should be removed once never type reaches stable. 3 | // 4 | // Based on: https://github.com/CodeChain-io/rust-never-type/blob/master/src/lib.rs 5 | 6 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 7 | pub enum Never {} 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use std::mem::size_of; 12 | 13 | use super::*; 14 | 15 | #[test] 16 | fn size_of_never_is_zero() { 17 | assert_eq!(0, size_of::()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ser_b64; 2 | pub mod ser_map_b64_any; 3 | pub mod ser_map_str_any; 4 | pub mod ser_map_str_str; 5 | pub mod ser_option_b64; 6 | pub mod ser_seq_b64; 7 | pub mod ser_seq_str; 8 | pub mod ser_string; 9 | pub mod ser_vec_b64; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_b64.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | use std::fmt; 3 | use std::marker::PhantomData; 4 | use std::string::ToString; 5 | 6 | use serde::de::{Error, Visitor}; 7 | use serde::ser::Serializer; 8 | use serde::Deserializer; 9 | 10 | use base64::{self, URL_SAFE_NO_PAD}; 11 | 12 | pub fn serialize(item: &T, serializer: S) -> Result 13 | where 14 | S: Serializer, 15 | T: AsRef<[u8]>, 16 | { 17 | let base64_str = base64::encode_config(&item.as_ref(), URL_SAFE_NO_PAD); 18 | serializer.serialize_str(&base64_str) 19 | } 20 | 21 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 22 | where 23 | D: Deserializer<'de>, 24 | T: for<'t> TryFrom<&'t [u8]>, 25 | { 26 | struct ItemVisitor { 27 | item: PhantomData, 28 | } 29 | 30 | impl<'de, T> Visitor<'de> for ItemVisitor 31 | where 32 | T: for<'t> TryFrom<&'t [u8]>, 33 | { 34 | type Value = T; 35 | 36 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 37 | formatter.write_str("A bytes like item") 38 | } 39 | 40 | fn visit_str(self, str_item: &str) -> Result 41 | where 42 | E: Error, 43 | { 44 | let vec = base64::decode_config(&str_item, URL_SAFE_NO_PAD) 45 | .map_err(|err| Error::custom(err.to_string()))?; 46 | T::try_from(&vec).map_err(|_| Error::custom("Length mismatch")) 47 | } 48 | } 49 | 50 | let visitor = ItemVisitor { item: PhantomData }; 51 | deserializer.deserialize_str(visitor) 52 | } 53 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_map_str_any.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::hash::Hash; 3 | use std::marker::PhantomData; 4 | use std::str::FromStr; 5 | use std::string::ToString; 6 | 7 | use serde::de::{Deserialize, Error, MapAccess, Visitor}; 8 | use serde::ser::{Serialize, SerializeMap, Serializer}; 9 | use serde::Deserializer; 10 | 11 | pub fn serialize(input_map: M, serializer: S) -> Result 12 | where 13 | S: Serializer, 14 | K: Serialize + ToString + Eq + Hash, 15 | V: Serialize, 16 | M: IntoIterator, 17 | { 18 | // TODO: A more efficient way to do this? 19 | let pairs: Vec<_> = input_map.into_iter().collect(); 20 | let mut map = serializer.serialize_map(Some(pairs.len()))?; 21 | for (k, v) in pairs.into_iter() { 22 | map.serialize_entry(&k.to_string(), &v)?; 23 | } 24 | map.end() 25 | } 26 | 27 | pub fn deserialize<'de, K, V, M, D>(deserializer: D) -> Result 28 | where 29 | D: Deserializer<'de>, 30 | K: Deserialize<'de> + FromStr + Eq + Hash, 31 | V: Deserialize<'de>, 32 | M: Default + Extend<(K, V)>, 33 | { 34 | struct MapVisitor { 35 | key: PhantomData, 36 | value: PhantomData, 37 | map: PhantomData, 38 | } 39 | 40 | impl<'de, K, V, M> Visitor<'de> for MapVisitor 41 | where 42 | K: Deserialize<'de> + FromStr + Eq + Hash, 43 | V: Deserialize<'de>, 44 | M: Default + Extend<(K, V)>, 45 | { 46 | type Value = M; 47 | 48 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 49 | formatter.write_str("A map") 50 | } 51 | 52 | fn visit_map(self, mut map: A) -> Result 53 | where 54 | A: MapAccess<'de>, 55 | { 56 | let mut res_map = M::default(); 57 | while let Some((k_string, v)) = map.next_entry::()? { 58 | let k = k_string 59 | .parse() 60 | .map_err(|_| Error::custom(format!("Parse failed: {:?}", k_string)))?; 61 | 62 | res_map.extend(Some((k, v))); 63 | } 64 | Ok(res_map) 65 | } 66 | } 67 | 68 | let visitor = MapVisitor { 69 | key: PhantomData, 70 | value: PhantomData, 71 | map: PhantomData, 72 | }; 73 | deserializer.deserialize_map(visitor) 74 | } 75 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_map_str_str.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::hash::Hash; 3 | use std::marker::PhantomData; 4 | use std::str::FromStr; 5 | use std::string::ToString; 6 | 7 | use serde::de::{Deserialize, Error, MapAccess, Visitor}; 8 | use serde::ser::{Serialize, SerializeMap, Serializer}; 9 | use serde::Deserializer; 10 | 11 | pub fn serialize(input_map: M, serializer: S) -> Result 12 | where 13 | S: Serializer, 14 | K: Serialize + ToString + Eq + Hash, 15 | V: Serialize + ToString, 16 | M: IntoIterator, 17 | { 18 | // TODO: A more efficient way to do this? 19 | let pairs: Vec<_> = input_map.into_iter().collect(); 20 | let mut map = serializer.serialize_map(Some(pairs.len()))?; 21 | for (k, v) in pairs.into_iter() { 22 | map.serialize_entry(&k.to_string(), &v.to_string())?; 23 | } 24 | map.end() 25 | } 26 | 27 | pub fn deserialize<'de, K, V, M, D>(deserializer: D) -> Result 28 | where 29 | D: Deserializer<'de>, 30 | K: Deserialize<'de> + FromStr + Eq + Hash, 31 | V: Deserialize<'de> + FromStr, 32 | M: Default + Extend<(K, V)>, 33 | { 34 | struct MapVisitor { 35 | key: PhantomData, 36 | value: PhantomData, 37 | map: PhantomData, 38 | } 39 | 40 | impl<'de, K, V, M> Visitor<'de> for MapVisitor 41 | where 42 | K: Deserialize<'de> + FromStr + Eq + Hash, 43 | V: Deserialize<'de> + FromStr, 44 | M: Default + Extend<(K, V)>, 45 | { 46 | type Value = M; 47 | 48 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 49 | formatter.write_str("A map") 50 | } 51 | 52 | fn visit_map(self, mut map: A) -> Result 53 | where 54 | A: MapAccess<'de>, 55 | { 56 | let mut res_map = M::default(); 57 | 58 | while let Some((k_string, v_string)) = map.next_entry::()? { 59 | let k = k_string 60 | .parse() 61 | .map_err(|_| Error::custom("Parse failed"))?; 62 | 63 | let v = v_string 64 | .parse() 65 | .map_err(|_| Error::custom("Parse failed"))?; 66 | 67 | res_map.extend(Some((k, v))); 68 | } 69 | Ok(res_map) 70 | } 71 | } 72 | 73 | let visitor = MapVisitor { 74 | key: PhantomData, 75 | value: PhantomData, 76 | map: PhantomData, 77 | }; 78 | deserializer.deserialize_map(visitor) 79 | } 80 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_seq_b64.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | use std::fmt; 3 | use std::marker::PhantomData; 4 | use std::string::ToString; 5 | 6 | use serde::de::{Deserialize, Error, SeqAccess, Visitor}; 7 | use serde::ser::{Serialize, Serializer}; 8 | use serde::Deserializer; 9 | 10 | use base64::{self, URL_SAFE_NO_PAD}; 11 | 12 | pub fn serialize(input_vec: V, serializer: S) -> Result 13 | where 14 | S: Serializer, 15 | T: Serialize + AsRef<[u8]>, 16 | V: IntoIterator, 17 | { 18 | let items_iter = input_vec 19 | .into_iter() 20 | .map(|item| base64::encode_config(item.as_ref(), URL_SAFE_NO_PAD)); 21 | serializer.collect_seq(items_iter) 22 | } 23 | 24 | pub fn deserialize<'de, T, V, D>(deserializer: D) -> Result 25 | where 26 | D: Deserializer<'de>, 27 | T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>, 28 | // The `IntoIterator` bound is a hack for solving ambiguity. 29 | // See: 30 | // https://users.rust-lang.org/t/serde-type-annotations-needed-cannot-resolve-serde-deserialize/36482?u=realcr 31 | V: Default + Extend + IntoIterator, 32 | { 33 | struct SeqVisitor { 34 | item: PhantomData, 35 | seq: PhantomData, 36 | } 37 | 38 | impl<'de, T, V> Visitor<'de> for SeqVisitor 39 | where 40 | T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>, 41 | V: Default + Extend, 42 | { 43 | type Value = V; 44 | 45 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 46 | formatter.write_str("A vector") 47 | } 48 | 49 | fn visit_seq(self, mut seq: A) -> Result 50 | where 51 | A: SeqAccess<'de>, 52 | { 53 | let mut res_vec: V = V::default(); 54 | while let Some(str_item) = seq.next_element::()? { 55 | let item_vec: Vec = base64::decode_config(&str_item, URL_SAFE_NO_PAD) 56 | .map_err(|err| Error::custom(err.to_string()))?; 57 | let item = T::try_from(&item_vec).map_err(|_| Error::custom("Length mismatch"))?; 58 | // Extend::::extend(&mut res_vec, Some(item)); 59 | res_vec.extend(Some(item)); 60 | } 61 | Ok(res_vec) 62 | } 63 | } 64 | 65 | let visitor = SeqVisitor { 66 | item: PhantomData, 67 | seq: PhantomData, 68 | }; 69 | deserializer.deserialize_seq(visitor) 70 | } 71 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_seq_str.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::marker::PhantomData; 3 | use std::str::FromStr; 4 | use std::string::ToString; 5 | 6 | use serde::de::{Deserialize, Error, SeqAccess, Visitor}; 7 | use serde::ser::{Serialize, Serializer}; 8 | use serde::Deserializer; 9 | 10 | pub fn serialize(input_vec: V, serializer: S) -> Result 11 | where 12 | S: Serializer, 13 | T: Serialize + ToString, 14 | V: IntoIterator, 15 | { 16 | let items_iter = input_vec.into_iter().map(|item| item.to_string()); 17 | serializer.collect_seq(items_iter) 18 | } 19 | 20 | pub fn deserialize<'de, T, V, D>(deserializer: D) -> Result 21 | where 22 | D: Deserializer<'de>, 23 | T: Deserialize<'de> + FromStr, 24 | V: Default + Extend, 25 | { 26 | struct SeqVisitor { 27 | item: PhantomData, 28 | seq: PhantomData, 29 | } 30 | 31 | impl<'de, T, V> Visitor<'de> for SeqVisitor 32 | where 33 | T: Deserialize<'de> + FromStr, 34 | V: Default + Extend, 35 | { 36 | type Value = V; 37 | 38 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 39 | formatter.write_str("A vector") 40 | } 41 | 42 | fn visit_seq(self, mut seq: A) -> Result 43 | where 44 | A: SeqAccess<'de>, 45 | { 46 | let mut res_vec: V = V::default(); 47 | while let Some(str_item) = seq.next_element::()? { 48 | let item = T::from_str(&str_item).map_err(|_| Error::custom("Length mismatch"))?; 49 | res_vec.extend(Some(item)); 50 | } 51 | Ok(res_vec) 52 | } 53 | } 54 | 55 | let visitor = SeqVisitor { 56 | item: PhantomData, 57 | seq: PhantomData, 58 | }; 59 | deserializer.deserialize_seq(visitor) 60 | } 61 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_string.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::marker::PhantomData; 3 | use std::str::FromStr; 4 | use std::string::ToString; 5 | 6 | use serde::de::{Error, Visitor}; 7 | use serde::ser::Serializer; 8 | use serde::Deserializer; 9 | 10 | pub fn serialize(item: &T, serializer: S) -> Result 11 | where 12 | S: Serializer, 13 | T: ToString, 14 | { 15 | serializer.serialize_str(&item.to_string()) 16 | } 17 | 18 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 19 | where 20 | D: Deserializer<'de>, 21 | T: FromStr, 22 | { 23 | struct ItemVisitor { 24 | item: PhantomData, 25 | } 26 | 27 | impl<'de, T> Visitor<'de> for ItemVisitor 28 | where 29 | T: FromStr, 30 | { 31 | type Value = T; 32 | 33 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 34 | formatter.write_str("A bytes like item") 35 | } 36 | 37 | fn visit_str(self, str_item: &str) -> Result 38 | where 39 | E: Error, 40 | { 41 | str_item 42 | .parse() 43 | .map_err(|_| Error::custom("Failed to parse as string")) 44 | } 45 | } 46 | 47 | let visitor = ItemVisitor { item: PhantomData }; 48 | deserializer.deserialize_str(visitor) 49 | } 50 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/ser_vec_b64.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | use std::fmt; 3 | use std::marker::PhantomData; 4 | use std::string::ToString; 5 | 6 | use serde::de::{Deserialize, Error, SeqAccess, Visitor}; 7 | use serde::ser::{Serialize, Serializer}; 8 | use serde::Deserializer; 9 | 10 | use base64::{self, URL_SAFE_NO_PAD}; 11 | 12 | pub fn serialize(input_vec: &[T], serializer: S) -> Result 13 | where 14 | S: Serializer, 15 | T: Serialize + AsRef<[u8]>, 16 | { 17 | let items_iter = input_vec 18 | .iter() 19 | .map(|item| base64::encode_config(item.as_ref(), URL_SAFE_NO_PAD)); 20 | serializer.collect_seq(items_iter) 21 | } 22 | 23 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result, D::Error> 24 | where 25 | D: Deserializer<'de>, 26 | T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>, 27 | { 28 | struct SeqVisitor { 29 | item: PhantomData, 30 | } 31 | 32 | impl<'de, T> Visitor<'de> for SeqVisitor 33 | where 34 | T: Deserialize<'de> + for<'t> TryFrom<&'t [u8]>, 35 | { 36 | type Value = Vec; 37 | 38 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 39 | formatter.write_str("A vector") 40 | } 41 | 42 | fn visit_seq(self, mut seq: A) -> Result 43 | where 44 | A: SeqAccess<'de>, 45 | { 46 | let mut res_vec = Vec::new(); 47 | while let Some(str_item) = seq.next_element::()? { 48 | let item_vec = base64::decode_config(&str_item, URL_SAFE_NO_PAD) 49 | .map_err(|err| Error::custom(err.to_string()))?; 50 | let item = T::try_from(&item_vec).map_err(|_| Error::custom("Length mismatch"))?; 51 | res_vec.push(item); 52 | } 53 | Ok(res_vec) 54 | } 55 | } 56 | 57 | let visitor = SeqVisitor { item: PhantomData }; 58 | deserializer.deserialize_seq(visitor) 59 | } 60 | -------------------------------------------------------------------------------- /components/common/src/ser_utils/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::collections::{HashMap, HashSet}; 3 | 4 | use serde::{Deserialize, Serialize}; 5 | 6 | #[allow(unused)] 7 | #[derive(Deserialize)] 8 | struct MySeqStruct { 9 | #[serde(with = "ser_seq_b64")] 10 | my_vec: Vec<[u8; 16]>, 11 | } 12 | 13 | #[allow(unused)] 14 | #[derive(Deserialize)] 15 | struct MyVecStruct { 16 | #[serde(with = "ser_vec_b64")] 17 | my_vec: Vec<[u8; 16]>, 18 | } 19 | 20 | #[allow(unused)] 21 | #[derive(Serialize, Deserialize)] 22 | struct MyOptionB64Struct { 23 | #[serde(with = "ser_option_b64")] 24 | my_opt: Option<[u8; 16]>, 25 | } 26 | 27 | #[allow(unused)] 28 | #[derive(Serialize, Deserialize)] 29 | struct MyMapB64AnyStruct { 30 | #[serde(with = "ser_map_b64_any")] 31 | my_map: HashMap<[u8; 32], String>, 32 | } 33 | 34 | #[allow(unused)] 35 | #[derive(Serialize, Deserialize)] 36 | struct MyMapStrAnyStruct { 37 | #[serde(with = "ser_map_str_any")] 38 | my_map: HashMap, 39 | } 40 | 41 | #[allow(unused)] 42 | #[derive(Serialize, Deserialize)] 43 | struct MyMapStrStrStruct { 44 | #[serde(with = "ser_map_str_any")] 45 | my_map: HashMap, 46 | } 47 | 48 | #[allow(unused)] 49 | #[derive(Serialize, Deserialize)] 50 | struct MySerStringStruct { 51 | #[serde(with = "ser_string")] 52 | my_string: String, 53 | } 54 | 55 | #[allow(unused)] 56 | #[derive(Serialize, Deserialize)] 57 | struct MySerB64Struct { 58 | #[serde(with = "ser_b64")] 59 | my_array: [u8; 32], 60 | } 61 | 62 | #[allow(unused)] 63 | #[derive(Serialize, Deserialize)] 64 | struct MySeqStrStruct { 65 | #[serde(with = "ser_seq_str")] 66 | my_vec: Vec, 67 | #[serde(with = "ser_seq_str")] 68 | my_hash_set: HashSet, 69 | } 70 | -------------------------------------------------------------------------------- /components/common/src/transform_pool.rs: -------------------------------------------------------------------------------- 1 | use futures::{Sink, SinkExt, Stream, StreamExt}; 2 | 3 | use crate::conn::FutTransform; 4 | 5 | #[derive(Debug)] 6 | pub enum TransformPoolLoopError {} 7 | 8 | /// Transform a stream of incoming items to outgoing items. 9 | /// The transformation is asynchronous, therefore outgoing items 10 | /// might not be in the same order in which the incoming items entered. 11 | /// 12 | /// max_concurrent is the maximum amount of concurrent transformations. 13 | pub async fn transform_pool_loop( 14 | incoming: I, 15 | outgoing: O, 16 | transform: T, 17 | max_concurrent: usize, 18 | ) -> Result<(), TransformPoolLoopError> 19 | where 20 | IN: Send + 'static, 21 | OUT: Send, 22 | T: FutTransform> + Clone + Send + 'static, 23 | I: Stream + Unpin, 24 | O: Sink + Clone + Send + Unpin + 'static, 25 | { 26 | incoming 27 | .for_each_concurrent(Some(max_concurrent), move |input_value| { 28 | let mut c_outgoing = outgoing.clone(); 29 | let mut c_transform = transform.clone(); 30 | async move { 31 | if let Some(output_value) = c_transform.transform(input_value).await { 32 | let _ = c_outgoing.send(output_value).await; 33 | } 34 | } 35 | }) 36 | .await; 37 | Ok(()) 38 | } 39 | 40 | // TODO: Add tests! 41 | 42 | /* 43 | 44 | #[derive(Debug)] 45 | pub enum TransformPoolError { 46 | SpawnError, 47 | } 48 | 49 | pub fn create_transform_pool(transform: T, 50 | max_concurrent: usize, 51 | mut spawner: S) 52 | -> Result<(mpsc::Sender, mpsc::Receiver), TransformPoolError> 53 | 54 | where 55 | IN: Send + 'static, 56 | OUT: Send + 'static, 57 | T: FutTransform> + Clone + Send + 'static, 58 | S: Spawn + Clone + Send + 'static, 59 | { 60 | let (input_sender, incoming) = mpsc::channel(0); 61 | let (outgoing, output_receiver) = mpsc::channel(0); 62 | 63 | let loop_fut = transform_pool_loop(incoming, 64 | outgoing, 65 | transform, 66 | max_concurrent, 67 | spawner.clone()) 68 | .map_err(|e| error!("transform_pool_loop() error: {:?}", e)) 69 | .map(|_| ()); 70 | 71 | spawner.spawn(loop_fut) 72 | .map_err(|_| TransformPoolError::SpawnError)?; 73 | 74 | Ok((input_sender, output_receiver)) 75 | } 76 | */ 77 | -------------------------------------------------------------------------------- /components/connection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-connection" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0" , package = "offset-signature" } 16 | net = { path = "../net", version = "0.1.0" , package = "offset-net" } 17 | keepalive = { path = "../keepalive", version="0.1.0", package = "offset-keepalive" } 18 | secure_channel = { path = "../secure_channel", version="0.1.0", package = "offset-secure-channel" } 19 | version = { path = "../version", version="0.1.0", package = "offset-version" } 20 | 21 | 22 | log = "0.4" 23 | simple_logger = "1.0.1" 24 | 25 | futures = "0.3.1" 26 | derive_more = "0.14.0" 27 | 28 | [dev-dependencies] 29 | 30 | futures = {version = "0.3.1", features = ["thread-pool"]} 31 | -------------------------------------------------------------------------------- /components/connection/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/connection/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | mod timeout; 14 | mod transforms; 15 | 16 | pub use self::transforms::{ 17 | create_encrypt_keepalive, create_secure_connector, create_version_encrypt_keepalive, 18 | }; 19 | -------------------------------------------------------------------------------- /components/connection/src/timeout.rs: -------------------------------------------------------------------------------- 1 | use futures::{future, select, FutureExt, StreamExt}; 2 | 3 | use common::conn::{BoxFuture, FutTransform}; 4 | use timer::TimerClient; 5 | 6 | /// A future transform's wrapper, adding timeout 7 | #[derive(Debug, Clone)] 8 | pub struct TimeoutFutTransform { 9 | fut_transform: FT, 10 | timer_client: TimerClient, 11 | timeout_ticks: usize, 12 | } 13 | 14 | impl TimeoutFutTransform { 15 | pub fn new(fut_transform: FT, timer_client: TimerClient, timeout_ticks: usize) -> Self { 16 | Self { 17 | fut_transform, 18 | timer_client, 19 | timeout_ticks, 20 | } 21 | } 22 | } 23 | 24 | impl FutTransform for TimeoutFutTransform 25 | where 26 | FT: FutTransform> + Send, 27 | I: Send + 'static, 28 | O: Send, 29 | { 30 | type Input = I; 31 | type Output = Option; 32 | 33 | fn transform(&mut self, input: Self::Input) -> BoxFuture<'_, Self::Output> { 34 | Box::pin(async move { 35 | let timer_stream = match self 36 | .timer_client 37 | .request_timer_stream("TimeoutFutTransform::transform".to_owned()) 38 | .await 39 | { 40 | Ok(timer_stream) => timer_stream, 41 | Err(e) => { 42 | error!("TimeoutTransform: request_timer_stream() error: {:?}", e); 43 | return None; 44 | } 45 | }; 46 | 47 | // A future that waits `timeout_ticks`: 48 | let fut_timeout = timer_stream 49 | .take(self.timeout_ticks) 50 | .for_each(|_| future::ready(())); 51 | let fut_output = self.fut_transform.transform(input); 52 | 53 | // Race execution of `fut_transform` against the timer: 54 | select! { 55 | _fut_timeout = fut_timeout.fuse() => None, 56 | fut_output = fut_output.fuse() => fut_output, 57 | } 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /components/crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-crypto" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | proto = { path = "../proto", version = "0.1.0", package = "offset-proto" } 12 | 13 | x25519-dalek = "0.6.0" 14 | ed25519-dalek = "1.0.0-pre.3" 15 | 16 | sha2 = "0.9.0" 17 | hkdf = "0.9.0-alpha.0" 18 | chacha20poly1305 = "0.5.1" 19 | 20 | 21 | serde = {version = "1.0.104", features = ["derive"]} 22 | bytes = "0.5.4" 23 | base64 = "0.9" 24 | 25 | derive_more = "0.14.0" 26 | 27 | # Quickcheck: 28 | quickcheck = {version = "0.9"} 29 | quickcheck_derive = {version = "0.2.1"} 30 | 31 | rand = "0.7.3" 32 | rand_core = "0.5.1" 33 | 34 | [dependencies.byteorder] 35 | version = "1.1" 36 | features = ["i128"] 37 | 38 | [dev-dependencies] 39 | -------------------------------------------------------------------------------- /components/crypto/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/crypto/src/error.rs: -------------------------------------------------------------------------------- 1 | use derive_more::*; 2 | 3 | #[derive(Clone, Copy, Debug, PartialEq, Display)] 4 | #[display(fmt = "crypto error")] 5 | pub struct CryptoError; 6 | -------------------------------------------------------------------------------- /components/crypto/src/hash.rs: -------------------------------------------------------------------------------- 1 | use proto::crypto::HashResult; 2 | use sha2::{Digest, Sha512Trunc256}; 3 | 4 | /// Calculate SHA512/256 over the given data. 5 | pub fn sha_512_256(data: &[u8]) -> HashResult { 6 | let mut hasher = Sha512Trunc256::new(); 7 | hasher.update(data); 8 | let digest_res = hasher.finalize(); 9 | 10 | let mut inner = [0x00; HashResult::len()]; 11 | inner.copy_from_slice(digest_res.as_ref()); 12 | 13 | HashResult::from(&inner) 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn hash_basic() { 22 | let data = b"This is a test!"; 23 | 24 | let hash_res = sha_512_256(&data[..]); 25 | 26 | let expected = [ 27 | 0x34, 0x9c, 0x7e, 0xa7, 0x49, 0x8d, 0x04, 0x32, 0xdc, 0xb0, 0x60, 0x4a, 0x9e, 0xd3, 28 | 0x7a, 0x8b, 0x65, 0xa9, 0x0b, 0xfa, 0x16, 0x6c, 0x91, 0x47, 0x5f, 0x07, 0x2a, 0x29, 29 | 0xe4, 0x2d, 0xa1, 0xfb, 30 | ]; 31 | 32 | assert_eq!(hash_res.as_ref(), expected); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /components/crypto/src/hash_lock.rs: -------------------------------------------------------------------------------- 1 | use sha2::{Digest, Sha512Trunc256}; 2 | 3 | use proto::crypto::{HashedLock, PlainLock}; 4 | 5 | pub trait HashLock { 6 | /// Lock the plain hash 7 | fn hash_lock(&self) -> HashedLock; 8 | } 9 | 10 | impl HashLock for PlainLock { 11 | // TODO: Use bcrypt instead here? (As suggested by @spolu) 12 | fn hash_lock(&self) -> HashedLock { 13 | let mut hashed_lock = HashedLock::default(); 14 | let inner = &mut hashed_lock; 15 | 16 | let mut hasher = Sha512Trunc256::new(); 17 | hasher.update(&self); 18 | let digest_res = hasher.finalize(); 19 | 20 | inner.copy_from_slice(digest_res.as_ref()); 21 | hashed_lock 22 | } 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | use proto::crypto::PlainLock; 30 | 31 | #[test] 32 | fn test_hash_lock_basic() { 33 | let plain_lock = PlainLock::from(&[1u8; PlainLock::len()]); 34 | let hashed_lock1 = plain_lock.hash_lock(); 35 | let hashed_lock2 = plain_lock.hash_lock(); 36 | assert_eq!(hashed_lock1, hashed_lock2); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /components/crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate common; 12 | #[macro_use] 13 | extern crate serde; 14 | 15 | pub mod dh; 16 | pub mod error; 17 | pub mod hash; 18 | pub mod hash_lock; 19 | pub mod identity; 20 | // pub mod nonce_window; 21 | pub mod rand; 22 | pub mod sym_encrypt; 23 | pub mod test_utils; 24 | -------------------------------------------------------------------------------- /components/crypto/src/test_utils.rs: -------------------------------------------------------------------------------- 1 | use rand::{self, rngs::StdRng, CryptoRng, RngCore}; 2 | use rand_core::impls; 3 | 4 | use crate::error::CryptoError; 5 | use crate::rand::CryptoRandom; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct DummyRandom { 9 | inner: StdRng, 10 | } 11 | 12 | impl DummyRandom { 13 | pub fn new(seed: &[u8]) -> Self { 14 | let mut rng_seed: [u8; 32] = [0; 32]; 15 | // We copy as many seed bytes as we have as seed into rng_seed 16 | // If seed.len() > 32, clone_from_slice will panic. 17 | rng_seed[..seed.len()].clone_from_slice(seed); 18 | let rng = rand::SeedableRng::from_seed(rng_seed); 19 | 20 | DummyRandom { inner: rng } 21 | } 22 | } 23 | 24 | impl RngCore for DummyRandom { 25 | fn next_u32(&mut self) -> u32 { 26 | impls::next_u32_via_fill(self) 27 | } 28 | 29 | fn next_u64(&mut self) -> u64 { 30 | impls::next_u64_via_fill(self) 31 | } 32 | 33 | fn fill_bytes(&mut self, dest: &mut [u8]) { 34 | // Rely on inner random generator: 35 | self.inner.fill_bytes(dest); 36 | } 37 | 38 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { 39 | self.fill_bytes(dest); 40 | Ok(()) 41 | } 42 | } 43 | 44 | impl CryptoRng for DummyRandom {} 45 | 46 | impl CryptoRandom for DummyRandom { 47 | fn fill(&mut self, dest: &mut [u8]) -> Result<(), CryptoError> { 48 | self.inner.fill_bytes(dest); 49 | Ok(()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /components/database/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-database" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | 12 | log = "0.4" 13 | futures = "0.3.1" 14 | im = "14.1.0" 15 | 16 | atomicwrites = "0.2.2" 17 | 18 | serde = {version = "1.0.104", features = ["derive"]} 19 | 20 | base64 = "0.9" 21 | # bincode = "1.1.2" 22 | serde_json = "1.0.44" 23 | 24 | [dev-dependencies] 25 | 26 | tempfile = "3.1.0" 27 | 28 | futures = {version = "0.3.1", features = ["thread-pool"]} 29 | -------------------------------------------------------------------------------- /components/database/src/atomic_db.rs: -------------------------------------------------------------------------------- 1 | /// An atomic database. Allows to batch a list of mutations, and guarantees to apply them to the 2 | /// database in an atomic manner. 3 | pub trait AtomicDb { 4 | type State; 5 | type Mutation; 6 | type Error; 7 | 8 | fn get_state(&self) -> &Self::State; 9 | fn mutate_db(&mut self, mutations: &[Self::Mutation]) -> Result<(), Self::Error>; 10 | } 11 | -------------------------------------------------------------------------------- /components/database/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[cfg(test)] 12 | #[macro_use] 13 | extern crate serde; 14 | 15 | mod atomic_db; 16 | mod database; 17 | pub mod file_db; 18 | 19 | pub use self::atomic_db::AtomicDb; 20 | pub use self::database::{database_loop, DatabaseClient, DatabaseClientError, DatabaseRequest}; 21 | -------------------------------------------------------------------------------- /components/funder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-funder" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | 9 | [dependencies] 10 | 11 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 12 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto"} 13 | identity = { path = "../identity", version = "0.1.0", package = "offset-identity" } 14 | proto = { path = "../proto", version = "0.1.0", package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0", package = "offset-signature" } 16 | database = { path = "../database", version = "0.1.0", package = "offset-database" } 17 | 18 | log = "0.4" 19 | pretty_env_logger = "0.2" 20 | 21 | bytes = "0.5.4" 22 | futures = "0.3.1" 23 | 24 | 25 | serde = {version = "1.0.104", features = ["derive"]} 26 | 27 | im = {version = "14.1.0", features = ["serde", "quickcheck"]} 28 | byteorder = {version = "1.1", features = ["i128"]} 29 | 30 | # Quickcheck: 31 | quickcheck = {version = "0.9"} 32 | quickcheck_macros = {version = "0.8"} 33 | quickcheck_derive = {version = "0.2.1"} 34 | rand = {version = "0.7.2"} 35 | 36 | [dev-dependencies] 37 | 38 | futures = {version = "0.3.1", features = ["thread-pool"]} 39 | -------------------------------------------------------------------------------- /components/funder/src/ephemeral.rs: -------------------------------------------------------------------------------- 1 | use super::liveness::{Liveness, LivenessMutation}; 2 | 3 | #[derive(Clone, Default)] 4 | pub struct Ephemeral { 5 | pub liveness: Liveness, 6 | } 7 | 8 | #[derive(Debug)] 9 | pub enum EphemeralMutation { 10 | LivenessMutation(LivenessMutation), 11 | } 12 | 13 | impl Ephemeral { 14 | pub fn new() -> Ephemeral { 15 | Ephemeral { 16 | liveness: Liveness::new(), 17 | } 18 | } 19 | 20 | pub fn mutate(&mut self, mutation: &EphemeralMutation) { 21 | match mutation { 22 | EphemeralMutation::LivenessMutation(liveness_mutation) => { 23 | self.liveness.mutate(liveness_mutation) 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /components/funder/src/handler/mod.rs: -------------------------------------------------------------------------------- 1 | mod canceler; 2 | mod handle_control; 3 | mod handle_friend; 4 | mod handle_init; 5 | mod handle_liveness; 6 | mod handler; 7 | mod prepare; 8 | mod sender; 9 | mod state_wrap; 10 | mod types; 11 | mod utils; 12 | 13 | #[cfg(test)] 14 | mod tests; 15 | 16 | pub use self::handler::{funder_handle_message, FunderHandlerError}; 17 | -------------------------------------------------------------------------------- /components/funder/src/handler/prepare.rs: -------------------------------------------------------------------------------- 1 | use crypto::hash; 2 | use proto::crypto::PlainLock; 3 | use proto::funder::messages::{ 4 | CollectSendFundsOp, Commit, Currency, PendingTransaction, Receipt, ResponseSendFundsOp, 5 | TransactionStage, 6 | }; 7 | 8 | pub fn prepare_receipt( 9 | currency: &Currency, 10 | collect_send_funds: &CollectSendFundsOp, 11 | response_send_funds: &ResponseSendFundsOp, 12 | pending_transaction: &PendingTransaction, 13 | ) -> Receipt { 14 | let mut hash_buff = Vec::new(); 15 | hash_buff.extend_from_slice(&pending_transaction.request_id); 16 | hash_buff.extend_from_slice(&response_send_funds.rand_nonce); 17 | let response_hash = hash::sha_512_256(&hash_buff); 18 | // = sha512/256(requestId || randNonce) 19 | 20 | let is_complete = match &pending_transaction.stage { 21 | TransactionStage::Response(_dest_hashed_lock, is_complete) => *is_complete, 22 | _ => unreachable!(), 23 | }; 24 | 25 | Receipt { 26 | response_hash, 27 | invoice_id: pending_transaction.invoice_id.clone(), 28 | currency: currency.clone(), 29 | src_plain_lock: collect_send_funds.src_plain_lock.clone(), 30 | dest_plain_lock: collect_send_funds.dest_plain_lock.clone(), 31 | is_complete, 32 | dest_payment: pending_transaction.dest_payment, 33 | total_dest_payment: pending_transaction.total_dest_payment, 34 | signature: response_send_funds.signature.clone(), 35 | } 36 | } 37 | 38 | /// Create a Commit (out of band) message given a ResponseSendFunds 39 | pub fn prepare_commit( 40 | currency: Currency, 41 | response_send_funds: &ResponseSendFundsOp, 42 | pending_transaction: &PendingTransaction, 43 | src_plain_lock: PlainLock, 44 | ) -> Commit { 45 | assert!(response_send_funds.is_complete); 46 | 47 | let mut hash_buff = Vec::new(); 48 | hash_buff.extend_from_slice(&pending_transaction.request_id); 49 | hash_buff.extend_from_slice(&response_send_funds.rand_nonce); 50 | let response_hash = hash::sha_512_256(&hash_buff); 51 | // = sha512/256(requestId || randNonce) 52 | 53 | Commit { 54 | response_hash, 55 | src_plain_lock, 56 | dest_hashed_lock: response_send_funds.dest_hashed_lock.clone(), 57 | dest_payment: pending_transaction.dest_payment, 58 | total_dest_payment: pending_transaction.total_dest_payment, 59 | invoice_id: pending_transaction.invoice_id.clone(), 60 | currency, 61 | signature: response_send_funds.signature.clone(), 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /components/funder/src/handler/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod change_address; 2 | mod pair_basic; 3 | mod pair_inconsistency; 4 | pub mod utils; 5 | -------------------------------------------------------------------------------- /components/funder/src/handler/tests/utils.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::hash::Hash; 3 | 4 | use identity::IdentityClient; 5 | 6 | use crypto::rand::CryptoRandom; 7 | use signature::canonical::CanonicalSerialize; 8 | 9 | use proto::app_server::messages::{NamedRelayAddress, RelayAddress}; 10 | use proto::crypto::PublicKey; 11 | use proto::funder::messages::FunderOutgoingControl; 12 | 13 | use crate::ephemeral::Ephemeral; 14 | use crate::handler::handler::{funder_handle_message, FunderHandlerError, FunderHandlerOutput}; 15 | use crate::state::FunderState; 16 | use crate::types::{FunderIncoming, FunderOutgoingComm}; 17 | 18 | const TEST_MAX_NODE_RELAYS: usize = 16; 19 | const TEST_MAX_OPERATIONS_IN_BATCH: usize = 16; 20 | const TEST_MAX_PENDING_USER_REQUESTS: usize = 16; 21 | 22 | /// A helper function to quickly create a dummy NamedRelayAddress. 23 | pub fn dummy_named_relay_address(index: u8) -> NamedRelayAddress { 24 | NamedRelayAddress { 25 | public_key: PublicKey::from(&[index; PublicKey::len()]), 26 | address: index as u32, 27 | name: format!("relay-{}", index), 28 | } 29 | } 30 | 31 | /// A helper function to quickly create a dummy RelayAddress. 32 | pub fn dummy_relay_address(index: u8) -> RelayAddress { 33 | dummy_named_relay_address(index).into() 34 | } 35 | 36 | /// A helper function. Applies an incoming funder message, updating state and ephemeral 37 | /// accordingly: 38 | pub async fn apply_funder_incoming<'a, B, R>( 39 | funder_incoming: FunderIncoming, 40 | state: &'a mut FunderState, 41 | ephemeral: &'a mut Ephemeral, 42 | rng: &'a mut R, 43 | identity_client: &'a mut IdentityClient, 44 | ) -> Result<(Vec>, Vec>), FunderHandlerError> 45 | where 46 | B: Clone + PartialEq + Eq + CanonicalSerialize + Debug + Hash + 'a, 47 | R: CryptoRandom + 'a, 48 | { 49 | let funder_handler_output = funder_handle_message( 50 | identity_client, 51 | rng, 52 | state.clone(), 53 | ephemeral.clone(), 54 | TEST_MAX_NODE_RELAYS, 55 | TEST_MAX_OPERATIONS_IN_BATCH, 56 | TEST_MAX_PENDING_USER_REQUESTS, 57 | funder_incoming, 58 | ) 59 | .await?; 60 | 61 | let FunderHandlerOutput { 62 | ephemeral_mutations, 63 | funder_mutations, 64 | outgoing_comms, 65 | outgoing_control, 66 | } = funder_handler_output; 67 | 68 | // Mutate FunderState according to the mutations: 69 | for mutation in &funder_mutations { 70 | state.mutate(mutation); 71 | } 72 | 73 | // Mutate Ephemeral according to the mutations: 74 | for mutation in &ephemeral_mutations { 75 | ephemeral.mutate(mutation); 76 | } 77 | 78 | Ok((outgoing_comms, outgoing_control)) 79 | } 80 | -------------------------------------------------------------------------------- /components/funder/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![cfg_attr(not(feature = "cargo-clippy"), allow(unknown_lints))] 3 | #![deny(trivial_numeric_casts, warnings)] 4 | #![allow(intra_doc_link_resolution_failure)] 5 | #![allow( 6 | clippy::too_many_arguments, 7 | clippy::implicit_hasher, 8 | clippy::module_inception, 9 | clippy::new_without_default 10 | )] 11 | 12 | #[macro_use] 13 | extern crate log; 14 | 15 | #[macro_use] 16 | extern crate serde; 17 | 18 | #[macro_use] 19 | extern crate quickcheck_derive; 20 | 21 | mod ephemeral; 22 | mod friend; 23 | mod funder; 24 | mod handler; 25 | mod liveness; 26 | mod mutual_credit; 27 | pub mod report; 28 | mod state; 29 | mod token_channel; 30 | pub mod types; 31 | 32 | #[cfg(test)] 33 | mod tests; 34 | 35 | pub use self::funder::{funder_loop, FunderError}; 36 | pub use self::state::{FunderMutation, FunderState}; 37 | -------------------------------------------------------------------------------- /components/funder/src/mutual_credit/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod incoming; 2 | pub mod outgoing; 3 | #[cfg(test)] 4 | mod tests; 5 | pub mod types; 6 | -------------------------------------------------------------------------------- /components/funder/src/tests/funder_error_command.rs: -------------------------------------------------------------------------------- 1 | use common::test_executor::TestExecutor; 2 | 3 | use proto::crypto::PublicKey; 4 | use proto::funder::messages::FriendStatus; 5 | 6 | use super::utils::{create_node_controls, dummy_relay_address}; 7 | 8 | async fn task_funder_error_command(test_executor: TestExecutor) { 9 | let num_nodes = 2; 10 | let mut node_controls = create_node_controls(num_nodes, test_executor.clone()).await; 11 | 12 | let public_keys = node_controls 13 | .iter() 14 | .map(|nc| nc.public_key.clone()) 15 | .collect::>(); 16 | 17 | let relays0 = vec![dummy_relay_address(0)]; 18 | let relays1 = vec![dummy_relay_address(1)]; 19 | node_controls[0] 20 | .add_friend(&public_keys[1], relays1, "node1") 21 | .await; 22 | node_controls[1] 23 | .add_friend(&public_keys[0], relays0, "node0") 24 | .await; 25 | assert_eq!(node_controls[0].report.friends.len(), 1); 26 | assert_eq!(node_controls[1].report.friends.len(), 1); 27 | 28 | // This command should cause an error, because node0 is not friend of itself. 29 | // We expect that the Funder will be able to handle this error, and not crash: 30 | node_controls[0] 31 | .set_friend_status(&public_keys[0], FriendStatus::Enabled) 32 | .await; 33 | 34 | // This command should work correctly: 35 | node_controls[0] 36 | .set_friend_status(&public_keys[1], FriendStatus::Enabled) 37 | .await; 38 | } 39 | 40 | #[test] 41 | fn test_funder_error_command() { 42 | let test_executor = TestExecutor::new(); 43 | let res = test_executor.run(task_funder_error_command(test_executor.clone())); 44 | assert!(res.is_output()); 45 | } 46 | -------------------------------------------------------------------------------- /components/funder/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod funder_basic; 2 | mod funder_error_command; 3 | mod funder_forward_payment; 4 | mod funder_inconsistency_basic; 5 | mod funder_payment_failure; 6 | 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /components/identity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-identity" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0" , package = "offset-crypto"} 12 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto"} 13 | 14 | futures = "0.3.1" 15 | 16 | [dev-dependencies] 17 | 18 | -------------------------------------------------------------------------------- /components/identity/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/identity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | extern crate futures; 12 | 13 | mod client; 14 | mod identity; 15 | mod messages; 16 | 17 | pub use crate::client::{IdentityClient, IdentityClientError}; 18 | pub use crate::identity::create_identity; 19 | -------------------------------------------------------------------------------- /components/identity/src/messages.rs: -------------------------------------------------------------------------------- 1 | use futures::channel::oneshot; 2 | 3 | use proto::crypto::{PublicKey, Signature}; 4 | 5 | /// The response from security module client to security module. 6 | #[derive(Debug)] 7 | pub enum ToIdentity { 8 | /// Request to sign a message. 9 | RequestSignature { 10 | message: Vec, 11 | response_sender: oneshot::Sender, 12 | }, 13 | /// Request the identity public key. 14 | RequestPublicKey { 15 | response_sender: oneshot::Sender, 16 | }, 17 | } 18 | 19 | /// Return requested signature over a message 20 | #[derive(Debug)] 21 | pub struct ResponseSignature { 22 | pub signature: Signature, 23 | } 24 | 25 | /// Return the identity public key. 26 | #[derive(Debug)] 27 | pub struct ResponsePublicKey { 28 | pub public_key: PublicKey, 29 | } 30 | -------------------------------------------------------------------------------- /components/index_client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-index-client" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0" , package = "offset-signature" } 16 | database = { path = "../database", version = "0.1.0", package = "offset-database" } 17 | 18 | log = "0.4" 19 | # TODO: How to make sure this is only imported in tests? 20 | env_logger = "0.6.0" 21 | futures = "0.3.1" 22 | 23 | serde = {version = "1.0.104", features = ["derive"]} 24 | 25 | # Quickcheck: 26 | quickcheck = {version = "0.9"} 27 | quickcheck_macros = {version = "0.8"} 28 | quickcheck_derive = {version = "0.2.1"} 29 | rand = {version = "0.7.2"} 30 | 31 | [dev-dependencies] 32 | 33 | futures = {version = "0.3.1", features = ["thread-pool"]} 34 | -------------------------------------------------------------------------------- /components/index_client/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate serde; 16 | 17 | #[macro_use] 18 | extern crate quickcheck_derive; 19 | 20 | #[macro_use] 21 | extern crate common; 22 | 23 | mod client_session; 24 | mod index_client; 25 | mod seq_friends; 26 | mod seq_map; 27 | mod single_client; 28 | mod spawn; 29 | 30 | #[cfg(test)] 31 | mod tests; 32 | 33 | pub use self::index_client::{IndexClientConfig, IndexClientConfigMutation, IndexClientError}; 34 | pub use self::spawn::{spawn_index_client, SpawnIndexClientError}; 35 | -------------------------------------------------------------------------------- /components/index_server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-index-server" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0" , package = "offset-signature" } 16 | 17 | log = "0.4" 18 | # TODO: How to make sure this is only imported in tests? 19 | env_logger = "0.6.0" 20 | 21 | futures = "0.3.1" 22 | 23 | [dev-dependencies] 24 | 25 | futures = {version = "0.3.1", features = ["thread-pool"]} 26 | -------------------------------------------------------------------------------- /components/index_server/src/graph/mod.rs: -------------------------------------------------------------------------------- 1 | mod bfs; 2 | pub mod capacity_graph; 3 | pub mod graph_service; 4 | pub mod simple_capacity_graph; 5 | mod utils; 6 | 7 | #[cfg(test)] 8 | mod test_utils; 9 | -------------------------------------------------------------------------------- /components/index_server/src/graph/test_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::graph::capacity_graph::LinearRate; 2 | 3 | /// A contant rate, used for testing 4 | #[derive(Debug, Clone, PartialEq, Eq)] 5 | pub struct ConstRate(pub u32); 6 | 7 | #[cfg(test)] 8 | impl LinearRate for ConstRate { 9 | type K = u32; 10 | 11 | fn zero() -> Self { 12 | ConstRate(0) 13 | } 14 | 15 | fn calc_fee(&self, _k: Self::K) -> Option { 16 | Some(self.0) 17 | } 18 | 19 | fn checked_add(&self, other: &Self) -> Option { 20 | Some(ConstRate(self.0.checked_add(other.0)?)) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/index_server/src/graph/utils.rs: -------------------------------------------------------------------------------- 1 | /// An iterator that wraps an optional iterator. 2 | /// If the optional iterator exists, OptionIterator will behave exactly like the underlying 3 | /// iterator. Otherwise, it will immediately return None. 4 | /// 5 | /// This iterator is useful for cases where we want a function to be able to either return an 6 | /// Iterator, or an empty Iterator, and those two iterators must be of the same type. Useful for 7 | /// functions that return `impl Iterator<...>`. 8 | pub struct OptionIterator { 9 | opt_iterator: Option, 10 | } 11 | 12 | impl Iterator for OptionIterator 13 | where 14 | I: Iterator, 15 | { 16 | type Item = T; 17 | fn next(&mut self) -> Option { 18 | match &mut self.opt_iterator { 19 | Some(iterator) => iterator.next(), 20 | None => None, 21 | } 22 | } 23 | } 24 | 25 | impl OptionIterator { 26 | pub fn new(opt_iterator: Option) -> OptionIterator { 27 | OptionIterator { opt_iterator } 28 | } 29 | } 30 | 31 | /// Util function to convert Option to Vec. 32 | /// Some(t) => vec![t], None => vec![] 33 | pub fn option_to_vec(opt_t: Option) -> Vec { 34 | match opt_t { 35 | Some(t) => vec![t], 36 | None => vec![], 37 | } 38 | } 39 | 40 | // TODO: add tests 41 | -------------------------------------------------------------------------------- /components/index_server/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate common; 16 | 17 | mod backoff_connector; 18 | mod graph; 19 | mod server; 20 | mod server_loop; 21 | mod verifier; 22 | 23 | pub use server::{index_server, IndexServerError}; 24 | -------------------------------------------------------------------------------- /components/index_server/src/server.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt::Debug; 3 | use std::marker::Unpin; 4 | 5 | use futures::task::Spawn; 6 | use futures::Stream; 7 | 8 | use common::conn::FutTransform; 9 | 10 | use proto::crypto::PublicKey; 11 | 12 | use timer::TimerClient; 13 | 14 | use crypto::identity::compare_public_key; 15 | use crypto::rand::CryptoRandom; 16 | 17 | use crate::server_loop::{server_loop, ClientConn, ServerConn, ServerLoopError}; 18 | 19 | use crate::backoff_connector::BackoffConnector; 20 | use crate::graph::graph_service::create_graph_service; 21 | use crate::graph::simple_capacity_graph::SimpleCapacityGraph; 22 | use crate::verifier::simple_verifier::SimpleVerifier; 23 | 24 | #[derive(Debug)] 25 | pub enum IndexServerError { 26 | RequestTimerStreamError, 27 | CreateGraphServiceError, 28 | ServerLoopError(ServerLoopError), 29 | } 30 | 31 | /// Run an index server 32 | /// Will keep running until an error occurs. 33 | pub async fn index_server( 34 | local_public_key: PublicKey, 35 | trusted_servers: HashMap, 36 | incoming_server_connections: IS, 37 | incoming_client_connections: IC, 38 | server_connector: SC, 39 | mut timer_client: TimerClient, 40 | ticks_to_live: usize, 41 | backoff_ticks: usize, 42 | rng: R, 43 | graph_service_spawner: GS, 44 | spawner: S, 45 | ) -> Result<(), IndexServerError> 46 | where 47 | A: Debug + Send + Sync + Clone + 'static, 48 | IS: Stream + Unpin + Send, 49 | IC: Stream + Unpin + Send, 50 | SC: FutTransform> + Clone + Send + 'static, 51 | R: CryptoRandom, 52 | S: Spawn + Clone + Send, 53 | GS: Spawn + Send + 'static, 54 | { 55 | let verifier = SimpleVerifier::new(ticks_to_live, rng); 56 | 57 | let graph_client = create_graph_service::<_, _, _, _, SimpleCapacityGraph<_, _>, _, _>( 58 | graph_service_spawner, 59 | spawner.clone(), 60 | ) 61 | .map_err(|_| IndexServerError::CreateGraphServiceError)?; 62 | 63 | let timer_stream = timer_client 64 | .request_timer_stream("index_server".to_owned()) 65 | .await 66 | .map_err(|_| IndexServerError::RequestTimerStreamError)?; 67 | 68 | let backoff_connector = BackoffConnector::new(server_connector, timer_client, backoff_ticks); 69 | 70 | server_loop( 71 | local_public_key, 72 | trusted_servers, 73 | incoming_server_connections, 74 | incoming_client_connections, 75 | backoff_connector, 76 | graph_client, 77 | compare_public_key, 78 | verifier, 79 | timer_stream, 80 | spawner, 81 | None, 82 | ) 83 | .await 84 | .map_err(IndexServerError::ServerLoopError) 85 | } 86 | -------------------------------------------------------------------------------- /components/index_server/src/verifier/dummy_verifier.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use super::verifier::Verifier; 4 | use proto::crypto::HashResult; 5 | 6 | pub struct DummyVerifier { 7 | phantom_n: PhantomData, 8 | phantom_b: PhantomData, 9 | phantom_u: PhantomData, 10 | hash_vec: Vec, 11 | } 12 | 13 | impl DummyVerifier { 14 | #[allow(unused)] 15 | pub fn new() -> Self { 16 | Self { 17 | phantom_n: PhantomData, 18 | phantom_b: PhantomData, 19 | phantom_u: PhantomData, 20 | // verify() method requires to return a borrowed slice, therefore 21 | // we need to keep a real vector: 22 | hash_vec: vec![ 23 | HashResult::from(&[0; HashResult::len()]), 24 | HashResult::from(&[1; HashResult::len()]), 25 | HashResult::from(&[2; HashResult::len()]), 26 | ], 27 | } 28 | } 29 | } 30 | 31 | impl Verifier for DummyVerifier { 32 | type Node = N; 33 | type Neighbor = B; 34 | type SessionId = U; 35 | 36 | fn verify( 37 | &mut self, 38 | _origin_tick_hash: &HashResult, 39 | _expansion_chain: &[&[HashResult]], 40 | _node: &N, 41 | _session_id: &U, 42 | _counter: u64, 43 | ) -> Option<&[HashResult]> { 44 | // Everything is successfully verified: 45 | Some(&self.hash_vec) 46 | } 47 | 48 | fn tick(&mut self) -> (HashResult, Vec) { 49 | // Nothing happens. Always the same tick. 50 | (HashResult::from(&[0; HashResult::len()]), Vec::new()) 51 | } 52 | 53 | fn neighbor_tick(&mut self, _neighbor: B, _tick_hash: HashResult) -> Option { 54 | // Nothing happens 55 | None 56 | } 57 | 58 | fn remove_neighbor(&mut self, _neighbor: &B) -> Option { 59 | // Nothing happens 60 | None 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /components/index_server/src/verifier/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | pub mod dummy_verifier; 3 | mod hash_clock; 4 | mod ratchet; 5 | pub mod simple_verifier; 6 | mod verifier; 7 | 8 | pub use self::verifier::Verifier; 9 | -------------------------------------------------------------------------------- /components/index_server/src/verifier/verifier.rs: -------------------------------------------------------------------------------- 1 | use proto::crypto::HashResult; 2 | 3 | pub trait Verifier { 4 | type Node; 5 | type Neighbor; 6 | type SessionId; 7 | 8 | /// Verify an incoming message: 9 | /// - Checks freshness using a chain of time hashes. 10 | /// - Making sure that the message is not out of order using a ratchet counter. 11 | fn verify( 12 | &mut self, 13 | origin_tick_hash: &HashResult, 14 | expansion_chain: &[&[HashResult]], 15 | node: &Self::Node, 16 | session_id: &Self::SessionId, 17 | counter: u64, 18 | ) -> Option<&[HashResult]>; 19 | 20 | /// One time tick. Returns a `tick_hash` representing the local current time, 21 | /// and a vector of all the nodes removed due to timeout 22 | fn tick(&mut self) -> (HashResult, Vec); 23 | // TODO: Can we change to &HashResult? Should we? 24 | 25 | /// Process a time tick from a neighbor. This information is used when producing a `tick_hash`. 26 | fn neighbor_tick( 27 | &mut self, 28 | neighbor: Self::Neighbor, 29 | tick_hash: HashResult, 30 | ) -> Option; 31 | 32 | /// Remove a neighbor. This method should be invoked when a neighbor disconnects. 33 | /// If not called, the time proofs (list of hashes) will be larger than needed. 34 | fn remove_neighbor(&mut self, neighbor: &Self::Neighbor) -> Option; 35 | } 36 | -------------------------------------------------------------------------------- /components/keepalive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-keepalive" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 13 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 14 | 15 | log = "0.4" 16 | futures = "0.3.1" 17 | derive_more = "0.15.0" 18 | 19 | [dev-dependencies] 20 | 21 | futures = {version = "0.3.1", features = ["thread-pool"]} 22 | -------------------------------------------------------------------------------- /components/keepalive/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/keepalive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate common; 16 | 17 | mod keepalive; 18 | 19 | pub use self::keepalive::KeepAliveChannel; 20 | -------------------------------------------------------------------------------- /components/lockfile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-lockfile" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | cluFlock = "1.2.5" 11 | 12 | [dev-dependencies] 13 | 14 | tempfile = "3.1.0" 15 | -------------------------------------------------------------------------------- /components/lockfile/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/lockfile/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | mod lockfile; 12 | 13 | pub use lockfile::{try_lock_file, LockFileError, LockFileHandle}; 14 | -------------------------------------------------------------------------------- /components/mutual_from/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-mutual-from" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | 13 | quote = "0.6.12" 14 | syn = "0.15.38" 15 | proc-macro2 = "0.4" 16 | 17 | 18 | -------------------------------------------------------------------------------- /components/mutual_from/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/mutual_from/tests/tests.rs: -------------------------------------------------------------------------------- 1 | use offset_mutual_from::mutual_from; 2 | 3 | #[derive(PartialEq, Eq, Clone, Debug)] 4 | struct Hello1 { 5 | a: u32, 6 | b: String, 7 | } 8 | 9 | #[mutual_from(Hello1)] 10 | #[derive(PartialEq, Eq, Clone, Debug)] 11 | struct Hello2 { 12 | a: u32, 13 | b: String, 14 | } 15 | 16 | #[test] 17 | fn test_mutual_from_named_struct() { 18 | let hello1 = Hello1 { 19 | a: 0u32, 20 | b: "some_string".to_owned(), 21 | }; 22 | let hello2 = Hello2::from(hello1.clone()); 23 | let hello1_new = Hello1::from(hello2.clone()); 24 | let hello2_new = Hello2::from(hello1_new.clone()); 25 | 26 | assert_eq!(hello1, hello1_new); 27 | assert_eq!(hello2, hello2_new); 28 | } 29 | 30 | #[derive(PartialEq, Eq, Clone, Debug)] 31 | struct MyStruct1(u32, u32); 32 | 33 | #[mutual_from(MyStruct1)] 34 | #[derive(PartialEq, Eq, Clone, Debug)] 35 | struct MyStruct2(u32, u32); 36 | 37 | #[test] 38 | fn test_mutual_from_unnamed_struct() { 39 | let my_struct1 = MyStruct1(1u32, 2u32); 40 | let my_struct2 = MyStruct2::from(my_struct1.clone()); 41 | let my_struct1_new = MyStruct1::from(my_struct2.clone()); 42 | let my_struct2_new = MyStruct2::from(my_struct1.clone()); 43 | 44 | assert_eq!(my_struct1, my_struct1_new); 45 | assert_eq!(my_struct2, my_struct2_new); 46 | } 47 | 48 | #[derive(PartialEq, Eq, Clone, Debug)] 49 | struct World1; 50 | 51 | #[mutual_from(World1)] 52 | #[derive(PartialEq, Eq, Clone, Debug)] 53 | struct World2; 54 | 55 | #[test] 56 | fn test_mutual_from_unit_struct() { 57 | let world1 = World1; 58 | let world2 = World2::from(world1.clone()); 59 | let world1_new = World1::from(world2.clone()); 60 | let world2_new = World2::from(world1_new.clone()); 61 | 62 | assert_eq!(world1, world1_new); 63 | assert_eq!(world2, world2_new); 64 | } 65 | -------------------------------------------------------------------------------- /components/net/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-net" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 12 | 13 | futures = "0.3.1" 14 | futures_codec = "0.4.0" 15 | async-std = "1.6.2" 16 | 17 | log = "0.4" 18 | 19 | bytes = "0.5.4" 20 | 21 | [dev-dependencies] 22 | 23 | env_logger = "0.6.0" 24 | 25 | futures = { version = "0.3.1", features = ["thread-pool"] } 26 | -------------------------------------------------------------------------------- /components/net/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/net/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | mod tcp_connector; 15 | mod tcp_listener; 16 | #[cfg(test)] 17 | mod tests; 18 | mod types; 19 | mod utils; 20 | 21 | pub use self::tcp_connector::TcpConnector; 22 | pub use self::tcp_listener::TcpListener; 23 | -------------------------------------------------------------------------------- /components/net/src/tcp_connector.rs: -------------------------------------------------------------------------------- 1 | use common::conn::{BoxFuture, ConnPairVec, FutTransform}; 2 | 3 | use futures::task::Spawn; 4 | 5 | // use std::net::SocketAddr; 6 | use async_std::net::TcpStream; 7 | 8 | use proto::net::messages::NetAddress; 9 | 10 | use crate::utils::tcp_stream_to_conn_pair; 11 | 12 | #[derive(Debug, Clone)] 13 | pub struct TcpConnector { 14 | max_frame_length: usize, 15 | spawner: S, 16 | } 17 | 18 | impl TcpConnector { 19 | pub fn new(max_frame_length: usize, spawner: S) -> Self { 20 | TcpConnector { 21 | max_frame_length, 22 | spawner, 23 | } 24 | } 25 | } 26 | 27 | impl FutTransform for TcpConnector 28 | where 29 | S: Spawn + Send, 30 | { 31 | type Input = NetAddress; 32 | type Output = Option; 33 | 34 | fn transform(&mut self, net_address: Self::Input) -> BoxFuture<'_, Self::Output> { 35 | Box::pin(async move { 36 | info!("TcpConnector: Connecting to {:?}", net_address.as_str()); 37 | let tcp_stream = TcpStream::connect(net_address.as_str()).await.ok()?; 38 | 39 | Some(tcp_stream_to_conn_pair( 40 | tcp_stream, 41 | self.max_frame_length, 42 | &mut self.spawner, 43 | )) 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /components/net/src/types.rs: -------------------------------------------------------------------------------- 1 | /* 2 | use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; 3 | use proto::net::messages::{TcpAddress, TcpAddressV4, TcpAddressV6}; 4 | 5 | /// Convert offset's TcpAddress to SocketAddr 6 | pub fn tcp_address_to_socket_addr(tcp_address: &TcpAddress) -> SocketAddr { 7 | match tcp_address { 8 | TcpAddress::V4(tcp_address_v4) => { 9 | let octets = &tcp_address_v4.octets; 10 | let ipv4_addr = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); 11 | SocketAddr::new(IpAddr::V4(ipv4_addr), tcp_address_v4.port) 12 | }, 13 | TcpAddress::V6(tcp_address_v6) => { 14 | let segments = &tcp_address_v6.segments; 15 | let ipv4_addr = Ipv6Addr::new(segments[0], segments[1], segments[2], segments[3], 16 | segments[4], segments[5], segments[6], segments[7]); 17 | SocketAddr::new(IpAddr::V6(ipv4_addr), tcp_address_v6.port) 18 | }, 19 | } 20 | } 21 | 22 | 23 | /// Convert SocketAddr to offset's TcpAddress 24 | pub fn socket_addr_to_tcp_address(socket_addr: &SocketAddr) -> TcpAddress { 25 | let port = socket_addr.port(); 26 | match socket_addr.ip() { 27 | IpAddr::V4(ipv4_addr) => { 28 | let tcp_address_v4 = TcpAddressV4 { 29 | octets: ipv4_addr.octets().clone(), 30 | port, 31 | }; 32 | TcpAddress::V4(tcp_address_v4) 33 | }, 34 | IpAddr::V6(ipv6_addr) => { 35 | let tcp_address_v6 = TcpAddressV6 { 36 | segments: ipv6_addr.segments().clone(), 37 | port, 38 | }; 39 | TcpAddress::V6(tcp_address_v6) 40 | }, 41 | } 42 | } 43 | */ 44 | -------------------------------------------------------------------------------- /components/net/src/utils.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | 3 | use futures::channel::mpsc; 4 | use futures::task::{Spawn, SpawnExt}; 5 | use futures::{future, SinkExt, StreamExt}; 6 | use futures_codec::{Framed, LengthCodec}; 7 | 8 | use async_std::net::TcpStream; 9 | 10 | use common::conn::ConnPairVec; 11 | 12 | // TODO: Maybe all the logic here of ensuring closing is not required after this fix in async-std: 13 | // https://github.com/async-rs/async-std/issues/599 14 | // Check if we can simplify logic here. 15 | pub fn tcp_stream_to_conn_pair( 16 | tcp_stream: TcpStream, 17 | _max_frame_length: usize, 18 | spawner: &mut S, 19 | ) -> ConnPairVec 20 | where 21 | S: Spawn + Send, 22 | { 23 | // TODO: Return support for max_frame_length 24 | let codec = LengthCodec; 25 | // codec.set_max_frame_length(max_frame_length); 26 | let (sender, receiver) = Framed::new(tcp_stream, codec).split(); 27 | 28 | // Conversion layer between Vec to Bytes: 29 | let mut vec_sender = 30 | sender 31 | .sink_map_err(|_| ()) 32 | .with(|vec: Vec| -> future::Ready> { 33 | future::ready(Ok(Bytes::from(vec))) 34 | }); 35 | 36 | let vec_receiver = receiver 37 | .take_while(|res| future::ready(res.is_ok())) 38 | .map(|res| res.unwrap().to_vec()); 39 | 40 | // Add a mechanism to make sure that the connection is dropped when we drop the sender. 41 | // Not fully sure why this doesn't happen automatically. 42 | let (user_sender, user_sender_receiver) = mpsc::channel(0); 43 | let (mut user_receiver_sender, user_receiver) = mpsc::channel(0); 44 | 45 | let receiver_task = spawner 46 | .spawn_with_handle(async move { 47 | let _ = user_receiver_sender 48 | .send_all(&mut vec_receiver.map(Ok)) 49 | .await; 50 | }) 51 | .unwrap(); 52 | 53 | spawner 54 | .spawn(async move { 55 | let _ = vec_sender.send_all(&mut user_sender_receiver.map(Ok)).await; 56 | drop(receiver_task); 57 | }) 58 | .unwrap(); 59 | 60 | ConnPairVec::from_raw(user_sender, user_receiver) 61 | } 62 | -------------------------------------------------------------------------------- /components/node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-node" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | signature = { path = "../signature", version = "0.1.0" , package = "offset-signature" } 16 | database = { path = "../database", version = "0.1.0" , package = "offset-database" } 17 | funder = { path = "../funder", version = "0.1.0" , package = "offset-funder" } 18 | index_client = { path = "../index_client", version = "0.1.0" , package = "offset-index-client" } 19 | app_server = { path = "../app_server", version = "0.1.0" , package = "offset-app-server" } 20 | channeler = { path = "../channeler", version = "0.1.0" , package = "offset-channeler" } 21 | relay = { path = "../relay", version = "0.1.0" , package = "offset-relay" } 22 | net = { path = "../net", version = "0.1.0" , package = "offset-net" } 23 | 24 | 25 | log = "0.4" 26 | futures = "0.3.1" 27 | serde = {version = "1.0.104", features = ["derive"]} 28 | 29 | derive_more = "0.14.0" 30 | 31 | # Quickcheck: 32 | quickcheck = {version = "0.9"} 33 | quickcheck_macros = {version = "0.8"} 34 | quickcheck_derive = {version = "0.2.1"} 35 | rand = {version = "0.7.2"} 36 | -------------------------------------------------------------------------------- /components/node/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate serde; 16 | 17 | #[macro_use] 18 | extern crate quickcheck_derive; 19 | 20 | mod node; 21 | mod types; 22 | 23 | pub use self::node::{node, NodeError}; 24 | pub use self::types::{NodeConfig, NodeMutation, NodeState}; 25 | pub use app_server::{ConnPairServer, IncomingAppConnection}; 26 | -------------------------------------------------------------------------------- /components/proto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-proto" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | build = "build.rs" 7 | edition = "2018" 8 | 9 | [dependencies] 10 | 11 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 12 | offset-mutual-from = { path = "../mutual_from", version = "0.1.0"} 13 | capnp_conv = { path = "../capnp_conv", version = "0.1.0", package = "offset-capnp-conv" } 14 | 15 | capnp = "0.10.0" 16 | 17 | byteorder = "1.1" 18 | 19 | serde = { version = "1.0.104", features = ["derive"] } 20 | 21 | serde_json = "1.0.44" 22 | bytes = "0.5.4" 23 | # toml = "0.4.10" 24 | base64 = "0.10.1" 25 | 26 | im = {version = "14.1.0", features = ["serde", "quickcheck"]} 27 | 28 | derive_more = "0.14.0" 29 | 30 | num-bigint = "0.2.2" 31 | num-traits = "0.2.6" 32 | 33 | paste = "0.1.5" 34 | 35 | # Quickcheck: 36 | quickcheck = {version = "0.9"} 37 | quickcheck_derive = {version = "0.2.1"} 38 | rand = {version = "0.7.2"} 39 | 40 | [dev-dependencies] 41 | tempfile = "3.1.0" 42 | 43 | [build-dependencies] 44 | capnpc = "0.10.0" 45 | -------------------------------------------------------------------------------- /components/proto/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/proto/build.rs: -------------------------------------------------------------------------------- 1 | macro_rules! build_schema { 2 | ($($path: expr),*) => { 3 | capnpc::CompilerCommand::new() 4 | .src_prefix("src/") 5 | $(.file($path))* 6 | .run() 7 | .unwrap(); 8 | }; 9 | } 10 | 11 | fn main() { 12 | build_schema! { 13 | "src/schema/common.capnp", 14 | "src/schema/funder.capnp", 15 | "src/schema/dh.capnp", 16 | "src/schema/relay.capnp", 17 | "src/schema/keepalive.capnp", 18 | "src/schema/app_server.capnp", 19 | "src/schema/report.capnp", 20 | "src/schema/index.capnp" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/proto/src/app_server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/consts.rs: -------------------------------------------------------------------------------- 1 | /// The current protocol version 2 | pub const PROTOCOL_VERSION: u32 = 0; 3 | 4 | /// Maximum amount of friend operations sent in one move token message. 5 | pub const MAX_OPERATIONS_IN_BATCH: usize = 16; 6 | 7 | /// Maximum length of route used to pass credit. 8 | pub const MAX_ROUTE_LEN: usize = 32; 9 | 10 | /// Maximum length for a name of a currency. 11 | pub const MAX_CURRENCY_LEN: usize = 16; 12 | 13 | // TODO: Possibly convert TICK_MS to be u64? 14 | /// Amount of milliseconds in one tick: 15 | pub const TICK_MS: usize = 1000; 16 | 17 | /// Amount of ticks to wait before rekeying a secure channel. 18 | pub const TICKS_TO_REKEY: usize = 60 * 60 * (1000 / TICK_MS); // 1 hour 19 | 20 | /// If no message was sent for this amount of ticks, the connection will be closed 21 | pub const KEEPALIVE_TICKS: usize = 0x20; 22 | 23 | /// Relay server: The amount of ticks to wait before a relay connection from a client 24 | /// sends identification of which type of connection it is. 25 | pub const RELAY_CONN_TIMEOUT_TICKS: usize = 4; 26 | 27 | /// The stream TCP connection is split into prefix length frames. This is the maximum allowed 28 | /// length for such frame, measured in bytes. 29 | pub const MAX_FRAME_LENGTH: usize = 1 << 20; // 1[MB] 30 | 31 | /// Index server: The amount of ticks it takes for an idle node to be removed from the 32 | /// index server database. 33 | pub const INDEX_NODE_TIMEOUT_TICKS: usize = 60 * (1000 / TICK_MS); // 1 minute 34 | 35 | /// Maximum length for an address string used in NetAddress 36 | pub const MAX_NET_ADDRESS_LENGTH: usize = 256; 37 | 38 | /// Maximum amount of relays a node may use. 39 | /// We limit this number because sending many relays in a single move token message 40 | /// might exceed frame length 41 | pub const MAX_NODE_RELAYS: usize = 16; 42 | -------------------------------------------------------------------------------- /components/proto/src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | 3 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 4 | 5 | use serde::{Deserialize, Serialize}; 6 | 7 | use capnp_conv::{CapnpConvError, ReadCapnp, WriteCapnp}; 8 | 9 | use common::big_array::BigArray; 10 | use common::define_fixed_bytes; 11 | 12 | use crate::common_capnp; 13 | 14 | #[macro_use] 15 | mod serialize; 16 | 17 | // use self::serialize::{type_capnp_serde128, type_capnp_serde256, type_capnp_serde512}; 18 | 19 | define_fixed_bytes!(HashResult, 32); 20 | type_capnp_serde!(HashResult, common_capnp::hash_result, (x0, x1, x2, x3)); 21 | 22 | define_fixed_bytes!(Salt, 32); 23 | type_capnp_serde!(Salt, common_capnp::salt, (x0, x1, x2, x3)); 24 | 25 | define_fixed_bytes!(DhPublicKey, 32); 26 | type_capnp_serde!(DhPublicKey, common_capnp::dh_public_key, (x0, x1, x2, x3)); 27 | 28 | define_fixed_bytes!(PlainLock, 32); 29 | type_capnp_serde!(PlainLock, common_capnp::plain_lock, (x0, x1, x2, x3)); 30 | 31 | define_fixed_bytes!(HashedLock, 32); 32 | type_capnp_serde!(HashedLock, common_capnp::hashed_lock, (x0, x1, x2, x3)); 33 | 34 | define_fixed_bytes!(PublicKey, 32); 35 | type_capnp_serde!(PublicKey, common_capnp::public_key, (x0, x1, x2, x3)); 36 | 37 | // PKCS8 key pair 38 | define_fixed_bytes!(PrivateKey, 32); 39 | 40 | define_fixed_bytes!(Signature, 64); 41 | type_capnp_serde!( 42 | Signature, 43 | common_capnp::signature, 44 | (x0, x1, x2, x3, x4, x5, x6, x7) 45 | ); 46 | 47 | // An invoice identifier 48 | define_fixed_bytes!(InvoiceId, 32); 49 | type_capnp_serde!(InvoiceId, common_capnp::invoice_id, (x0, x1, x2, x3)); 50 | 51 | define_fixed_bytes!(PaymentId, 16); 52 | type_capnp_serde!(PaymentId, common_capnp::payment_id, (x0, x1)); 53 | 54 | define_fixed_bytes!(RandValue, 16); 55 | type_capnp_serde!(RandValue, common_capnp::rand_value, (x0, x1)); 56 | 57 | // An Universally Unique Identifier (UUID). 58 | define_fixed_bytes!(Uid, 16); 59 | type_capnp_serde!(Uid, common_capnp::uid, (x0, x1)); 60 | -------------------------------------------------------------------------------- /components/proto/src/crypto/serialize.rs: -------------------------------------------------------------------------------- 1 | /// Define read and write functions for basic types 2 | macro_rules! type_capnp_serde { 3 | ($native_type:ty, $capnp_type:ty, ($($field:ident),*)) => { 4 | paste::item! { 5 | impl<'a> WriteCapnp<'a> for $native_type { 6 | type WriterType = $capnp_type::Builder<'a>; 7 | 8 | fn write_capnp(&self, writer: &mut Self::WriterType) { 9 | let mut inner = writer.reborrow().get_inner().unwrap(); 10 | let mut cursor = std::io::Cursor::new(self.as_ref()); 11 | $( 12 | inner.[](cursor.read_u64::().unwrap()); 13 | )* 14 | } 15 | } 16 | } 17 | 18 | paste::item! { 19 | impl<'a> ReadCapnp<'a> for $native_type { 20 | type ReaderType = $capnp_type::Reader<'a>; 21 | 22 | fn read_capnp(reader: &Self::ReaderType) -> Result { 23 | let inner = reader.get_inner()?; 24 | let mut vec = Vec::new(); 25 | $( 26 | vec.write_u64::(inner.[]())?; 27 | )* 28 | Ok(Self::try_from(&vec[..]).unwrap()) 29 | } 30 | } 31 | } 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /components/proto/src/funder/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/index_client/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/index_server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | // pub mod signature_buff; 3 | -------------------------------------------------------------------------------- /components/proto/src/keepalive/messages.rs: -------------------------------------------------------------------------------- 1 | use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; 2 | 3 | #[capnp_conv(crate::keepalive_capnp::ka_message)] 4 | #[derive(Debug, PartialEq, Eq, Clone)] 5 | pub enum KaMessage { 6 | KeepAlive, 7 | Message(Vec), 8 | } 9 | -------------------------------------------------------------------------------- /components/proto/src/keepalive/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate quickcheck_derive; 12 | 13 | // Workaround for issue: https://github.com/rust-lang/rust/issues/64450 14 | extern crate offset_mutual_from as mutual_from; 15 | 16 | #[macro_use] 17 | pub mod macros; 18 | pub mod app_server; 19 | pub mod consts; 20 | pub mod crypto; 21 | pub mod file; 22 | pub mod funder; 23 | pub mod index_client; 24 | pub mod index_server; 25 | pub mod keepalive; 26 | pub mod net; 27 | pub mod proto_ser; 28 | pub mod relay; 29 | pub mod report; 30 | pub mod secure_channel; 31 | pub mod ser_string; 32 | pub mod wrapper; 33 | 34 | include_schema!(report_capnp, "report_capnp"); 35 | include_schema!(app_server_capnp, "app_server_capnp"); 36 | include_schema!(common_capnp, "common_capnp"); 37 | include_schema!(dh_capnp, "dh_capnp"); 38 | include_schema!(relay_capnp, "relay_capnp"); 39 | include_schema!(funder_capnp, "funder_capnp"); 40 | include_schema!(keepalive_capnp, "keepalive_capnp"); 41 | include_schema!(index_capnp, "index_capnp"); 42 | -------------------------------------------------------------------------------- /components/proto/src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Include a capnp schema 2 | macro_rules! include_schema { 3 | ($( $name:ident, $path:expr );*) => { 4 | $( 5 | #[allow(unused, clippy::all)] 6 | pub mod $name { 7 | include!(concat!(env!("OUT_DIR"), "/schema/", $path, ".rs")); 8 | } 9 | 10 | // use self::$name::*; 11 | )* 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /components/proto/src/net/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/proto_ser.rs: -------------------------------------------------------------------------------- 1 | use derive_more::From; 2 | 3 | use capnp_conv::{CapnpConvError, FromCapnpBytes, ToCapnpBytes}; 4 | 5 | #[derive(Debug, From)] 6 | pub enum ProtoSerializeError { 7 | CapnpConvError(CapnpConvError), 8 | } 9 | 10 | pub trait ProtoSerialize { 11 | /// Serialize a Rust struct into bytes using Capnp 12 | fn proto_serialize(&self) -> Vec; 13 | } 14 | 15 | pub trait ProtoDeserialize: Sized { 16 | /// Deserialize a Rust struct from bytes using Capnp 17 | fn proto_deserialize(bytes: &[u8]) -> Result; 18 | } 19 | 20 | impl ProtoSerialize for T 21 | where 22 | T: ToCapnpBytes, 23 | { 24 | fn proto_serialize(&self) -> Vec { 25 | self.to_capnp_bytes() 26 | } 27 | } 28 | 29 | impl ProtoDeserialize for T 30 | where 31 | T: FromCapnpBytes, 32 | { 33 | fn proto_deserialize(bytes: &[u8]) -> Result { 34 | Ok(Self::from_capnp_bytes(bytes)?) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /components/proto/src/relay/messages.rs: -------------------------------------------------------------------------------- 1 | use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; 2 | 3 | use crate::crypto::PublicKey; 4 | 5 | #[capnp_conv(crate::relay_capnp::init_connection)] 6 | #[derive(Debug, PartialEq, Eq)] 7 | pub enum InitConnection { 8 | Listen, 9 | // remote side wants to accept a connection from public_key 10 | Accept(PublicKey), 11 | // remote side wants to connect to public_key 12 | Connect(PublicKey), 13 | } 14 | 15 | #[capnp_conv(crate::relay_capnp::reject_connection)] 16 | #[derive(Debug, PartialEq, Eq, Clone)] 17 | pub struct RejectConnection { 18 | pub public_key: PublicKey, 19 | } 20 | 21 | #[capnp_conv(crate::relay_capnp::incoming_connection)] 22 | #[derive(Debug, PartialEq, Eq, Clone)] 23 | pub struct IncomingConnection { 24 | pub public_key: PublicKey, 25 | } 26 | -------------------------------------------------------------------------------- /components/proto/src/relay/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/report/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: Possibly move convert module to another crate? 2 | pub mod convert; 3 | pub mod messages; 4 | -------------------------------------------------------------------------------- /components/proto/src/schema/dh.capnp: -------------------------------------------------------------------------------- 1 | @0xa7ec056ae12d5593; 2 | 3 | using import "common.capnp".PublicKey; 4 | using import "common.capnp".DhPublicKey; 5 | using import "common.capnp".Salt; 6 | using import "common.capnp".Signature; 7 | using import "common.capnp".RandValue; 8 | 9 | # Diffie Hellman: 10 | ################# 11 | 12 | struct ExchangeRandNonce { 13 | randNonce @0: RandValue; 14 | srcPublicKey @1: PublicKey; 15 | # Sender's public key 16 | optDestPublicKey: union { 17 | empty @2: Void; 18 | # Nothing has changed 19 | publicKey @3: PublicKey; 20 | # Set this exact list to be the list of relays 21 | } 22 | # PublicKey the sender expects the remote side to have. 23 | # Useful for multiplexing multiple entities behind one listening port. 24 | # A multiplexer can identify right at the first incoming message to which 25 | # entity should this connection be redirected. 26 | } 27 | 28 | struct ExchangeDh { 29 | dhPublicKey @0: DhPublicKey; 30 | randNonce @1: RandValue; 31 | # This is the nonce previously sent by the remote side. 32 | keySalt @2: Salt; 33 | signature @3: Signature; 34 | } 35 | 36 | # Periodic rekeying is done inside the encrypted channel: 37 | struct Rekey { 38 | dhPublicKey @0: DhPublicKey; 39 | keySalt @1: Salt; 40 | } 41 | 42 | struct ChannelContent { 43 | union { 44 | rekey @0: Rekey; 45 | user @1: Data; 46 | } 47 | } 48 | 49 | struct ChannelMessage { 50 | randPadding @0: Data; 51 | content @1: ChannelContent; 52 | } 53 | -------------------------------------------------------------------------------- /components/proto/src/schema/keepalive.capnp: -------------------------------------------------------------------------------- 1 | @0x9fb474aba32a63d1; 2 | 3 | # A keepalive message wrapper. 4 | # Allows to turn a channel into a channel with keepalive support. 5 | struct KaMessage { 6 | union { 7 | keepAlive @0: Void; 8 | message @1: Data; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /components/proto/src/schema/relay.capnp: -------------------------------------------------------------------------------- 1 | @0xccef24a2bc5520ea; 2 | 3 | using import "common.capnp".PublicKey; 4 | 5 | 6 | # First message sent after a connection was encrypted. 7 | # This message will determine the context of the connection. 8 | # This message can be sent only once per encrypted connection. 9 | struct InitConnection { 10 | union { 11 | listen @0: Void; 12 | # Listen to connections 13 | accept @1: PublicKey; 14 | # Accepting connection from 15 | connect @2: PublicKey; 16 | # Request for a connection to 17 | } 18 | } 19 | 20 | # Client -> Relay 21 | struct RejectConnection { 22 | publicKey @0: PublicKey; 23 | # Reject incoming connection by PublicKey 24 | } 25 | 26 | # Relay -> Client 27 | struct IncomingConnection { 28 | publicKey @0: PublicKey; 29 | # Incoming Connection public key 30 | } 31 | -------------------------------------------------------------------------------- /components/proto/src/secure_channel/messages.rs: -------------------------------------------------------------------------------- 1 | use capnp_conv::{capnp_conv, CapnpConvError, ReadCapnp, WriteCapnp}; 2 | 3 | use crate::crypto::{DhPublicKey, PublicKey, RandValue, Salt, Signature}; 4 | 5 | #[capnp_conv(crate::dh_capnp::exchange_rand_nonce::opt_dest_public_key)] 6 | #[derive(Debug, PartialEq, Eq)] 7 | enum OptDestPublicKey { 8 | Empty, 9 | PublicKey(PublicKey), 10 | } 11 | 12 | impl From> for OptDestPublicKey { 13 | fn from(from: Option) -> Self { 14 | match from { 15 | Some(public_key) => Self::PublicKey(public_key), 16 | None => Self::Empty, 17 | } 18 | } 19 | } 20 | 21 | impl From for Option { 22 | fn from(from: OptDestPublicKey) -> Self { 23 | match from { 24 | OptDestPublicKey::PublicKey(public_key) => Some(public_key), 25 | OptDestPublicKey::Empty => None, 26 | } 27 | } 28 | } 29 | 30 | /// First Diffie-Hellman message: 31 | #[capnp_conv(crate::dh_capnp::exchange_rand_nonce)] 32 | #[derive(Debug, PartialEq, Eq)] 33 | pub struct ExchangeRandNonce { 34 | pub rand_nonce: RandValue, 35 | pub src_public_key: PublicKey, 36 | #[capnp_conv(with = OptDestPublicKey)] 37 | pub opt_dest_public_key: Option, 38 | } 39 | 40 | /// Second Diffie-Hellman message: 41 | #[capnp_conv(crate::dh_capnp::exchange_dh)] 42 | #[derive(Debug, PartialEq, Eq)] 43 | pub struct ExchangeDh { 44 | pub dh_public_key: DhPublicKey, 45 | pub rand_nonce: RandValue, 46 | pub key_salt: Salt, 47 | pub signature: Signature, 48 | } 49 | 50 | impl ExchangeDh { 51 | pub fn signature_buffer(&self) -> Vec { 52 | let mut sbuffer = Vec::new(); 53 | sbuffer.extend_from_slice(&self.dh_public_key); 54 | sbuffer.extend_from_slice(&self.rand_nonce); 55 | sbuffer.extend_from_slice(&self.key_salt); 56 | sbuffer 57 | } 58 | } 59 | 60 | #[capnp_conv(crate::dh_capnp::rekey)] 61 | #[derive(Debug, PartialEq, Eq, Clone)] 62 | pub struct Rekey { 63 | pub dh_public_key: DhPublicKey, 64 | pub key_salt: Salt, 65 | } 66 | 67 | #[capnp_conv(crate::dh_capnp::channel_content)] 68 | #[derive(Debug, PartialEq, Eq, Clone)] 69 | pub enum ChannelContent { 70 | Rekey(Rekey), 71 | User(Vec), 72 | } 73 | 74 | #[capnp_conv(crate::dh_capnp::channel_message)] 75 | #[derive(Debug, PartialEq, Eq)] 76 | pub struct ChannelMessage { 77 | pub rand_padding: Vec, 78 | pub content: ChannelContent, 79 | } 80 | -------------------------------------------------------------------------------- /components/proto/src/secure_channel/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod messages; 2 | -------------------------------------------------------------------------------- /components/proto/src/ser_string.rs: -------------------------------------------------------------------------------- 1 | use derive_more::From; 2 | 3 | use serde::de::DeserializeOwned; 4 | use serde::ser::Serialize; 5 | 6 | use base64::{self, URL_SAFE_NO_PAD}; 7 | 8 | use crate::crypto::PublicKey; 9 | 10 | #[derive(Debug)] 11 | pub struct SerStringError; 12 | 13 | /// Define conversion to/from String: 14 | macro_rules! str_convert_funcs { 15 | ($to_string_func:ident, $from_string_func:ident, $conv_type:ident, $conv_len:expr) => { 16 | /// Convert a our type into a string 17 | pub fn $to_string_func(conv: &$conv_type) -> String { 18 | base64::encode_config(&conv, URL_SAFE_NO_PAD) 19 | } 20 | 21 | /// Convert a string into a our type 22 | pub fn $from_string_func(input_str: &str) -> Result<$conv_type, SerStringError> { 23 | // Decode public key: 24 | let conv_vec = 25 | base64::decode_config(input_str, URL_SAFE_NO_PAD).map_err(|_| SerStringError)?; 26 | // TODO: A more idiomatic way to do this? 27 | if conv_vec.len() != $conv_len { 28 | return Err(SerStringError); 29 | } 30 | let mut conv_array = [0u8; $conv_len]; 31 | conv_array.copy_from_slice(&conv_vec[0..$conv_len]); 32 | Ok($conv_type::from(&conv_array)) 33 | } 34 | }; 35 | } 36 | 37 | str_convert_funcs!( 38 | public_key_to_string, 39 | string_to_public_key, 40 | PublicKey, 41 | PublicKey::len() 42 | ); 43 | 44 | #[derive(Debug, From)] 45 | pub enum StringSerdeError { 46 | // IoError(io::Error), 47 | JsonSerdeError(serde_json::Error), 48 | } 49 | 50 | pub fn deserialize_from_string(input: &str) -> Result 51 | where 52 | T: DeserializeOwned, 53 | { 54 | Ok(serde_json::from_str(&input)?) 55 | } 56 | 57 | pub fn serialize_to_string(t: &T) -> Result 58 | where 59 | T: Serialize, 60 | { 61 | Ok(serde_json::to_string_pretty(t)?) 62 | } 63 | -------------------------------------------------------------------------------- /components/relay/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-relay" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | 16 | log = "0.4" 17 | futures = "0.3.1" 18 | 19 | derive_more = "0.14.0" 20 | 21 | [dev-dependencies] 22 | 23 | futures = {version = "0.3.1", features = ["thread-pool"]} 24 | -------------------------------------------------------------------------------- /components/relay/src/client/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client_connector; 2 | pub mod client_listener; 3 | -------------------------------------------------------------------------------- /components/relay/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![type_length_limit = "291239"] 3 | #![deny(trivial_numeric_casts, warnings)] 4 | #![allow(intra_doc_link_resolution_failure)] 5 | #![allow( 6 | clippy::too_many_arguments, 7 | clippy::implicit_hasher, 8 | clippy::module_inception, 9 | clippy::new_without_default 10 | )] 11 | 12 | #[macro_use] 13 | extern crate log; 14 | 15 | #[macro_use] 16 | extern crate common; 17 | 18 | mod client; 19 | mod server; 20 | 21 | pub use self::client::client_connector::ClientConnector; 22 | pub use self::client::client_listener::ClientListener; 23 | pub use self::server::{relay_server, RelayServerError}; 24 | -------------------------------------------------------------------------------- /components/relay/src/server/conn_limiter.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | use core::pin::Pin; 3 | use futures::channel::oneshot; 4 | use futures::task::{Context, Poll}; 5 | use futures::{Sink, Stream, StreamExt}; 6 | use std::marker::Unpin; 7 | 8 | use proto::crypto::PublicKey; 9 | 10 | /// A struct that reports when it is dropped. 11 | struct Tracked { 12 | inner: T, 13 | opt_drop_sender: Option>, 14 | } 15 | 16 | impl Tracked { 17 | pub fn new(inner: T, drop_sender: oneshot::Sender<()>) -> Tracked { 18 | Tracked { 19 | inner, 20 | opt_drop_sender: Some(drop_sender), 21 | } 22 | } 23 | } 24 | 25 | impl Stream for Tracked 26 | where 27 | T: Stream + Unpin, 28 | { 29 | type Item = T::Item; 30 | 31 | fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll> { 32 | self.inner.poll_next_unpin(context) 33 | } 34 | } 35 | 36 | impl Drop for Tracked { 37 | fn drop(&mut self) { 38 | if let Some(drop_sender) = self.opt_drop_sender.take() { 39 | let _ = drop_sender.send(()); 40 | }; 41 | } 42 | } 43 | 44 | async fn conn_limiter(incoming_conns: T, max_conns: usize) -> Result<(), ()> 45 | where 46 | T: Stream, 47 | M: Stream>, 48 | K: Sink, Error = KE>, 49 | { 50 | let mut cur_conns: usize = 0; 51 | unimplemented!(); 52 | } 53 | -------------------------------------------------------------------------------- /components/relay/src/server/mod.rs: -------------------------------------------------------------------------------- 1 | mod conn_limiter; 2 | mod conn_processor; 3 | // pub mod net_server; 4 | mod server; 5 | mod server_loop; 6 | mod types; 7 | 8 | pub use server::relay_server; 9 | pub use server_loop::RelayServerError; 10 | -------------------------------------------------------------------------------- /components/relay/src/server/server.rs: -------------------------------------------------------------------------------- 1 | use std::marker::Unpin; 2 | 3 | use futures::task::Spawn; 4 | use futures::Stream; 5 | 6 | use common::conn::ConnPairVec; 7 | 8 | use proto::crypto::PublicKey; 9 | 10 | use timer::TimerClient; 11 | 12 | use crate::server::conn_processor::conn_processor; 13 | use crate::server::server_loop::{relay_server_loop, RelayServerError}; 14 | 15 | /// A relay server loop. Incoming connections should contain both (sender, receiver) and a 16 | /// public_key of the remote side (Should be obtained after authentication). 17 | /// 18 | /// `conn_timeout_ticks` is the amount of time we are willing to wait for a connection to identify 19 | /// its purpose. 20 | pub async fn relay_server( 21 | incoming_conns: IC, 22 | timer_client: TimerClient, 23 | conn_timeout_ticks: usize, 24 | half_tunnel_ticks: usize, 25 | spawner: S, 26 | ) -> Result<(), RelayServerError> 27 | where 28 | S: Spawn + Clone + Send + 'static, 29 | IC: Stream + Unpin + Send + 'static, 30 | { 31 | // TODO: How to get rid of the Box::pin here? 32 | let processed_conns = Box::pin(conn_processor( 33 | incoming_conns, 34 | timer_client.clone(), 35 | conn_timeout_ticks, 36 | )); 37 | 38 | relay_server_loop(timer_client, processed_conns, half_tunnel_ticks, spawner).await 39 | } 40 | -------------------------------------------------------------------------------- /components/relay/src/server/types.rs: -------------------------------------------------------------------------------- 1 | use common::conn::{ConnPair, ConnPairVec}; 2 | 3 | use proto::crypto::PublicKey; 4 | use proto::relay::messages::{IncomingConnection, RejectConnection}; 5 | 6 | pub struct IncomingListen { 7 | pub conn_pair: ConnPair, 8 | } 9 | 10 | pub struct IncomingAccept { 11 | pub accept_public_key: PublicKey, 12 | pub conn_pair: ConnPairVec, 13 | } 14 | 15 | pub struct IncomingConnect { 16 | pub connect_public_key: PublicKey, 17 | pub conn_pair: ConnPairVec, 18 | } 19 | 20 | pub enum IncomingConnInner { 21 | Listen(IncomingListen), 22 | Accept(IncomingAccept), 23 | Connect(IncomingConnect), 24 | } 25 | 26 | pub struct IncomingConn { 27 | pub public_key: PublicKey, 28 | pub inner: IncomingConnInner, 29 | } 30 | -------------------------------------------------------------------------------- /components/route/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-route" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 12 | crypto = { path = "../crypto", version = "0.1.0" , package = "offset-crypto" } 13 | 14 | 15 | num-bigint = "0.2.2" 16 | num-traits = "0.2.6" 17 | -------------------------------------------------------------------------------- /components/route/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/route/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | mod multi_route; 12 | 13 | pub use multi_route::{choose_multi_route, MultiRouteChoice}; 14 | -------------------------------------------------------------------------------- /components/secure_channel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-secure-channel" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 12 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity"} 13 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 14 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 15 | 16 | log = "0.4" 17 | pretty_env_logger = "0.2" 18 | derive_more = "0.15.0" 19 | 20 | futures = "0.3.1" 21 | 22 | byteorder = "1.1" 23 | 24 | [dev-dependencies] 25 | 26 | futures = {version = "0.3.1", features = ["thread-pool"]} 27 | 28 | 29 | -------------------------------------------------------------------------------- /components/secure_channel/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/secure_channel/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![type_length_limit = "2097152"] 3 | #![deny(trivial_numeric_casts, warnings)] 4 | #![allow(intra_doc_link_resolution_failure)] 5 | #![allow( 6 | clippy::too_many_arguments, 7 | clippy::implicit_hasher, 8 | clippy::module_inception, 9 | clippy::new_without_default 10 | )] 11 | 12 | #[macro_use] 13 | extern crate common; 14 | 15 | #[macro_use] 16 | extern crate log; 17 | 18 | mod secure_channel; 19 | mod state; 20 | mod types; 21 | 22 | pub use self::secure_channel::SecureChannel; 23 | -------------------------------------------------------------------------------- /components/secure_channel/src/types.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq, Clone)] 2 | pub struct EncryptedData(pub Vec); 3 | #[derive(Debug, PartialEq, Eq, Clone)] 4 | pub struct PlainData(pub Vec); 5 | -------------------------------------------------------------------------------- /components/signature/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-signature" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 12 | crypto = { path = "../crypto", version = "0.1.0" , package = "offset-crypto" } 13 | 14 | byteorder = "1.3.2" 15 | 16 | -------------------------------------------------------------------------------- /components/signature/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/signature/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | pub mod canonical; 12 | pub mod signature_buff; 13 | pub mod verify; 14 | -------------------------------------------------------------------------------- /components/stcompact/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-stcompact" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [lib] 9 | name = "stcompact" 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "stcompact" 14 | path = "src/bin/stcompact.rs" 15 | 16 | [[bin]] 17 | name = "stcompact_ser_gen" 18 | path = "src/bin/stcompact_ser_gen.rs" 19 | 20 | [dependencies] 21 | 22 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 23 | timer = { path = "../timer", version = "0.1.0", package = "offset-timer" } 24 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 25 | lockfile = { path = "../lockfile", version = "0.1.0", package = "offset-lockfile" } 26 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 27 | route = { path = "../route", version = "0.1.0", package = "offset-route" } 28 | database = { path = "../database", version = "0.1.0", package = "offset-database" } 29 | identity = { path = "../identity", version = "0.1.0", package = "offset-identity" } 30 | node = { path = "../node", version = "0.1.0" , package = "offset-node" } 31 | net = { path = "../net", version = "0.1.0", package = "offset-net" } 32 | connection = { path = "../connection", version = "0.1.0", package = "offset-connection" } 33 | app = { path = "../app", version = "0.1.0", package = "offset-app" } 34 | app_client = { path = "../app_client", version = "0.1.0", package = "offset-app-client" } 35 | 36 | serde = {version = "1.0.104", features = ["derive"]} 37 | 38 | base64 = "0.10.1" 39 | 40 | log = "0.4" 41 | env_logger = "0.6.0" 42 | futures = {version = "0.3.1", features = ["thread-pool"]} 43 | async-std = "1.6.2" 44 | 45 | structopt = "0.2.15" 46 | 47 | derive_more = "0.99.2" 48 | serde_json = "1.0.44" 49 | 50 | # Quickcheck: 51 | quickcheck = {version = "0.9"} 52 | quickcheck_macros = {version = "0.8"} 53 | quickcheck_derive = {version = "0.2.1"} 54 | rand = {version = "0.7.2"} 55 | 56 | [dev-dependencies] 57 | 58 | tempfile = "3.1.0" 59 | -------------------------------------------------------------------------------- /components/stcompact/src/bin/stcompact.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use structopt::StructOpt; 14 | 15 | use futures::executor::{block_on, ThreadPool}; 16 | 17 | use stcompact::stcompactlib::{stcompact, StCompactCmd, StCompactError}; 18 | 19 | fn run() -> Result<(), StCompactError> { 20 | env_logger::init(); 21 | let st_compact_cmd = StCompactCmd::from_args(); 22 | let thread_pool = ThreadPool::new().map_err(|_| StCompactError::SpawnError)?; 23 | let file_thread_pool = ThreadPool::new().map_err(|_| StCompactError::SpawnError)?; 24 | block_on(stcompact(st_compact_cmd, thread_pool, file_thread_pool)) 25 | } 26 | 27 | fn main() { 28 | if let Err(e) = run() { 29 | error!("error: {:?}", e); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /components/stcompact/src/bin/stcompact_ser_gen.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | /* 11 | #[macro_use] 12 | extern crate log; 13 | */ 14 | 15 | use quickcheck::Arbitrary; 16 | use rand::{self, rngs::StdRng}; 17 | use serde::Serialize; 18 | use structopt::StructOpt; 19 | 20 | use stcompact::messages::{ServerToUserAck, UserToServerAck}; 21 | 22 | /// stcompact_ser_gen: Offset Compact serialization generator 23 | /// 24 | /// Generates example serialized messages, for integration tests 25 | /// with a user application 26 | /// 27 | #[derive(Debug, StructOpt)] 28 | #[structopt(name = "stcompact_ser_gen")] 29 | pub struct StCompactSerGenCmd { 30 | /// Amount of instances to generate (For each message type) 31 | #[structopt(short = "i", long = "iters")] 32 | pub iters: usize, 33 | } 34 | 35 | fn gen_print_instances(type_name: &str, iters: usize, gen: &mut G) 36 | where 37 | T: Arbitrary + Serialize, 38 | G: quickcheck::Gen, 39 | { 40 | println!("final {} = [", type_name); 41 | for _ in 0..iters { 42 | let msg = T::arbitrary(gen); 43 | let ser_str = serde_json::to_string_pretty(&msg).unwrap(); 44 | println!("r'''"); 45 | println!("{}", ser_str); 46 | println!("''',"); 47 | } 48 | println!("];\n"); 49 | } 50 | 51 | fn main() { 52 | env_logger::init(); 53 | 54 | // Load argumnets: 55 | let st_compact_ser_gen_cmd = StCompactSerGenCmd::from_args(); 56 | 57 | // Create a random generator for quickcheck: 58 | let size = 3; 59 | let rng_seed: [u8; 32] = [1; 32]; 60 | let rng: StdRng = rand::SeedableRng::from_seed(rng_seed); 61 | let mut gen = quickcheck::StdGen::new(rng, size); 62 | 63 | // Print randomly generated instances to console: 64 | gen_print_instances::( 65 | "serverToUserAck", 66 | st_compact_ser_gen_cmd.iters, 67 | &mut gen, 68 | ); 69 | println!("// -------------------------------------"); 70 | gen_print_instances::( 71 | "userToServerAck", 72 | st_compact_ser_gen_cmd.iters, 73 | &mut gen, 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /components/stcompact/src/compact_node/mod.rs: -------------------------------------------------------------------------------- 1 | mod convert; 2 | mod handle_node; 3 | mod handle_user; 4 | pub mod messages; 5 | mod permission; 6 | mod persist; 7 | mod server; 8 | mod server_init; 9 | mod server_loop; 10 | mod types; 11 | mod utils; 12 | 13 | pub use convert::create_compact_report; 14 | pub use persist::CompactState; 15 | pub use server::compact_node; 16 | pub use types::ConnPairCompact; 17 | -------------------------------------------------------------------------------- /components/stcompact/src/compact_node/permission.rs: -------------------------------------------------------------------------------- 1 | use app::conn::AppPermissions; 2 | 3 | use crate::compact_node::messages::UserToCompact; 4 | 5 | /// Check if an app is allowed to send a certain user request 6 | pub fn check_permission(user_request: &UserToCompact, app_permissions: &AppPermissions) -> bool { 7 | match user_request { 8 | UserToCompact::AddRelay(_) 9 | | UserToCompact::RemoveRelay(_) 10 | | UserToCompact::AddIndexServer(_) 11 | | UserToCompact::RemoveIndexServer(_) 12 | | UserToCompact::AddFriend(_) 13 | | UserToCompact::SetFriendRelays(_) 14 | | UserToCompact::SetFriendName(_) 15 | | UserToCompact::RemoveFriend(_) 16 | | UserToCompact::EnableFriend(_) 17 | | UserToCompact::DisableFriend(_) 18 | | UserToCompact::OpenFriendCurrency(_) 19 | | UserToCompact::CloseFriendCurrency(_) 20 | | UserToCompact::SetFriendCurrencyMaxDebt(_) 21 | | UserToCompact::SetFriendCurrencyRate(_) 22 | | UserToCompact::RemoveFriendCurrency(_) 23 | | UserToCompact::ResetFriendChannel(_) => app_permissions.config, 24 | UserToCompact::InitPayment(_) 25 | | UserToCompact::ConfirmPaymentFees(_) 26 | | UserToCompact::CancelPayment(_) 27 | | UserToCompact::AckPaymentDone(_, _) => app_permissions.buyer, 28 | UserToCompact::AddInvoice(_) 29 | | UserToCompact::CancelInvoice(_) 30 | | UserToCompact::CommitInvoice(_) => app_permissions.seller, 31 | UserToCompact::RequestVerifyCommit(_) => true, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /components/stcompact/src/compact_node/server.rs: -------------------------------------------------------------------------------- 1 | use database::DatabaseClient; 2 | 3 | use app::conn::AppConnTuple; 4 | 5 | use crate::gen::GenUid; 6 | 7 | use crate::compact_node::{ 8 | persist::CompactState, 9 | types::{CompactNodeError, ConnPairCompact}, 10 | }; 11 | use crate::compact_node::{server_init::compact_node_init, server_loop::compact_node_loop}; 12 | 13 | pub async fn compact_node( 14 | mut app_conn_tuple: AppConnTuple, 15 | mut conn_pair_compact: ConnPairCompact, 16 | mut compact_state: CompactState, 17 | mut database_client: DatabaseClient, 18 | mut compact_gen: CG, 19 | ) -> Result<(), CompactNodeError> 20 | where 21 | CG: GenUid, 22 | { 23 | compact_node_init( 24 | &mut app_conn_tuple, 25 | &mut conn_pair_compact, 26 | &mut compact_state, 27 | &mut database_client, 28 | &mut compact_gen, 29 | ) 30 | .await?; 31 | compact_node_loop( 32 | app_conn_tuple, 33 | conn_pair_compact, 34 | compact_state, 35 | database_client, 36 | compact_gen, 37 | ) 38 | .await 39 | } 40 | -------------------------------------------------------------------------------- /components/stcompact/src/compact_node/types.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use common::conn::ConnPair; 4 | 5 | use app::common::Uid; 6 | use app::conn::AppServerToApp; 7 | use database::DatabaseClient; 8 | 9 | use crate::compact_node::messages::{CompactToUserAck, UserToCompactAck}; 10 | use crate::compact_node::persist::CompactState; 11 | 12 | pub type ConnPairCompact = ConnPair; 13 | 14 | #[allow(clippy::large_enum_variant)] 15 | #[derive(Debug)] 16 | pub enum CompactServerEvent { 17 | User(UserToCompactAck), 18 | UserClosed, 19 | Node(AppServerToApp), 20 | NodeClosed, 21 | } 22 | 23 | #[derive(Debug)] 24 | pub enum CompactNodeError { 25 | AppSenderError, 26 | UserSenderError, 27 | ReportMutationError, 28 | DatabaseMutateError, 29 | } 30 | 31 | pub struct CompactServerState { 32 | node_report: app::report::NodeReport, 33 | compact_state: CompactState, 34 | database_client: DatabaseClient, 35 | /// Ids of requests that were initiated directly by the user, 36 | /// and were not acked yet. 37 | pub pending_user_requests: HashSet, 38 | } 39 | 40 | impl CompactServerState { 41 | pub fn new( 42 | node_report: app::report::NodeReport, 43 | compact_state: CompactState, 44 | database_client: DatabaseClient, 45 | ) -> Self { 46 | Self { 47 | node_report, 48 | compact_state, 49 | database_client, 50 | pending_user_requests: HashSet::new(), 51 | } 52 | } 53 | 54 | /// Get current `node_update` 55 | pub fn node_report(&self) -> &app::report::NodeReport { 56 | &self.node_report 57 | } 58 | 59 | pub fn update_node_report(&mut self, node_report: app::report::NodeReport) { 60 | self.node_report = node_report; 61 | } 62 | 63 | /// Get current `compact_state` 64 | pub fn compact_state(&self) -> &CompactState { 65 | &self.compact_state 66 | } 67 | 68 | /// Persistent (and atomic) update to `compact_state` 69 | pub async fn update_compact_state( 70 | &mut self, 71 | compact_state: CompactState, 72 | ) -> Result<(), CompactNodeError> { 73 | self.compact_state = compact_state.clone(); 74 | self.database_client 75 | .mutate(vec![compact_state]) 76 | .await 77 | .map_err(|_| CompactNodeError::DatabaseMutateError)?; 78 | Ok(()) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /components/stcompact/src/compact_node/utils.rs: -------------------------------------------------------------------------------- 1 | use futures::{Sink, SinkExt}; 2 | 3 | use crate::compact_node::create_compact_report; 4 | use crate::compact_node::messages::{CompactToUser, CompactToUserAck}; 5 | use crate::compact_node::persist::CompactState; 6 | use crate::compact_node::types::{CompactNodeError, CompactServerState}; 7 | 8 | /// Update compact state, and send compact report to user if necessary 9 | pub async fn update_send_compact_state( 10 | compact_state: CompactState, 11 | server_state: &mut CompactServerState, 12 | user_sender: &mut US, 13 | ) -> Result<(), CompactNodeError> 14 | where 15 | US: Sink + Unpin, 16 | { 17 | // Check if the old compact state is not the same as the new one 18 | if server_state.compact_state() != &compact_state { 19 | server_state.update_compact_state(compact_state).await?; 20 | let new_compact_report = create_compact_report( 21 | server_state.compact_state().clone(), 22 | server_state.node_report().clone(), 23 | ); 24 | 25 | let compact_to_user = CompactToUser::Report(new_compact_report); 26 | user_sender 27 | .send(CompactToUserAck::CompactToUser(compact_to_user)) 28 | .await 29 | .map_err(|_| CompactNodeError::UserSenderError)?; 30 | } 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /components/stcompact/src/gen.rs: -------------------------------------------------------------------------------- 1 | use crypto::rand::{CryptoRandom, RandGen}; 2 | 3 | use app::common::{PrivateKey, Uid}; 4 | 5 | pub trait GenUid { 6 | /// Generate a Uid 7 | fn gen_uid(&mut self) -> Uid; 8 | } 9 | 10 | /* 11 | pub trait GenPaymentId { 12 | /// Generate a PaymentId 13 | fn gen_payment_id(&mut self) -> PaymentId; 14 | } 15 | */ 16 | 17 | pub trait GenPrivateKey { 18 | /// Generate private key 19 | fn gen_private_key(&mut self) -> PrivateKey; 20 | } 21 | 22 | // TODO: Find a way to eliminate this shim. 23 | // Possibly have all the crates use traits like GenUid, GenPrivateKey, GenNonce etc? 24 | /// A wrapper over a random generator that implements 25 | /// GenUid and GenPrivateKey 26 | pub struct GenCryptoRandom(pub R); 27 | 28 | impl GenPrivateKey for GenCryptoRandom 29 | where 30 | R: CryptoRandom, 31 | { 32 | fn gen_private_key(&mut self) -> PrivateKey { 33 | PrivateKey::rand_gen(&mut self.0) 34 | } 35 | } 36 | 37 | impl GenUid for GenCryptoRandom 38 | where 39 | R: CryptoRandom, 40 | { 41 | fn gen_uid(&mut self) -> Uid { 42 | Uid::rand_gen(&mut self.0) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /components/stcompact/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate common; 12 | 13 | #[macro_use] 14 | extern crate log; 15 | 16 | #[cfg(test)] 17 | extern crate quickcheck; 18 | 19 | #[cfg(test)] 20 | #[macro_use(quickcheck)] 21 | extern crate quickcheck_macros; 22 | 23 | #[macro_use] 24 | extern crate quickcheck_derive; 25 | 26 | pub mod compact_node; 27 | 28 | mod gen; 29 | pub mod messages; 30 | pub mod server_loop; 31 | pub mod store; 32 | 33 | mod serialize; 34 | pub mod stcompactlib; 35 | 36 | // TODO: Possibly remove later? 37 | pub use gen::GenCryptoRandom; 38 | -------------------------------------------------------------------------------- /components/stcompact/src/store/consts.rs: -------------------------------------------------------------------------------- 1 | pub const LOCKFILE: &str = "lockfile"; 2 | pub const LOCAL: &str = "local"; 3 | pub const REMOTE: &str = "remote"; 4 | pub const NODE_IDENT: &str = "node.ident"; 5 | pub const NODE_CONFIG: &str = "node.config"; 6 | pub const NODE_DB: &str = "node.db"; 7 | pub const NODE_INFO: &str = "node.info"; 8 | pub const APP_IDENT: &str = "app.ident"; 9 | pub const COMPACT_DB: &str = "compact.db"; 10 | -------------------------------------------------------------------------------- /components/stcompact/src/store/mod.rs: -------------------------------------------------------------------------------- 1 | mod consts; 2 | #[allow(unused)] 3 | mod file_store; 4 | mod store; 5 | #[cfg(test)] 6 | mod tests; 7 | 8 | pub use file_store::{open_file_store, FileStore}; 9 | pub use store::{ 10 | LoadedNode, LoadedNodeLocal, LoadedNodeRemote, Store, StoreError, StoredNodeConfig, StoredNodes, 11 | }; 12 | -------------------------------------------------------------------------------- /components/stctrl/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /components/stctrl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-stctrl" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | 9 | [lib] 10 | name = "stctrl" 11 | path = "src/lib.rs" 12 | 13 | [[bin]] 14 | name = "stctrl" 15 | path = "src/bin/stctrl.rs" 16 | 17 | [[bin]] 18 | name = "stverify" 19 | path = "src/bin/stverify.rs" 20 | 21 | [dependencies] 22 | 23 | route = { path = "../route", version = "0.1.0", package = "offset-route" } 24 | app = { path = "../app", version = "0.1.0", package = "offset-app" } 25 | offset-mutual-from = { path = "../mutual_from", version = "0.1.0"} 26 | 27 | log = "0.4" 28 | 29 | env_logger = "0.6.0" 30 | futures = {version = "0.3.1", features = ["thread-pool"]} 31 | prettytable-rs = "0.8.0" 32 | 33 | serde = {version = "1.0.104", features = ["derive"]} 34 | 35 | structopt = "0.2.15" 36 | 37 | derive_more = "0.14.0" 38 | 39 | # Quickcheck: 40 | quickcheck = {version = "0.9"} 41 | quickcheck_macros = {version = "0.8"} 42 | quickcheck_derive = {version = "0.2.1"} 43 | rand = {version = "0.7.2"} 44 | 45 | [dev_dependencies] 46 | 47 | tempfile = "3.1.0" 48 | 49 | -------------------------------------------------------------------------------- /components/stctrl/src/bin/stctrl.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use std::io; 14 | use structopt::StructOpt; 15 | 16 | use stctrl::stctrllib::{stctrl, StCtrlCmd, StCtrlError}; 17 | 18 | fn run() -> Result<(), StCtrlError> { 19 | env_logger::init(); 20 | let st_ctrl_cmd = StCtrlCmd::from_args(); 21 | stctrl(st_ctrl_cmd, &mut io::stdout()) 22 | } 23 | 24 | fn main() { 25 | if let Err(e) = run() { 26 | error!("error: {:?}", e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/stctrl/src/bin/stverify.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | #[macro_use] 11 | extern crate log; 12 | 13 | use std::io; 14 | use structopt::StructOpt; 15 | 16 | use stctrl::stverifylib::{stverify, StVerifyCmd, StVerifyError}; 17 | 18 | fn run() -> Result<(), StVerifyError> { 19 | env_logger::init(); 20 | let st_verify_cmd = StVerifyCmd::from_args(); 21 | stverify(st_verify_cmd, &mut io::stdout()) 22 | } 23 | 24 | fn main() { 25 | if let Err(e) = run() { 26 | error!("error: {:?}", e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /components/stctrl/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(trivial_numeric_casts, warnings)] 2 | #![allow(intra_doc_link_resolution_failure)] 3 | #![allow( 4 | clippy::too_many_arguments, 5 | clippy::implicit_hasher, 6 | clippy::module_inception, 7 | clippy::new_without_default 8 | )] 9 | 10 | // Workaround for issue: https://github.com/rust-lang/rust/issues/64450 11 | extern crate offset_mutual_from as mutual_from; 12 | 13 | #[macro_use] 14 | extern crate prettytable; 15 | 16 | #[macro_use] 17 | extern crate quickcheck_derive; 18 | 19 | // #[macro_use] 20 | // extern crate log; 21 | 22 | #[macro_use] 23 | extern crate serde; 24 | 25 | // mod multi_route_util; 26 | 27 | pub mod buyer; 28 | pub mod config; 29 | pub mod file; 30 | pub mod info; 31 | pub mod seller; 32 | pub mod utils; 33 | 34 | pub mod stctrllib; 35 | pub mod stverifylib; 36 | -------------------------------------------------------------------------------- /components/stctrl/src/utils.rs: -------------------------------------------------------------------------------- 1 | use app::common::PublicKey; 2 | use app::report::NodeReport; 3 | 4 | /// Find a friend's public key given his name 5 | pub fn friend_public_key_by_name<'a>( 6 | node_report: &'a NodeReport, 7 | friend_name: &str, 8 | ) -> Option<&'a PublicKey> { 9 | // Search for the friend: 10 | for (friend_public_key, friend_report) in &node_report.funder_report.friends { 11 | if friend_report.name == friend_name { 12 | return Some(friend_public_key); 13 | } 14 | } 15 | None 16 | } 17 | -------------------------------------------------------------------------------- /components/test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-test" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "AGPL-3.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | funder = { path = "../funder", version = "0.1.0", package = "offset-funder" } 12 | crypto = { path = "../crypto", version = "0.1.0", package = "offset-crypto" } 13 | identity = { path = "../identity", version = "0.1.0" , package = "offset-identity" } 14 | timer = { path = "../timer", version = "0.1.0" , package = "offset-timer" } 15 | proto = { path = "../proto", version = "0.1.0" , package = "offset-proto" } 16 | relay = { path = "../relay", version = "0.1.0" , package = "offset-relay" } 17 | net = { path = "../net", version = "0.1.0" , package = "offset-net" } 18 | index_server = { path = "../index_server", version = "0.1.0" , package = "offset-index-server" } 19 | node = { path = "../node", version = "0.1.0" , package = "offset-node" } 20 | database = { path = "../database", version = "0.1.0" , package = "offset-database" } 21 | bin = { path = "../bin", version = "0.1.0" , package = "offset-bin" } 22 | stctrl = { path = "../stctrl", version = "0.1.0" , package = "offset-stctrl" } 23 | stcompact = { path = "../stcompact", version = "0.1.0" , package = "offset-stcompact" } 24 | app = { path = "../app", version = "0.1.0" , package = "offset-app" } 25 | app_client = { path = "../app_client", version = "0.1.0" , package = "offset-app-client" } 26 | connection = { path = "../connection", version = "0.1.0" , package = "offset-connection" } 27 | 28 | futures = "0.3.1" 29 | 30 | log = "0.4" 31 | 32 | [dev-dependencies] 33 | 34 | tempfile = "3.1.0" 35 | env_logger = "0.6.0" 36 | serde_json = "1.0.44" 37 | 38 | # Quickcheck: 39 | quickcheck = {version = "0.9"} 40 | quickcheck_macros = {version = "0.8"} 41 | rand = {version = "0.7.2"} 42 | 43 | futures = {version = "0.3.1", features = ["thread-pool"]} 44 | -------------------------------------------------------------------------------- /components/test/src/cli_tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod basic_cli; 2 | mod stctrl_setup; 3 | -------------------------------------------------------------------------------- /components/test/src/compact_node_wrapper.rs: -------------------------------------------------------------------------------- 1 | use futures::sink::SinkExt; 2 | use futures::stream::StreamExt; 3 | 4 | use common::conn::ConnPair; 5 | 6 | use app::gen::gen_uid; 7 | use stcompact::compact_node::messages::{CompactToUserAck, UserToCompact, UserToCompactAck}; 8 | 9 | #[derive(Debug)] 10 | pub struct CompactNodeWrapperError; 11 | 12 | /// Send a request and wait until the request is acked 13 | pub async fn send_request( 14 | conn_pair: &mut ConnPair, 15 | user_to_compact: UserToCompact, 16 | ) -> Result<(), CompactNodeWrapperError> { 17 | let user_request_id = gen_uid(); 18 | let user_to_compact_ack = UserToCompactAck { 19 | user_request_id: user_request_id.clone(), 20 | inner: user_to_compact, 21 | }; 22 | conn_pair.sender.send(user_to_compact_ack).await.unwrap(); 23 | 24 | // Wait until we get an ack for our request: 25 | while let Some(compact_to_user_ack) = conn_pair.receiver.next().await { 26 | match compact_to_user_ack { 27 | CompactToUserAck::Ack(request_id) => { 28 | if request_id == user_request_id { 29 | break; 30 | } 31 | } 32 | _ => {} 33 | } 34 | } 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /components/test/src/compact_server_wrapper.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | use futures::sink::SinkExt; 4 | use futures::stream::StreamExt; 5 | 6 | use common::conn::ConnPair; 7 | 8 | use app::gen::gen_uid; 9 | use stcompact::messages::{ 10 | NodesStatus, ServerToUser, ServerToUserAck, UserToServer, UserToServerAck, 11 | }; 12 | 13 | #[derive(Debug)] 14 | pub struct CompactServerWrapperError; 15 | 16 | /// Send a request and wait until the request is acked 17 | pub async fn send_request( 18 | conn_pair: &mut ConnPair, 19 | nodes_status: &mut NodesStatus, 20 | user_to_server: UserToServer, 21 | ) -> Result<(), CompactServerWrapperError> { 22 | let request_id = gen_uid(); 23 | let user_to_server_ack = UserToServerAck { 24 | request_id: request_id.clone(), 25 | inner: user_to_server, 26 | }; 27 | conn_pair.sender.send(user_to_server_ack).await.unwrap(); 28 | 29 | // Wait until we get an ack for our request: 30 | while let Some(server_to_user_ack) = conn_pair.receiver.next().await { 31 | match server_to_user_ack { 32 | ServerToUserAck::Ack(in_request_id) => { 33 | if request_id == in_request_id { 34 | break; 35 | } 36 | } 37 | ServerToUserAck::ServerToUser(ServerToUser::NodesStatus(new_nodes_status)) => { 38 | let _ = mem::replace(nodes_status, new_nodes_status); 39 | } 40 | _ => {} 41 | } 42 | } 43 | Ok(()) 44 | } 45 | -------------------------------------------------------------------------------- /components/test/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![type_length_limit = "20844883"] 3 | #![deny(trivial_numeric_casts, warnings)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[cfg(test)] 12 | #[macro_use] 13 | extern crate log; 14 | 15 | #[cfg(test)] 16 | #[macro_use] 17 | extern crate common; 18 | 19 | #[cfg(test)] 20 | extern crate quickcheck; 21 | 22 | // #[cfg(test)] 23 | // #[macro_use(quickcheck)] 24 | // extern crate quickcheck_macros; 25 | 26 | /* 27 | #[cfg(test)] 28 | #[macro_use] 29 | extern crate quickcheck_derive; 30 | */ 31 | 32 | #[cfg(test)] 33 | mod sim_network; 34 | 35 | #[cfg(test)] 36 | mod utils; 37 | 38 | #[cfg(test)] 39 | mod app_wrapper; 40 | 41 | #[cfg(test)] 42 | mod compact_node_wrapper; 43 | 44 | #[cfg(test)] 45 | mod compact_server_wrapper; 46 | 47 | #[cfg(test)] 48 | mod node_report_service; 49 | 50 | #[cfg(test)] 51 | mod compact_report_service; 52 | 53 | #[cfg(test)] 54 | mod tests; 55 | 56 | #[cfg(test)] 57 | mod cli_tests; 58 | -------------------------------------------------------------------------------- /components/test/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod compact_node_payment; 2 | mod compact_server_remote_node; 3 | mod handle_error_command; 4 | mod nodes_chain; 5 | mod relay_migration; 6 | mod resolve_inconsistency; 7 | mod serialize; 8 | mod two_nodes_payment; 9 | -------------------------------------------------------------------------------- /components/timer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-timer" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | log = "0.4" 11 | 12 | bytes = "0.5.4" 13 | 14 | futures = "0.3.1" 15 | 16 | async-std = {version = "1.6.2", features=["unstable"]} 17 | 18 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 19 | 20 | [dev-dependencies] 21 | 22 | futures = {version = "0.3.1", features = ["thread-pool"]} 23 | 24 | -------------------------------------------------------------------------------- /components/timer/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/timer/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | #[macro_use] 15 | extern crate common; 16 | 17 | mod timer; 18 | pub mod utils; 19 | 20 | pub use self::timer::{ 21 | create_timer, create_timer_incoming, dummy_timer_multi_sender, TimerClient, TimerTick, 22 | }; 23 | -------------------------------------------------------------------------------- /components/version/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "offset-version" 3 | version = "0.1.0" 4 | authors = ["real "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2018" 7 | 8 | [dependencies] 9 | 10 | common = { path = "../common", version = "0.1.0", package = "offset-common" } 11 | 12 | log = "0.4" 13 | futures = "0.3.1" 14 | 15 | byteorder = "1.1" 16 | 17 | [dev-dependencies] 18 | 19 | futures = {version = "0.3.1", features = ["thread-pool"]} 20 | -------------------------------------------------------------------------------- /components/version/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 real 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /components/version/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![deny(trivial_numeric_casts, warnings)] 3 | #![allow(intra_doc_link_resolution_failure)] 4 | #![allow( 5 | clippy::too_many_arguments, 6 | clippy::implicit_hasher, 7 | clippy::module_inception, 8 | clippy::new_without_default 9 | )] 10 | 11 | #[macro_use] 12 | extern crate log; 13 | 14 | mod version_prefix; 15 | 16 | pub use self::version_prefix::VersionPrefix; 17 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | 1.44.0 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | --------------------------------------------------------------------------------