├── .bazelrc
├── .clang-format
├── .github
├── issue_template.md
├── pull_request_template.md
└── workflows
│ └── test.yml
├── .gitignore
├── BUILD
├── CHANGELOG
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── WORKSPACE
├── common
├── BUILD
├── commands
│ ├── BUILD
│ ├── command.h
│ ├── errors.cc
│ └── errors.h
├── common.cc
├── common.h
├── converter.cc
├── converter.h
├── crypto
│ ├── BUILD
│ ├── argon2_provider.cc
│ ├── argon2_provider.h
│ ├── manager.cc
│ ├── manager.h
│ ├── provider_base.cc
│ ├── provider_base.h
│ ├── tests
│ │ └── types.cc
│ ├── types.cc
│ └── types.h
├── flags.cc
├── flags.h
├── grpc_server_base.cc
├── grpc_server_base.h
├── http_server_base.cc
├── http_server_base.h
├── server_base.h
├── stats
│ ├── BUILD
│ ├── session.cc
│ └── session.h
└── tests
│ ├── BUILD
│ └── runner.cc
├── docker
└── BUILD
├── docs
├── checksum_validation.md
├── getting_started.md
├── hip
│ ├── 001-sign_bundle.md
│ ├── 002-signing_server.md
│ └── template.md
├── http_rest_api.md
├── integration_scenarios.md
├── pull_request_template.md
├── python
│ ├── .gitignore
│ ├── README.md
│ ├── argon2_authentication_token.py
│ ├── generate_proto.sh
│ └── ssl_client.py
├── secure_server.md
└── ssl
│ ├── .gitignore
│ ├── grpc
│ ├── 01_generate_ca.sh
│ ├── 02_generate_server.sh
│ └── 03_generate_client.sh
│ └── rest
│ └── generate.sh
├── doxyfile
├── hooks
├── autohook.sh
├── pre-commit
│ ├── 01-buildifier-check
│ ├── 02-cpplint
│ └── 03-format-check
└── scripts
│ ├── buildifier_check
│ ├── cpplint
│ └── format_check
├── hub.png
├── hub
├── BUILD
├── auth
│ ├── BUILD
│ ├── dummy_provider.h
│ ├── hmac_provider.cc
│ ├── hmac_provider.h
│ ├── manager.cc
│ ├── manager.h
│ ├── provider.h
│ ├── sign_bundle_context.cc
│ ├── sign_bundle_context.h
│ └── tests
│ │ └── hmac_provider.cc
├── bundle
│ ├── BUILD
│ ├── bundle_utils.cc
│ └── bundle_utils.h
├── commands
│ ├── BUILD
│ ├── balance_subscription.cc
│ ├── balance_subscription.h
│ ├── converter.cc
│ ├── converter.h
│ ├── create_user.cc
│ ├── create_user.h
│ ├── events.h
│ ├── factory.h
│ ├── get_address_info.cc
│ ├── get_address_info.h
│ ├── get_balance.cc
│ ├── get_balance.h
│ ├── get_deposit_address.cc
│ ├── get_deposit_address.h
│ ├── get_seed_for_address.cc
│ ├── get_seed_for_address.h
│ ├── get_seed_for_uuid.cc
│ ├── get_seed_for_uuid.h
│ ├── get_stats.cc
│ ├── get_stats.h
│ ├── get_user_history.cc
│ ├── get_user_history.h
│ ├── helper.cc
│ ├── helper.h
│ ├── process_transfer_batch.cc
│ ├── process_transfer_batch.h
│ ├── recover_funds.cc
│ ├── recover_funds.h
│ ├── sign_bundle.cc
│ ├── sign_bundle.h
│ ├── sweep_detail.cc
│ ├── sweep_detail.h
│ ├── sweep_info.cc
│ ├── sweep_info.h
│ ├── sweep_subscription.cc
│ ├── sweep_subscription.h
│ ├── tests
│ │ ├── helper.cc
│ │ ├── helper.h
│ │ ├── runner.h
│ │ ├── test_balance_subscription.cc
│ │ ├── test_create_user.cc
│ │ ├── test_get_address_info.cc
│ │ ├── test_get_balance.cc
│ │ ├── test_get_deposit_address.cc
│ │ ├── test_get_user_history.cc
│ │ ├── test_process_transfer_batch.cc
│ │ ├── test_user_withdraw.cc
│ │ └── test_user_withdraw_cancel.cc
│ ├── user_withdraw.cc
│ ├── user_withdraw.h
│ ├── user_withdraw_cancel.cc
│ ├── user_withdraw_cancel.h
│ ├── was_address_spent_from.cc
│ ├── was_address_spent_from.h
│ ├── was_withdrawal_cancelled.cc
│ └── was_withdrawal_cancelled.h
├── crypto
│ ├── BUILD
│ ├── local_provider.cc
│ ├── local_provider.h
│ ├── remote_signing_provider.cc
│ ├── remote_signing_provider.h
│ └── tests
│ │ └── local_signing_provider.cc
├── db
│ ├── BUILD
│ ├── CPPLINT.cfg
│ ├── connection.h
│ ├── connection_impl.h
│ ├── db.cc
│ ├── db.h
│ ├── helper.cc
│ ├── helper.h
│ ├── mariadb.cc
│ ├── mariadb.h
│ ├── sqlite3.cc
│ ├── sqlite3.h
│ ├── tests
│ │ └── trigger.cc
│ └── types.h
├── iota
│ ├── BUILD
│ ├── local_pow.cc
│ ├── local_pow.h
│ ├── pow.cc
│ ├── pow.h
│ ├── remote_pow.h
│ └── tests
│ │ └── local_pow.cc
├── main.cc
├── server
│ ├── BUILD
│ ├── grpc.cc
│ ├── grpc.h
│ ├── grpc_server.cc
│ ├── grpc_server.h
│ ├── http_json_server.cc
│ ├── http_json_server.h
│ ├── hub_server_base.cc
│ └── hub_server_base.h
├── service
│ ├── BUILD
│ ├── CPPLINT.cfg
│ ├── address_monitor.cc
│ ├── address_monitor.h
│ ├── attachment_service.cc
│ ├── attachment_service.h
│ ├── scheduled_service.cc
│ ├── scheduled_service.h
│ ├── service.cc
│ ├── service.h
│ ├── sweep_service.cc
│ ├── sweep_service.h
│ ├── tests
│ │ ├── address_monitor.cc
│ │ └── scheduled_service.cc
│ ├── user_address_monitor.cc
│ └── user_address_monitor.h
└── tests
│ ├── BUILD
│ ├── runner.cc
│ └── runner.h
├── proto
├── BUILD
├── hub.proto
├── messages.proto
├── signing_server.proto
└── signing_server_messages.proto
├── requirements.txt
├── schema
├── BUILD
├── ddl2cpp.py
├── delta.mariadb.sql
├── delta.sqlite3.sql
├── schema.sql
├── triggers.mariadb.sql
└── triggers.sqlite3.sql
├── signing_server
├── BUILD
├── commands
│ ├── BUILD
│ ├── get_address_for_uuid.cc
│ ├── get_address_for_uuid.h
│ ├── get_security_level.cc
│ ├── get_security_level.h
│ ├── get_seed_for_uuid.cc
│ ├── get_seed_for_uuid.h
│ ├── get_signature_for_uuid.cc
│ ├── get_signature_for_uuid.h
│ ├── helper.cc
│ └── helper.h
├── grpc.cc
├── grpc.h
├── main.cc
├── server.cc
└── server.h
├── third-party
├── cpprest
│ └── BUILD.bzl
├── date
│ └── BUILD.bzl
├── mariadb_connector
│ └── BUILD.bzl
├── sqlpp11
│ └── BUILD.bzl
├── sqlpp11mysql
│ └── BUILD.bzl
└── sqlpp11sqlite
│ └── BUILD.bzl
└── tools
├── bazel.rc
├── buildifier
├── ci
└── build.sh
├── cpplint
├── cpplint.py
└── remote.rc
/.bazelrc:
--------------------------------------------------------------------------------
1 | import %workspace%/tools/bazel.rc
2 | import %workspace%/tools/remote.rc
3 | try-import %workspace%/user.bazelrc
4 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | The issue tracker is only for reporting bugs or submitting feature requests.
4 | If you have general questions on IOTA you can go to https://iota.stackexchange.com/, https://helloiota.com/, or browse Discord channels (https://discord.gg/C88Wexg).
5 |
6 |
7 |
8 | ### Bug description
9 | A general description of the bug.
10 |
11 | ### Hardware Spec
12 | On what hardware is the node running on?
13 |
14 | ### Steps To Reproduce
15 | 1.
16 | 2.
17 | 3.
18 |
19 | ### Expected behaviour
20 | What should happen.
21 |
22 | ### Actual behaviour
23 | What really happened.
24 |
25 | ### Errors
26 | Paste any errors that you see.
27 |
28 |
29 |
30 |
31 | *Note*
32 | The feature request will probably be integrated faster if you do a pull request for it.
33 | If you want to discuss the feature before you actually write the code you are welcome to do it by first submitting an issue.
34 |
35 | ### Description
36 | Briefly describe the feature you want.
37 |
38 | ### Motivation
39 | Explain why this feature is needed.
40 |
41 | ### Requirements
42 | Create a list of what you want this feature request to fulfill.
43 |
44 | ### Open Questions (optional)
45 | Anything you want to discuss.
46 |
47 | ### Am I planning to do it myself with a PR?
48 | Yes/No.
49 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
9 |
10 | # Description
11 |
12 | _Please include a summary of the change. Include the motivation for the change._
13 |
14 | Fixes # (issue)
15 |
16 | ## Type of change
17 |
18 | _Please delete options that are not relevant._
19 |
20 | - Bug fix (a non-breaking change which fixes an issue)
21 | - Enhancement (a non-breaking change which adds functionality)
22 | - Breaking change (fix or feature that would cause existing functionality to not work as expected)
23 | - Documentation Fix
24 |
25 | # How Has This Been Tested?
26 |
27 | _Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration_
28 |
29 | - Test A
30 | - Test B
31 |
32 |
33 | # Checklist:
34 |
35 | _Please delete items that are not relevant._
36 |
37 | - [ ] My code follows the style guidelines for this project
38 | - [ ] I have performed a self-review of my own code
39 | - [ ] I have commented my code, particularly in hard-to-understand areas
40 | - [ ] I have made corresponding changes to the documentation
41 | - [ ] I have added tests that prove my fix is effective or that my feature works
42 | - [ ] New and existing unit tests pass locally with my changes
43 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | test:
11 | runs-on: ubuntu-20.04
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Bazel test opt
17 | run: bazel test -c opt --test_output=all //...
18 | env:
19 | USE_BAZEL_VERSION: 3.3.1
20 |
21 | - name: Bazel test debug
22 | run: bazel test -c dbg --test_output=all //...
23 | env:
24 | USE_BAZEL_VERSION: 3.3.1
25 |
26 | # - name: Bazel test bootlin x86_64 toolchains
27 | # run: bazel test --crosstool_top=@iota_toolchains//tools/x86-64-core-i7--glibc--bleeding-edge-2018.07-1:toolchain --cpu=x86_64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain //...
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bazel-*
2 | compile_commands.json
3 | GPATH
4 | GTAGS
5 | GRTAGS
6 | .#*
7 | hub.db
8 | .gdb_history
9 | .idea/
10 | tulsi*
11 | html
12 |
--------------------------------------------------------------------------------
/BUILD:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iotaledger-archive/hub/9df503d4def3021b082ba7aaaace7a9265e2ba18/BUILD
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | - Jun 13 2018, PR #154 - hub/crypto: change default argon2 method & parameters
2 | Default argon2 method was changed from argon2i to argon2id
3 | Default argon2 time cost was changed from 1 to 4
4 | Default argon2 memory cost was changed from 1<<16 to 1<<17
5 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @th0br0 @tsvisabo
2 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
Responsible disclosure policy
2 |
3 | At the IOTA Foundation, we consider the security of our systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present. If you've discovered a vulnerability, please follow the guidelines below to report it to our security team:
4 |
5 | - E-mail your findings to secops@iota.org. If the report contains highly sensitive information, please consider encrypting your findings using our contact@iota.org (466385BD0B40D9550F93C04746A440CCE5664A64) PGP key.
6 |
7 | Please follow these rules when testing/reporting vulnerabilities:
8 |
9 | - Do not take advantage of the vulnerability you have discovered, for example by downloading more data than is necessary to demonstrate the vulnerability.
10 | - Do not read, modify or delete data that isn't you own.
11 | - We ask that you do not to disclosure the problem to third parties until it has been resolved.
12 | - The scope of the program is limited to technical vulnerabilities in IOTA Foundations's web applications and open source software packages distributed through GitHub, please do not try to test physical security or attempt phishing attacks against our employees, and so on.
13 | - Out of concern for the availability of our services to all users, please do not attempt to carry out DoS attacks, leverage black hat SEO techniques, spam people, and do other similarly questionable things. We also discourage the use of any vulnerability testing tools that automatically generate significant volumes of traffic.
14 |
15 | What we promise:
16 |
17 | - We will respond to your report within 3 business days with our evaluation of the report and an expected resolution date.
18 | - If you have followed the instructions above, we will not take any legal action against you in regard to the report.
19 | - We will keep you informed during all stages of resolving the problem.
20 | - To show our appreciation for your effort and cooperation during the report, we will list your name and a link to a personal website/social network profile on the page below so that the public can know you've helped keep the IOTA Foundation secure.
21 |
22 | We sincerely appreciate the efforts of security researchers in keeping our community safe.
23 |
24 |
--------------------------------------------------------------------------------
/common/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "common",
3 | srcs = glob(["*.cc"]),
4 | hdrs = glob([
5 | "*.h",
6 | ]),
7 | visibility = ["//visibility:public"],
8 | deps = [
9 | "//common/commands",
10 | "//common/crypto:types",
11 | "//common/stats",
12 | "//proto:hub_grpc_cc",
13 | "@boost//:beast",
14 | "@boost//:property_tree",
15 | "@com_github_gflags_gflags//:gflags",
16 | "@com_github_google_glog//:glog",
17 | "@com_github_grpc_grpc//:grpc++",
18 | ],
19 | )
20 |
--------------------------------------------------------------------------------
/common/commands/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "commands",
3 | srcs = glob(["*.cc"]),
4 | hdrs = glob([
5 | "*.h",
6 | ]),
7 | visibility = ["//visibility:public"],
8 | deps = [
9 | "//common/crypto:types",
10 | "//common/stats",
11 | "@boost//:beast",
12 | "@boost//:property_tree",
13 | "@com_github_gflags_gflags//:gflags",
14 | "@com_github_google_glog//:glog",
15 | "@com_github_grpc_grpc//:grpc++",
16 | "@TangleScope//cppclient:beast",
17 | ],
18 | )
19 |
--------------------------------------------------------------------------------
/common/commands/errors.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_ERRORS_H_
9 | #define COMMON_ERRORS_H_
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include "grpc++/grpc++.h"
16 |
17 | namespace common {
18 |
19 | namespace cmd {
20 |
21 | typedef enum {
22 |
23 | OK = 0,
24 | MISSING_ARGUMENT,
25 | WRONG_ARGUMENT_NAME,
26 | CANCELLED,
27 | USER_EXISTS,
28 | USER_DOES_NOT_EXIST,
29 | UNKNOWN_ADDRESS,
30 | UNKNOWN_ERROR,
31 | GET_ADDRESS_FAILED,
32 | INVALID_UUID,
33 | INVALID_CHECKSUM,
34 | INVALID_ADDRESS,
35 | ADDRESS_WAS_SPENT,
36 | IOTA_NODE_UNAVAILABLE,
37 | WITHDRAWAL_CAN_NOT_BE_CANCELLED,
38 | INVALID_AUTHENTICATION,
39 | SIGNATURE_FAILED,
40 | WRONG_USER_ADDRESS,
41 | ADDRESS_NOT_KNOWN_TO_NODE,
42 | ADDRESS_BALANCE_ZERO,
43 | BATCH_INVALID,
44 | BATCH_INCONSISTENT,
45 | BATCH_AMOUNT_NOT_ZERO,
46 | INSUFFICIENT_BALANCE,
47 |
48 | } Error;
49 |
50 | std::unordered_map errorToStringMapCreate();
51 |
52 | grpc::Status errorToGrpcError(Error err);
53 |
54 | std::string getErrorString(Error);
55 |
56 | } // namespace cmd
57 | } // namespace common
58 |
59 | #endif // COMMON_ERRORS_H_
60 |
--------------------------------------------------------------------------------
/common/common.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common.h"
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | #include
15 |
16 | namespace common {
17 |
18 | std::string readFile(const std::string& fileName) {
19 | std::ifstream ifs(fileName.c_str());
20 |
21 | if (!ifs.good()) {
22 | LOG(FATAL) << "File: " << fileName << " does not exist.";
23 | }
24 |
25 | std::stringstream buffer;
26 |
27 | buffer << ifs.rdbuf();
28 | return buffer.str();
29 | }
30 | } // namespace common
31 |
--------------------------------------------------------------------------------
/common/common.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_COMMON_H_
9 | #define COMMON_COMMON_H_
10 |
11 | #include
12 |
13 | namespace common {
14 |
15 | std::string readFile(const std::string& fileName);
16 | }
17 |
18 | #endif // COMMON_COMMON_H_
19 |
--------------------------------------------------------------------------------
/common/converter.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common/converter.h"
9 |
10 | namespace common {
11 |
12 | std::string boolToString(bool isTrue) { return isTrue ? "true" : "false"; }
13 | bool stringToBool(std::string_view isTrueStr) {
14 | return (isTrueStr.compare("true") == 0) ? true : false;
15 | }
16 |
17 | uint64_t timepointToUint64(std::chrono::system_clock::time_point timepoint) {
18 | return std::chrono::duration_cast(
19 | timepoint.time_since_epoch())
20 | .count();
21 | }
22 | } // namespace common
23 |
--------------------------------------------------------------------------------
/common/converter.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_CONVERTER_H_
9 | #define COMMON_CONVERTER_H_
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | namespace common {
16 | std::string boolToString(bool isTrue);
17 | bool stringToBool(std::string_view isTrueStr);
18 |
19 | uint64_t timepointToUint64(std::chrono::system_clock::time_point timepoint);
20 | }
21 |
22 | #endif // COMMON_COMMON_H_
23 |
--------------------------------------------------------------------------------
/common/crypto/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "crypto",
3 | srcs = [
4 | "manager.cc",
5 | "provider_base.cc",
6 | ],
7 | hdrs = [
8 | "manager.h",
9 | "provider_base.h",
10 | ],
11 | visibility = ["//visibility:public"],
12 | deps = [
13 | ":types",
14 | "//proto:signing_server_grpc_cc",
15 | "@optional_lite",
16 | "@org_iota_common//common/helpers:checksum",
17 | ],
18 | )
19 |
20 | cc_library(
21 | name = "types",
22 | srcs = ["types.cc"],
23 | hdrs = [
24 | "types.h",
25 | ],
26 | visibility = ["//visibility:public"],
27 | deps = [
28 | "@boost//:random",
29 | "@com_github_google_glog//:glog",
30 | ],
31 | )
32 |
33 | cc_library(
34 | name = "argon2_provider",
35 | srcs = ["argon2_provider.cc"],
36 | hdrs = ["argon2_provider.h"],
37 | visibility = ["//visibility:public"],
38 | deps = [
39 | ":crypto",
40 | "//common",
41 | "@argon2",
42 | "@boost//:interprocess",
43 | "@com_github_google_glog//:glog",
44 | "@iota_lib_cpp",
45 | "@org_iota_common//common/crypto/iss/v1:iss_kerl",
46 | "@org_iota_common//common/crypto/kerl:converter",
47 | "@org_iota_common//common/helpers:sign",
48 | "@org_iota_common//common/trinary:trit_tryte",
49 | ],
50 | )
51 |
52 | cc_test(
53 | name = "test_crypto",
54 | srcs = glob([
55 | "tests/**/*.cc",
56 | ]),
57 | deps = [
58 | ":argon2_provider",
59 | "//common/tests",
60 | "@boost//:interprocess",
61 | "@com_google_googletest//:gtest",
62 | ],
63 | )
64 |
--------------------------------------------------------------------------------
/common/crypto/argon2_provider.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_CRYPTO_ARGON2_PROVIDER_H_
9 | #define COMMON_CRYPTO_ARGON2_PROVIDER_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "common/crypto/provider_base.h"
15 |
16 | namespace common {
17 | namespace crypto {
18 |
19 | /// Argon2Provider class.
20 | /// The argon2 provider provides the cryptographic services necessary to
21 | /// obtain new addresses based on salt and sign bundle hashes.
22 | class Argon2Provider : public CryptoProviderBase {
23 | public:
24 | Argon2Provider() = delete;
25 | /// Constructor
26 | /// param[in] salt - the salt that will be used in calculations
27 | explicit Argon2Provider(std::string salt);
28 |
29 | /// Get a new address for a given UUID and the salt
30 | /// param[in] UUID - a UUID
31 | nonstd::optional getAddressForUUID(
32 | const common::crypto::UUID& uuid) const override;
33 |
34 | /// The current security level
35 | /// @return size_t - the security level (1 - 3)
36 | nonstd::optional securityLevel(
37 | const common::crypto::UUID& uuid) const override;
38 |
39 | /// Calculate the seed for a UUID.
40 | /// param[in] UUID - a UUID
41 | /// @return string - the seed
42 |
43 | virtual std::string getSeedFromUUID(
44 | const common::crypto::UUID& uuid) const override;
45 |
46 | protected:
47 | /// Calculate the signature for a UUID and a bundle hash
48 | /// param[in] UUID - a UUID
49 | /// param[in] Hash - a bundleHash
50 | /// @return string - the signature
51 | nonstd::optional doGetSignatureForUUID(
52 | const common::crypto::UUID& uuid,
53 | const common::crypto::Hash& bundleHash) const override;
54 |
55 | private:
56 | /// The salt that will be used all throughout the lifetime of the provider
57 | const std::string _salt;
58 |
59 | static constexpr uint32_t _argon_t_cost{1};
60 | static constexpr uint32_t _argon_m_cost{1 << 16}; // 64mebibytes
61 | static constexpr uint32_t _argon_parallelism{1};
62 | };
63 |
64 | } // namespace crypto
65 | } // namespace common
66 | #endif // COMMON_CRYPTO_ARGON2_PROVIDER_H_
67 |
--------------------------------------------------------------------------------
/common/crypto/manager.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common/crypto/manager.h"
9 |
10 | namespace common {
11 | namespace crypto {
12 |
13 | CryptoManager& CryptoManager::get() {
14 | static CryptoManager instance;
15 |
16 | return instance;
17 | }
18 |
19 | } // namespace crypto
20 | } // namespace common
21 |
--------------------------------------------------------------------------------
/common/crypto/manager.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_CRYPTO_MANAGER_H_
9 | #define COMMON_CRYPTO_MANAGER_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "common/crypto/provider_base.h"
15 |
16 | namespace common {
17 | namespace crypto {
18 |
19 | /// CryptoManager holds the single instance of a CryptoProvider
20 | class CryptoManager {
21 | private:
22 | /// Constructor
23 | CryptoManager() {}
24 | /// deleted
25 | CryptoManager(CryptoManager const&) = delete;
26 | /// deleted
27 | CryptoManager(CryptoManager&&) = delete;
28 | /// deleted
29 | CryptoManager& operator=(CryptoManager const&) = delete;
30 | /// deleted
31 | CryptoManager& operator=(CryptoManager&&) = delete;
32 |
33 | public:
34 | /// Get the singleton instance
35 | /// @return CryptoManager - the singleton instance of CryptoManager
36 | static CryptoManager& get();
37 |
38 | /// Set the cryptography provider
39 | /// @param[in] provider - an instance of CryptoProvider
40 | void setProvider(std::unique_ptr provider) {
41 | _provider = std::move(provider);
42 | }
43 |
44 | /// Get the cryptography provider
45 | /// @return CryptoProvider - an instance of CryptoProvider
46 | CryptoProviderBase& provider() { return *_provider; }
47 |
48 | private:
49 | /// The cryptography provider
50 | std::unique_ptr _provider;
51 | };
52 |
53 | } // namespace crypto
54 | } // namespace common
55 | #endif // COMMON_CRYPTO_MANAGER_H_
56 |
--------------------------------------------------------------------------------
/common/crypto/provider_base.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common/crypto/provider_base.h"
9 | #include "common/helpers/checksum.h"
10 |
11 | namespace common {
12 | namespace crypto {
13 |
14 | common::crypto::Checksum CryptoProviderBase::calcChecksum(
15 | std::string_view address) const {
16 | char* checksumPtr = iota_checksum(address.data(), address.size(),
17 | common::crypto::Checksum::length());
18 | auto result = common::crypto::Checksum(checksumPtr);
19 | std::free(checksumPtr);
20 | return result;
21 | }
22 |
23 | nonstd::optional
24 | CryptoProviderBase::verifyAndStripChecksum(const std::string& address) const {
25 | auto addressView =
26 | std::string_view(address).substr(0, common::crypto::Address::length());
27 | auto checksumView = std::string_view(address).substr(
28 | common::crypto::Address::length(),
29 | common::crypto::Address::length() + common::crypto::Checksum::length());
30 | if (calcChecksum(addressView).str_view() == checksumView) {
31 | return common::crypto::Address(
32 | address.substr(0, common::crypto::Address::length()));
33 | }
34 | return {};
35 | }
36 |
37 | } // namespace crypto
38 | } // namespace common
39 |
--------------------------------------------------------------------------------
/common/crypto/tests/types.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 IOTA Foundation
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "common/crypto/types.h"
9 |
10 | namespace {
11 |
12 | struct TestTag {};
13 |
14 | using TestArr = common::crypto::TryteArray<12, TestTag>;
15 |
16 | class TrytesArrayTest : public ::testing::Test {};
17 |
18 | TEST_F(TrytesArrayTest, EnforceCorrectLength) {
19 | EXPECT_THROW(TestArr{""}, std::runtime_error);
20 | }
21 |
22 | TEST_F(TrytesArrayTest, EnforceValidCharacters) {
23 | EXPECT_THROW(TestArr{"WhatTheHell?"}, std::runtime_error);
24 | }
25 |
26 | TEST_F(TrytesArrayTest, AssertInternalRepresentationIsConsistent) {
27 | auto data =
28 | "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
29 | "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
30 | common::crypto::Hash testHash(data);
31 | ASSERT_EQ(testHash.str(), data);
32 | }
33 |
34 | class UUIDTest : public ::testing::Test {};
35 |
36 | TEST_F(UUIDTest, AssertInternalRepresentationIsConsistent) {
37 | common::crypto::UUID uuidOrig;
38 | std::string_view stringRepresentation = uuidOrig.str_view();
39 |
40 | auto uuidClone = common::crypto::UUID(stringRepresentation);
41 |
42 | ASSERT_EQ(uuidClone.str(), uuidOrig.str());
43 | }
44 |
45 | }; // namespace
46 |
--------------------------------------------------------------------------------
/common/crypto/types.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common/crypto/types.h"
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | namespace common {
17 | namespace crypto {
18 |
19 | std::array UUID::generate() {
20 | std::array res;
21 | boost::random::random_device rd;
22 | boost::random::uniform_int_distribution<> index_dist(0, UUID_SIZE - 1);
23 | for (uint32_t i = 0; i < UUID_SIZE; ++i) {
24 | res[i] = BASE64_CHARS[index_dist(rd)];
25 | }
26 | return res;
27 | }
28 |
29 | std::array UUID::fromStringView(
30 | const std::string_view& sv) {
31 | std::array res;
32 | std::copy(std::begin(sv), std::end(sv), std::begin(res));
33 | return res;
34 | }
35 |
36 | UUID::UUID() {
37 | try {
38 | _data = std::move(UUID::generate());
39 | } catch (const std::exception& ex) {
40 | LOG(FATAL) << " Failed in generating UUID: " << ex.what();
41 | }
42 | }
43 |
44 | UUID::UUID(const std::string_view& sv) : _data(fromStringView(sv)) {}
45 |
46 | std::string UUID::str() const { return std::string(str_view()); }
47 |
48 | std::string_view UUID::str_view() const {
49 | return std::string_view(reinterpret_cast(_data.data()),
50 | UUID_SIZE);
51 | }
52 |
53 | const std::array& UUID::data() const {
54 | return _data;
55 | }
56 |
57 | bool operator==(const common::crypto::UUID& lhs,
58 | const common::crypto::UUID& rhs) {
59 | return lhs.data() == rhs.data();
60 | }
61 |
62 | bool operator!=(const common::crypto::UUID& lhs,
63 | const common::crypto::UUID& rhs) {
64 | return !(lhs == rhs);
65 | }
66 | } // namespace crypto
67 | } // namespace common
68 |
--------------------------------------------------------------------------------
/common/flags.cc:
--------------------------------------------------------------------------------
1 | #include "common/flags.h"
2 |
3 | namespace common {
4 | namespace flags {
5 |
6 | DEFINE_string(salt, "", "Salt for local seed provider");
7 | DEFINE_string(listenAddress, "0.0.0.0:50051", "address to listen on");
8 | // Server side credentials
9 | DEFINE_string(sslCert, "/dev/null", "Path to SSL certificate");
10 | DEFINE_string(sslKey, "/dev/null", "Path to SSL certificate key");
11 | DEFINE_string(sslCA, "/dev/null", "Path to CA root");
12 | DEFINE_string(sslDH, "/dev/null",
13 | "Path to Diffie Hellman parameters (when using REST)");
14 |
15 | DEFINE_string(authMode, "none", "credentials to use. can be {none, ssl}");
16 | // Argon2
17 | DEFINE_uint32(maxConcurrentArgon2Hash, 4,
18 | "Max number of concurrent Argon2 Hash processes");
19 | DEFINE_uint32(argon2TCost, 4, "Time cost of Argon2");
20 | DEFINE_uint32(argon2MCost, 1 << 17, "Memory cost of Argon2 in bytes");
21 | DEFINE_uint32(argon2Parallelism, 1,
22 | "Number of threads to use in parallel for Argon2");
23 | DEFINE_uint32(argon2Mode, 2, "Argon2 mode to use: 1=argon2i;2,else=argon2id");
24 | DEFINE_uint32(keySecLevel, 2, "Security level for IOTA signature");
25 |
26 | DEFINE_uint32(numThreadsHttp, 4,
27 | "The number of threads the http server should run");
28 | } // namespace flags
29 | } // namespace common
30 |
--------------------------------------------------------------------------------
/common/flags.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_FLAGS_H_
9 | #define COMMON_FLAGS_H_
10 |
11 | #include
12 | #include
13 |
14 | namespace common {
15 | namespace flags {
16 | DECLARE_string(salt);
17 | DECLARE_string(listenAddress);
18 | DECLARE_string(sslCert);
19 | DECLARE_string(sslKey);
20 | DECLARE_string(sslCA);
21 | DECLARE_string(authMode);
22 | // Argon2
23 | DECLARE_uint32(maxConcurrentArgon2Hash);
24 | DECLARE_uint32(argon2TCost);
25 | DECLARE_uint32(argon2MCost);
26 | DECLARE_uint32(argon2Parallelism);
27 | DECLARE_uint32(argon2Mode);
28 | // IOTA seeds
29 | DECLARE_uint32(keySecLevel);
30 | // Http server
31 | DECLARE_uint32(numThreadsHttp);
32 | DECLARE_string(sslDH);
33 | } // namespace flags
34 | } // namespace common
35 |
36 | #endif // COMMON_FLAGS_H_
--------------------------------------------------------------------------------
/common/grpc_server_base.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include
9 |
10 | #include "common/common.h"
11 | #include "common/grpc_server_base.h"
12 |
13 | namespace common {
14 |
15 | void GrpcServerBase::runAndWait() { _server->Wait(); }
16 |
17 | std::shared_ptr GrpcServerBase::makeCredentials(
18 | const std::string& authMode, const std::string& sslCertPath,
19 | const std::string& sslKeyPath, const std::string& sslCAPath) {
20 | LOG(INFO) << "Using auth mode: " << authMode;
21 | if (authMode == "none") {
22 | return grpc::InsecureServerCredentials();
23 | } else if (authMode == "ssl") {
24 | grpc::SslServerCredentialsOptions options;
25 |
26 | grpc::SslServerCredentialsOptions::PemKeyCertPair keycert = {
27 | readFile(sslKeyPath), readFile(sslCertPath)};
28 |
29 | options.pem_key_cert_pairs.push_back(keycert);
30 | options.pem_root_certs = readFile(sslCAPath);
31 | options.client_certificate_request =
32 | GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
33 | return grpc::SslServerCredentials(options);
34 | }
35 |
36 | LOG(FATAL) << "Unknown auth mode: " << authMode;
37 | }
38 | } // namespace common
39 |
--------------------------------------------------------------------------------
/common/grpc_server_base.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_GRPC_SERVER_BASE_H_
9 | #define COMMON_GRPC_SERVER_BASE_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "server_base.h"
15 | #include "grpc++/grpc++.h"
16 |
17 | namespace common {
18 |
19 | class GrpcServerBase : public ServerBase {
20 | public:
21 | /// Runs the service and waits for requests
22 | virtual void runAndWait() override ;
23 |
24 | protected:
25 | std::unique_ptr _server;
26 | std::shared_ptr makeCredentials(
27 | const std::string& authMode, const std::string& sslCertPath,
28 | const std::string& sslKeyPath, const std::string& sslCAPath);
29 | };
30 | } // namespace common
31 |
32 | #endif // COMMON_GRPC_SERVER_BASE_H_
33 |
--------------------------------------------------------------------------------
/common/http_server_base.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_HTTP_SERVER_BASE_H_
9 | #define COMMON_HTTP_SERVER_BASE_H_
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include "server_base.h"
22 |
23 | namespace common {
24 |
25 | class HttpServerBase : public ServerBase {
26 | public:
27 | typedef enum { OK = 0, COMMAND_NOT_FOUND, WRONG_REQUEST_FORMAT } ErrorCode;
28 | /// Runs the service and waits for requests
29 | virtual void runAndWait() override;
30 | virtual ErrorCode handleRequestImpl(std::string_view request_body,
31 | std::string& response) = 0;
32 | private:
33 | static void setupCredentials(boost::asio::ssl::context& ctx);
34 | };
35 | } // namespace common
36 |
37 | #endif // COMMON_HTTP_SERVER_BASE_H_
38 |
--------------------------------------------------------------------------------
/common/server_base.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_SERVER_BASE_H_
9 | #define COMMON_SERVER_BASE_H_
10 |
11 | #include "common/flags.h"
12 |
13 | namespace common {
14 |
15 | class ServerBase {
16 | public:
17 | /// Creates and initializes the API interface.
18 | virtual void initialize() = 0;
19 | /// Runs the service and waits for requests
20 | virtual void runAndWait() = 0;
21 | };
22 | } // namespace common
23 |
24 | #endif // COMMON_SERVER_BASE_H_
25 |
--------------------------------------------------------------------------------
/common/stats/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "stats",
3 | srcs = glob(["**/*.cc"]),
4 | hdrs = glob(["**/*.h"]),
5 | visibility = ["//visibility:public"],
6 | deps = [
7 | "//common/crypto:types",
8 | "@com_github_google_glog//:glog",
9 | ],
10 | )
11 |
--------------------------------------------------------------------------------
/common/stats/session.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "common/stats/session.h"
9 |
10 | namespace common {
11 | std::ostream& operator<<(std::ostream& os, const ClientSession& session) {
12 | os << session.to_str();
13 | return os;
14 | }
15 | } // namespace common
16 |
--------------------------------------------------------------------------------
/common/stats/session.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef COMMON_STATS_SESSION_H_
9 | #define COMMON_STATS_SESSION_H_
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 |
17 | #include "common/crypto/types.h"
18 |
19 | namespace common {
20 | class ClientSession {
21 | public:
22 | ClientSession() : _tag(crypto::UUID().str()), _str(rep_str()) {}
23 |
24 | ~ClientSession() { LOG(INFO) << *this << "destroyed."; }
25 |
26 | const std::string& tag() const { return _tag; }
27 | const std::string& to_str() const { return _str; }
28 |
29 | private:
30 | friend std::ostream& operator<<(std::ostream& os, const ClientSession& stats);
31 |
32 | std::string rep_str() const {
33 | std::ostringstream ostr;
34 | ostr << "ClientSession(" << _tag << ") ";
35 | return ostr.str();
36 | }
37 |
38 | const std::string _tag;
39 | const std::string _str;
40 | };
41 |
42 | }; // namespace common
43 |
44 | #endif // COMMON_STATS_SESSION_H_
45 |
--------------------------------------------------------------------------------
/common/tests/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "tests",
3 | srcs = ["runner.cc"],
4 | visibility = ["//visibility:public"],
5 | deps = [
6 | "//common/crypto:argon2_provider",
7 | "//common/stats",
8 | "@com_github_google_glog//:glog",
9 | "@com_google_googletest//:gtest",
10 | ],
11 | )
12 |
--------------------------------------------------------------------------------
/common/tests/runner.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 IOTA Foundation
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | int main(int argc, char** argv) {
11 | google::InstallFailureSignalHandler();
12 | google::InitGoogleLogging("commands-tests");
13 | testing::InitGoogleMock(&argc, argv);
14 | gflags::ParseCommandLineFlags(&argc, &argv, true);
15 |
16 | return RUN_ALL_TESTS();
17 | }
18 |
--------------------------------------------------------------------------------
/docker/BUILD:
--------------------------------------------------------------------------------
1 | load("@io_bazel_rules_docker//cc:image.bzl", "cc_image")
2 |
3 | cc_image(
4 | name = "hub",
5 | base = "@ubuntu_base//image",
6 | binary = "//hub:hub",
7 | repository = "iota/hub/docker",
8 | visibility = ["//visibility:public"],
9 | )
10 |
11 | cc_image(
12 | name = "signing_server",
13 | base = "@ubuntu_base//image",
14 | binary = "//signing_server:signing_server",
15 | repository = "iota/hub/docker",
16 | visibility = ["//visibility:public"],
17 | )
18 |
--------------------------------------------------------------------------------
/docs/checksum_validation.md:
--------------------------------------------------------------------------------
1 | # HIP-002: Checksum validation
2 |
3 | ## Problem description
4 | Users need an address's checksum to send funds to it.
5 | Also, when withdrawing, due to some errors, whether it is wrong address given
6 | by user or wrong use of hub on the exchange side, we wouldn't want the transaction
7 | to happen in the first place, to keep everyone happy.
8 |
9 | ## Proposed solution
10 |
11 | 1. UserWithdraw will now validate provided address is valid using checksum.
12 |
13 | 2. GetDepositAddress will return the checksum
14 |
15 | ## Proposed implemntation
16 |
17 | modify existing `message` objects:
18 | ```proto
19 | // add `checksum` to GetDepositAddressReply:
20 | message GetDepositAddressReply {
21 | // Newly created deposit address
22 | string address = 1;
23 | }
24 | // Provided address should contain checksum
25 | message UserWithdrawRequest {
26 | string userId = 1;
27 | // Address the user requests payout to. Should be without checksum.
28 | string payoutAddress = 2;
29 | // Requested withdrawal amount
30 | uint64 amount = 3;
31 | // Tag for withdrawal
32 | string tag = 4;
33 | }
34 | enum ErrorCode {
35 | // Provided `payoutAddress` first 81 trytes
36 | // does not checksum to the last 9
37 | CHECKSUM_INVALID = 9;
38 | }
39 |
40 | ```
41 | declare/instantiate types in `crypto/types.h`:
42 |
43 | struct ChecksumTag {};
44 | using Checksum = TryteArray<9, ChecksumTag>;
45 |
46 | Add methods:
47 |
48 | `Checksum calcChecksum(const string& address)`
49 | `nonstd::optional verifyAndStripChecksum(const string& address)`
50 |
51 |
52 | that will check if first 81 trytes checksums to last 9 of `addressWithChecksum`
53 | and will only return an address if it does checksum
54 | so, in case it does not withdrawal will fail
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/docs/getting_started.md:
--------------------------------------------------------------------------------
1 | # IOTA Hub: Getting started.
2 |
3 | ## Before we start:
4 | - Hub is not an IOTA node, it is a tool for managing transfers from/to addresses in a simple and secure manner
5 | - User should send tokens to a deposit address only once, since deposit addresses are swept and aren't reusable
6 | - In case user sent tokens to a deposit address that has been swept, we offer a mechanism to recover the funds (see docs/hip/001-sign_bundle.md)
7 |
8 | ## Building the hub
9 | - `bazel build -c opt //hub:hub`
10 |
11 | ## Building signing_server (for remote signing_server)
12 | - `bazel build -c opt //signing_server`
13 |
14 | ## Setup the database (this example is using MariaDB)
15 | - Install `MariaDB` (e.g. via Docker)
16 | - Import schemas:
17 | - `mysql -h127.0.0.1 --user root -ppassword < schema/schema.sql`
18 | - `mysql -h127.0.0.1 --user root -ppassword < schema/triggers.mariadb.sql`
19 |
20 | ## Running the hub
21 | - `./bazel-bin/hub/hub --salt yoursaltcharachters --apiAddress your_iri_node_uri --db db_name --dbUser your_user --dbPassword user_password --monitorInterval xxx --attachmentInterval yyy --sweepInterval zzz`
22 | - For detailed explanation about program arguments, see `README.md` or start with `--help`
23 | - For running the hub with remote salt provider (`--signingMode=remote`) run the `signing_provider` first
24 |
25 | ## Running the signing_server
26 | - `./bazel-bin/signing_server/signing_server --salt abcdefghijklmnopqrstuvwxyz --authMode=ssl -sslKey docs/ssl/server.key -sslCert docs/ssl/server.crt -sslCA docs/ssl/ca.crt --listenAddress=localhost:50052`
27 |
28 | ### Run via Docker
29 | You can build and run a docker image for `RPCHub` via `bazel run -c opt //docker:hub`
30 |
31 | ## Calling client commands
32 | - The Hub exposes both gRPC (https://grpc.io/docs/tutorials/) and REST apis
33 | - GRPC: Methods and arguments are available under proto/hub.proto (methods) and proto/messages.proto (request/response types)
34 | - REST: [HTTP_REST_API](http_rest_api.md)
35 |
--------------------------------------------------------------------------------
/docs/hip/001-sign_bundle.md:
--------------------------------------------------------------------------------
1 | # HIP-001: SignBundle
2 |
3 | ## Problem description
4 | Even though exchanges warn against this explicitly, might end up sending tokens to addresses that have already been used as inputs for a sweep.
5 | Due to address security reasons, the Hub does not monitor such addresses any longer.
6 | However, when large amounts of funds are at risk, users might sue exchanges / go to the press / similar. To prevent this from happening, an exchange must have
7 | a means to access the funds (i.e. send back to the user).
8 |
9 | ## Proposed solution
10 | Offer the following gRPC method call that can be enabled via a runtime flag but is *disabled by default*.
11 |
12 | ```proto
13 | // add to ErrorCode:
14 | enum ErrorCode {
15 | // Address is unknown or has not been used as input for a sweep
16 | ADDRESS_NOT_ELIGIBLE;
17 | // The authentication token could not be verified.
18 | INVALID_AUTHENTICATION;
19 | }
20 |
21 | message SignBundleRequest {
22 | // The Hub-owned IOTA address that should be signed. (without checksum)
23 | string address = 1;
24 | // The bundle hash that should be signed.
25 | string bundleHash = 2;
26 | // Authentication token
27 | string authentication = 3;
28 | }
29 |
30 | message SignBundleReply {
31 | // The computed signature
32 | string signature = 1;
33 | }
34 |
35 | service Hub {
36 | // Reveals the seed for a given user address.
37 | rpc SignBundle(SignBundleRequest) returns SignBundleResponse);
38 | }
39 | ```
40 |
41 | Internally, the call will:
42 | 1. Check that address was used in sweep before.
43 | 2. Verify authentication token.
44 | 3. Calculate & return signature
45 |
46 | If an exchange wants to provide a custom audit system integration, they'll need to implement the following interface and register it at startup in their local fork.
47 |
48 | ```c++
49 | // @file hub/auth/provider.h
50 |
51 | namespace hub {
52 | namespace auth {
53 |
54 | enum AuthContext {
55 | SIGN_BUNDLE = 0;
56 | };
57 |
58 | class AuthProvider {
59 | public:
60 | virtual bool validateToken(const std::string& token) = 0;
61 | };
62 |
63 | }
64 | }
65 |
66 | ```
67 |
68 | ## Motivation
69 | ### Authentication payload
70 | Some exchanges might have internal safeguards to prevent rogue internal actors from accessing secrets. Therefore, the Hub needs to be able to integrate with these by exposing an interface they can program against.
71 |
72 | ## Questions
73 | 1. Should the call be able to be called multiple times?
74 | 2. Which authentication method should be provided by default?
75 | 1. Password
76 | 2. HMAC
77 |
78 |
79 |
--------------------------------------------------------------------------------
/docs/hip/template.md:
--------------------------------------------------------------------------------
1 | # HIP-XXX: Name
2 |
3 | ## Problem description
4 |
5 | ## Proposed solution
6 |
7 | ## Motivation
8 |
9 | ## Questions
10 |
11 |
--------------------------------------------------------------------------------
/docs/pull_request_template.md:
--------------------------------------------------------------------------------
1 | <>
2 |
3 | # Test Plan:
4 | <>
5 |
--------------------------------------------------------------------------------
/docs/python/.gitignore:
--------------------------------------------------------------------------------
1 | proto/
--------------------------------------------------------------------------------
/docs/python/README.md:
--------------------------------------------------------------------------------
1 | # Example Python client code
2 | First generate protobuf bindings via `./generate_proto.sh`
3 |
--------------------------------------------------------------------------------
/docs/python/argon2_authentication_token.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import argon2
3 |
4 | #Install argon2_cffi:
5 | #https://argon2-cffi.readthedocs.io/en/stable/installation.html
6 |
7 | def argon2Token(message, salt):
8 |
9 | res = argon2.low_level.hash_secret(message, salt, time_cost=4, memory_cost=17, parallelism=1, hash_len=64, type=argon2.low_level.Type.ID)
10 |
11 | token = res.split("$",4)
12 |
13 | return token[4][:43]
14 |
15 | def main():
16 |
17 | bundleHash = b"9999999999999999999999999999999999999999999999999999999D9999999999999999999999999"
18 | address = b"999ZZS9LS99LPKLDGHTU999999PP9KH9K9JH999999PLR99IO999T999H9999999999HHL999YU999ZBA"
19 | salt = b"El6vxEO4rR009/U/u70SgPa6C7GVZQzXZOUQrkMnXFI"
20 |
21 |
22 | print(argon2Token(bundleHash + address, salt) == b"RWw2dnhFTzRyUjAwOS9VL3U3MFNnUGE2QzdHVlpRelh")
23 |
24 | if __name__ == '__main__':
25 | main()
26 |
27 |
--------------------------------------------------------------------------------
/docs/python/generate_proto.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | python -m grpc_tools.protoc --python_out=. --proto_path=../../ --grpc_python_out=. ../../proto/messages.proto ../../proto/hub.proto
4 |
--------------------------------------------------------------------------------
/docs/python/ssl_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import grpc
3 |
4 | import proto.hub_pb2_grpc as hub
5 | import proto.messages_pb2 as msg
6 |
7 |
8 | def main():
9 | host = 'localhost'
10 | port = 50051
11 |
12 | with open('../ssl/client.crt', 'rb') as f:
13 | client_cert = f.read()
14 | with open('../ssl/client.key', 'rb') as f:
15 | client_key = f.read()
16 | with open('../ssl/ca.crt', 'rb') as f:
17 | chain = f.read()
18 |
19 | credentials = grpc.ssl_channel_credentials(root_certificates=chain,
20 | private_key=client_key,
21 | certificate_chain=client_cert)
22 | channel = grpc.secure_channel('{}:{}'.format(host, port), credentials)
23 |
24 | stub = hub.HubStub(channel)
25 |
26 | req = msg.CreateUserRequest(userId='a')
27 | stub.CreateUser(req)
28 |
29 |
30 | if __name__ == '__main__':
31 | main()
32 |
--------------------------------------------------------------------------------
/docs/secure_server.md:
--------------------------------------------------------------------------------
1 | # Securing Hub/Signing_Server (The example below is for hub but could easily adjusted to signing_server as well)
2 |
3 | ## Connect to Hub via SSL
4 | 1. Create certificates, see example scripts in `docs/ssl` for further guidance. *The server CN needs to match the actual server's hostname!*
5 | 2. Start Hub in correct authMode: `--authMode ssl --sslKey docs/ssl/server.key --sslCert docs/ssl/server.crt --sslCA docs/ssl/ca.crt`
6 |
7 | **Please note that if you're running the hub via `bazel run`, these paths need to be absolute!**
8 | 3. Configure your Hub client to use SSL, see the provided Python example for further guidance. If you're using grpcc for testing, this might be helpful:
9 | `grpcc -a 'localhost:50051' -p proto/hub.proto --root_cert path-to/ca.crt --private_key path-to/client.key --cert_chain path-to/client.crt`
10 |
--------------------------------------------------------------------------------
/docs/ssl/.gitignore:
--------------------------------------------------------------------------------
1 | *.crt
2 | *.key
3 | *.csr
--------------------------------------------------------------------------------
/docs/ssl/grpc/01_generate_ca.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | openssl genrsa -passout pass:1234 -des3 -out ca.key 4096
4 | openssl req -new -x509 -passin pass:1234 -days 365 -key ca.key -out ca.crt -subj "/C=DE/ST=Berlin/L=Berlin/O=HUB User/OU=HUB User/CN=HUB Root CA"
5 |
6 |
--------------------------------------------------------------------------------
/docs/ssl/grpc/02_generate_server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Generate valid Server Key/Cert
4 | openssl genrsa -passout pass:1234 -des3 -out server.key 4096
5 | openssl req -passin pass:1234 -new -key server.key -out server.csr -subj "/C=DE/ST=Berlin/L=Berlin/O=HUB/OU=Server/CN=localhost"
6 | openssl x509 -req -passin pass:1234 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
7 |
8 | # Remove passphrase from the Server Key
9 | openssl rsa -passin pass:1234 -in server.key -out server.key
10 |
11 | cat ca.crt server.crt > server_chain.crt
12 |
--------------------------------------------------------------------------------
/docs/ssl/grpc/03_generate_client.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Generate valid Client Key/Cert
4 | openssl genrsa -passout pass:1234 -des3 -out client.key 4096
5 | openssl req -passin pass:1234 -new -key client.key -out client.csr -subj "/C=DE/ST=Berlin/L=Berlin/O=HUB/OU=Client/CN=localhost"
6 | openssl x509 -passin pass:1234 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
7 |
8 | # Remove passphrase from Client Key
9 | openssl rsa -passin pass:1234 -in client.key -out client.key
10 |
--------------------------------------------------------------------------------
/docs/ssl/rest/generate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # in order to be able to test commands with https support using curl and a self
4 | # signed certificate, use the `-k` flag
5 |
6 | openssl dhparam -out dh.pem 2048
7 | openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days - nodes 365 -sub -subj "/CN=localhost"
--------------------------------------------------------------------------------
/hooks/pre-commit/01-buildifier-check:
--------------------------------------------------------------------------------
1 | ../scripts/buildifier_check
--------------------------------------------------------------------------------
/hooks/pre-commit/02-cpplint:
--------------------------------------------------------------------------------
1 | ../scripts/cpplint
--------------------------------------------------------------------------------
/hooks/pre-commit/03-format-check:
--------------------------------------------------------------------------------
1 | ../scripts/format_check
--------------------------------------------------------------------------------
/hooks/scripts/buildifier_check:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | buildifier -showlog -mode=check $(git ls-files $(git rev-parse --show-toplevel) | grep -E "WORKSPACE|BUILD(\.(bazel|bzl))?\$")
4 |
--------------------------------------------------------------------------------
/hooks/scripts/cpplint:
--------------------------------------------------------------------------------
1 | ../../tools/cpplint
--------------------------------------------------------------------------------
/hooks/scripts/format_check:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | root=$(git rev-parse --show-toplevel)
4 | status=0
5 | for file in $(git diff --staged --name-only | grep -E "\.(c|cc|cpp|h|hh|hpp)\$")
6 | do
7 | filepath="$root/$file"
8 | output=$(diff <(cat $filepath) <(clang-format -style=file -fallback-style=none $filepath))
9 | if [ $? -ne 0 ]
10 | then
11 | echo -e "\nFile \""$file"\" is not compliant with the coding style"
12 | echo "$output"
13 | status=1
14 | fi
15 | done
16 | exit $status
17 |
--------------------------------------------------------------------------------
/hub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iotaledger-archive/hub/9df503d4def3021b082ba7aaaace7a9265e2ba18/hub.png
--------------------------------------------------------------------------------
/hub/BUILD:
--------------------------------------------------------------------------------
1 | cc_binary(
2 | name = "hub",
3 | srcs = ["main.cc"],
4 | visibility = ["//visibility:public"],
5 | deps = [
6 | "//hub/db",
7 | "//hub/server",
8 | "@com_github_gflags_gflags//:gflags",
9 | "@com_github_google_glog//:glog",
10 | ],
11 | )
12 |
--------------------------------------------------------------------------------
/hub/auth/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "auth",
3 | srcs = ["manager.cc"],
4 | hdrs = [
5 | "manager.h",
6 | "provider.h",
7 | ],
8 | visibility = ["//visibility:public"],
9 | deps = [
10 | ],
11 | )
12 |
13 | cc_library(
14 | name = "dummy_provider",
15 | hdrs = ["dummy_provider.h"],
16 | visibility = ["//visibility:public"],
17 | deps = [
18 | ":auth",
19 | "@com_github_google_glog//:glog",
20 | ],
21 | )
22 |
23 | cc_library(
24 | name = "hmac_provider",
25 | srcs = glob([
26 | "hmac_provider.*",
27 | "sign_bundle_context.*",
28 | ]),
29 | hdrs = ["hmac_provider.h"],
30 | visibility = ["//visibility:public"],
31 | deps = [
32 | ":auth",
33 | "//common",
34 | "//common/crypto",
35 | "@argon2",
36 | "@com_github_google_glog//:glog",
37 | ],
38 | )
39 |
40 | cc_test(
41 | name = "test_hmac_provider",
42 | srcs = glob([
43 | "tests/**/*.cc",
44 | ]),
45 | deps = [
46 | ":hmac_provider",
47 | "//hub/tests",
48 | "@com_google_googletest//:gtest",
49 | ],
50 | )
51 |
--------------------------------------------------------------------------------
/hub/auth/dummy_provider.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_AUTH_DUMMY_PROVIDER_H_
9 | #define HUB_AUTH_DUMMY_PROVIDER_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "hub/auth/provider.h"
15 |
16 | namespace hub {
17 | namespace auth {
18 |
19 | /// DummyProvider class.
20 | /// The dummy provider accepts any token.
21 | class DummyProvider : public AuthProvider {
22 | public:
23 | /// Constructor
24 | DummyProvider() {}
25 |
26 | bool validateToken(const AuthContext& context,
27 | const std::string& token) noexcept override {
28 | return true;
29 | }
30 | };
31 |
32 | } // namespace auth
33 | } // namespace hub
34 | #endif // HUB_AUTH_DUMMY_PROVIDER_H_
35 |
--------------------------------------------------------------------------------
/hub/auth/hmac_provider.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 | #include
8 | #include
9 | #include
10 |
11 | #include "common/flags.h"
12 | #include "hub/auth/hmac_provider.h"
13 |
14 | namespace hub {
15 | namespace auth {
16 |
17 | HMACProvider::HMACProvider(const std::string& key) : _key(key) {
18 | if (_key.size() > KEY_SIZE) {
19 | _key.resize(KEY_SIZE);
20 | } else if (_key.size() < KEY_SIZE) {
21 | throw std::runtime_error(
22 | __FUNCTION__ +
23 | std::string("Provided HMAC key has wrong size (expected size: ") +
24 | std::to_string(KEY_SIZE) +
25 | " observed size: " + std::to_string(_key.size()) + ")");
26 | }
27 | }
28 | HMACProvider::~HMACProvider() {
29 | _key.replace(0, _key.size(), _key.size(), '0');
30 | }
31 |
32 | bool HMACProvider::validateToken(const AuthContext& context,
33 | const std::string& token) noexcept {
34 | char encoded[HASH_SIZE * 6];
35 |
36 | if (argon2id_hash_encoded(
37 | common::flags::FLAGS_argon2TCost, common::flags::FLAGS_argon2MCost,
38 | common::flags::FLAGS_argon2Parallelism, context.message().c_str(),
39 | context.message().size(), _key.c_str(), _key.size(), HASH_SIZE * 2,
40 | encoded, HASH_SIZE * 6) != ARGON2_OK) {
41 | LOG(ERROR) << "Failed in " << __FUNCTION__;
42 | return false;
43 | }
44 |
45 | return token.compare(stripEncodedPrefix(encoded)) == 0;
46 | }
47 |
48 | std::string_view HMACProvider::stripEncodedPrefix(const std::string_view& e) {
49 | // strip prefix from encoded
50 | // Encoded example with prefix:
51 | // $argon2id$v=19$m=131072,t=4,p=1$c29tZXNhbHQ$xLJXnoh1+mb/bqTS72pL+pBbH1+sih7KFiZV1k4fdmM
52 | // After stripping: c29tZXNhbHQ$xLJXnoh1+mb/bqTS72pL+pBbH1+sih7KFiZV1k4fdmM
53 |
54 | static constexpr uint8_t NUM_DOLLAR_SIGNS_IN_PREFIX = 4;
55 |
56 | auto prefixSize = 0;
57 | uint8_t dollarSignCounter = 0;
58 | std::string_view curr(e);
59 | while (dollarSignCounter < NUM_DOLLAR_SIGNS_IN_PREFIX) {
60 | curr = e.substr(prefixSize, KEY_SIZE);
61 | auto pos = curr.find_first_of('$');
62 | if (pos == std::string::npos) {
63 | LOG(ERROR) << "Failed in " << __FUNCTION__;
64 | break;
65 | }
66 | curr = curr.substr(0, pos + 1);
67 | prefixSize += curr.size();
68 | dollarSignCounter++;
69 | }
70 |
71 | return e.substr(prefixSize, KEY_SIZE);
72 | }
73 |
74 | } // namespace auth
75 | } // namespace hub
76 |
--------------------------------------------------------------------------------
/hub/auth/hmac_provider.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_AUTH_HMAC_PROVIDER_H_
9 | #define HUB_AUTH_HMAC_PROVIDER_H_
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "hub/auth/provider.h"
16 | #include "hub/auth/sign_bundle_context.h"
17 |
18 | namespace hub {
19 | namespace auth {
20 |
21 | /// DummyProvider class.
22 | /// The dummy provider accepts any token.
23 | class HMACProvider : public AuthProvider {
24 | public:
25 | /// 64bit based characters (43 *64bits = 258bits)
26 | constexpr static uint16_t KEY_SIZE = 43;
27 | /// 64bit based characters (43 *64bits = 258bits)
28 | constexpr static uint16_t HASH_SIZE = 43;
29 | /// Constructor
30 | explicit HMACProvider(const std::string& key);
31 | ~HMACProvider();
32 |
33 | bool validateToken(const AuthContext& context,
34 | const std::string& token) noexcept override;
35 |
36 | private:
37 | std::string_view stripEncodedPrefix(const std::string_view& encoded);
38 |
39 | std::string _key;
40 | };
41 |
42 | } // namespace auth
43 | } // namespace hub
44 | #endif // HUB_AUTH_HMAC_PROVIDER_H_
45 |
--------------------------------------------------------------------------------
/hub/auth/manager.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "hub/auth/manager.h"
9 |
10 | namespace hub {
11 | namespace auth {
12 |
13 | AuthManager& AuthManager::get() {
14 | static AuthManager instance;
15 |
16 | return instance;
17 | }
18 |
19 | } // namespace auth
20 | } // namespace hub
21 |
--------------------------------------------------------------------------------
/hub/auth/manager.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_AUTH_MANAGER_H_
9 | #define HUB_AUTH_MANAGER_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "hub/auth/provider.h"
15 |
16 | namespace hub {
17 | namespace auth {
18 |
19 | /// AuthManager holds the single instance of a AuthProvider
20 | class AuthManager {
21 | private:
22 | /// Constructor
23 | AuthManager() {}
24 | /// deleted
25 | AuthManager(AuthManager const&) = delete;
26 | /// deleted
27 | AuthManager(AuthManager&&) = delete;
28 | /// deleted
29 | AuthManager& operator=(AuthManager const&) = delete;
30 | /// deleted
31 | AuthManager& operator=(AuthManager&&) = delete;
32 |
33 | public:
34 | /// Get the singleton instance
35 | /// @return AuthManager - the singleton instance of AuthManager
36 | static AuthManager& get();
37 |
38 | /// Set the authentication provider
39 | /// @param[in] provider - an instance of AuthProvider
40 | void setProvider(std::unique_ptr provider) {
41 | _provider = std::move(provider);
42 | }
43 |
44 | /// Get the authentication provider
45 | /// @return AuthProvider - an instance of AuthProvider
46 | AuthProvider& provider() { return *_provider; }
47 |
48 | private:
49 | /// The authentication provider
50 | std::unique_ptr _provider;
51 | };
52 |
53 | } // namespace auth
54 | } // namespace hub
55 | #endif // HUB_AUTH_MANAGER_H_
56 |
--------------------------------------------------------------------------------
/hub/auth/provider.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_AUTH_PROVIDER_H_
9 | #define HUB_AUTH_PROVIDER_H_
10 |
11 | #include
12 |
13 | namespace hub {
14 | namespace auth {
15 |
16 | class AuthContext {
17 | public:
18 | virtual const std::string& message() const noexcept = 0;
19 | };
20 |
21 | /// AuthProvider abstract class.
22 | /// Provides facilities to authenticate certain requests.
23 | class AuthProvider {
24 | public:
25 | /// Destructor
26 | virtual ~AuthProvider() {}
27 |
28 | /// Attempts to validate a token.
29 | /// param[in] the token context
30 | /// param[in] token the token
31 | /// returns true if token was valid
32 | virtual bool validateToken(const AuthContext& context,
33 | const std::string& token) noexcept = 0;
34 | };
35 |
36 | } // namespace auth
37 | } // namespace hub
38 | #endif // HUB_AUTH_PROVIDER_H_
39 |
--------------------------------------------------------------------------------
/hub/auth/sign_bundle_context.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "hub/auth/sign_bundle_context.h"
9 |
10 | namespace hub {
11 | namespace auth {
12 |
13 | SignBundleContext::SignBundleContext(const common::crypto::Hash& bundleHash,
14 | const common::crypto::Address& address) {
15 | _message = bundleHash.str() + address.str();
16 | }
17 | const std::string& SignBundleContext::message() const noexcept {
18 | return _message;
19 | }
20 | } // namespace auth
21 | } // namespace hub
22 |
--------------------------------------------------------------------------------
/hub/auth/sign_bundle_context.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_AUTH_SIGN_BUNDLE_CONTEXT_H_
9 | #define HUB_AUTH_SIGN_BUNDLE_CONTEXT_H_
10 |
11 | #include
12 |
13 | #include "common/crypto/types.h"
14 | #include "hub/auth/provider.h"
15 |
16 | namespace hub {
17 | namespace auth {
18 |
19 | class SignBundleContext : public AuthContext {
20 | public:
21 | SignBundleContext(const common::crypto::Hash& bundleHash,
22 | const common::crypto::Address& address);
23 | const std::string& message() const noexcept override;
24 |
25 | private:
26 | std::string _message;
27 | };
28 |
29 | } // namespace auth
30 | } // namespace hub
31 | #endif // HUB_AUTH_SIGN_BUNDLE_CONTEXT_H_
32 |
--------------------------------------------------------------------------------
/hub/auth/tests/hmac_provider.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 IOTA Foundation
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "common/crypto/types.h"
10 | #include "hub/auth/hmac_provider.h"
11 | #include "hub/db/db.h"
12 | #include "hub/tests/runner.h"
13 |
14 | using namespace hub;
15 | using namespace hub::auth;
16 |
17 | namespace {
18 |
19 | class HMACProviderTest : public hub::Test {};
20 |
21 | TEST_F(HMACProviderTest, EnforceKeyLength) {
22 | EXPECT_THROW(HMACProvider{std::string("abcdefghijklmnop")},
23 | std::runtime_error);
24 | }
25 |
26 | TEST_F(HMACProviderTest, ShouldValidateOnCorrectToken) {
27 | std::string key = "El6vxEO4rR009/U/u70SgPa6C7GVZQzXZOUQrkMnXFI";
28 | HMACProvider provider(key);
29 |
30 | common::crypto::Hash bundleHash(
31 | "9999999999999999999999999999999999999999999999999999999D9999999999999999"
32 | "999999999");
33 | common::crypto::Address address(
34 | "999ZZS9LS99LPKLDGHTU999999PP9KH9K9JH999999PLR99IO999T999H9999999999HHL99"
35 | "9YU999ZBA");
36 | auth::SignBundleContext context(bundleHash, address);
37 |
38 | constexpr auto token = "RWw2dnhFTzRyUjAwOS9VL3U3MFNnUGE2QzdHVlpRelh";
39 |
40 | ASSERT_TRUE(provider.validateToken(context, token));
41 | }
42 |
43 | TEST_F(HMACProviderTest, ShouldRejectOnIncorrectToken) {
44 | std::string key = "El6vxEO4rR009/U/u70SgPa6C7GVZQzXZOUQrkMnXFI";
45 | HMACProvider provider(key);
46 |
47 | common::crypto::Hash bundleHash(
48 | "9999999999999999999999999999999999999999999999999999999D9999999999999999"
49 | "999999999");
50 | common::crypto::Address address(
51 | "999ZZS9LS99LPKLDGHTU999999PP9KH9K9JH999999PLR99IO999T999H9999999999HHL99"
52 | "9YU999ZBA");
53 | auth::SignBundleContext context(bundleHash, address);
54 |
55 | // changed last character
56 | constexpr auto token = "RWw2dnhFTzRyUjAwOS9VL3U3MFNnUGE2QzdHVlpRelz";
57 |
58 | ASSERT_FALSE(provider.validateToken(context, token));
59 | }
60 |
61 | }; // namespace
62 |
--------------------------------------------------------------------------------
/hub/bundle/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "bundle_utils",
3 | srcs = ["bundle_utils.cc"],
4 | hdrs = ["bundle_utils.h"],
5 | visibility = ["//visibility:public"],
6 | deps = [
7 | "//common/crypto",
8 | "//hub/db",
9 | "@com_github_gflags_gflags//:gflags",
10 | "@com_github_google_glog//:glog",
11 | "@org_iota_common//common/model:bundle",
12 | "@org_iota_common//common/trinary:flex_trit",
13 | "@org_iota_common//utils:bundle_miner",
14 | ],
15 | )
16 |
--------------------------------------------------------------------------------
/hub/bundle/bundle_utils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_BUNDLE_CREATE_BUNDLE_H_
9 | #define HUB_BUNDLE_CREATE_BUNDLE_H_
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include "common/crypto/types.h"
20 | #include "hub/db/types.h"
21 |
22 | DECLARE_uint32(numBundlesToMine);
23 |
24 | namespace hub {
25 | namespace bundle_utils {
26 |
27 | /// Compute and serialize a bundle made up of all the deposits and withdrawals
28 | /// identified during the sweep.
29 | /// @param[in] deposits - a list of deposit transactions
30 | /// @param[in] hubInputs - a list of internal transfers
31 | /// @param[in] withdrawals - a list of withdrawal transactions
32 | /// @param[in] hubOutput - a list of db::TransferOutput structures
33 | /// @param[in] alreadySignedBundleHashes - if not empty, this means we should
34 | /// force signature and mine for a bundle an already spent address
35 | /// @return a std::tuple containing
36 | /// - the bundle hash
37 | /// - the serialized bundle
38 | std::tuple createBundle(
39 | const std::vector& deposits,
40 | const std::vector& hubInputs,
41 | const std::vector& withdrawals,
42 | const nonstd::optional hubOutputOptional,
43 | const std::vector& alreadySignedBundleHashes = {});
44 |
45 | /// Persist the bundle data to database
46 | /// identified during the sweep.
47 | /// @param[in] bundle - the bundle hash and its serialized value
48 | /// @param[in] deposits - a list of deposit transactions
49 | /// @param[in] hubInputs - a list of internal transfers
50 | /// @param[in] withdrawals - a list of withdrawal transactions
51 | /// @param[in] hubOutput - the hub address into which the remainder is
52 | /// deposited
53 | void persistToDatabase(std::tuple bundle,
54 | const std::vector& deposits,
55 | const std::vector& hubInputs,
56 | const std::vector& withdrawals,
57 | const nonstd::optional hubOutput);
58 |
59 | /// Creates a new hub address to which funds that remain after a transfer
60 | /// can be moved.
61 | /// @param[in] remainder
62 | /// @return a db::TransferOutput structure containing
63 | /// - the new hub address
64 | /// - the id of the new hub address
65 | /// - the remainder
66 | hub::db::TransferOutput getHubOutput(uint64_t remainder);
67 |
68 | } // namespace bundle_utils
69 | } // namespace hub
70 |
71 | #endif // HUB_BUNDLE_CREATE_BUNDLE_H_
72 |
--------------------------------------------------------------------------------
/hub/commands/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "commands",
3 | srcs = glob(
4 | ["**/*.cc"],
5 | exclude = ["tests/**/*"],
6 | ),
7 | hdrs = glob(
8 | ["**/*.h"],
9 | exclude = ["tests/**/*"],
10 | ),
11 | visibility = ["//visibility:public"],
12 | deps = [
13 | "//common",
14 | "//common/stats",
15 | "//hub/auth:hmac_provider",
16 | "//hub/bundle:bundle_utils",
17 | "//hub/db",
18 | "@boost//:range",
19 | "@com_github_google_glog//:glog",
20 | "@TangleScope//cppclient:beast",
21 | ],
22 | )
23 |
24 | cc_test(
25 | name = "tests",
26 | timeout = "long",
27 | srcs = glob([
28 | "tests/**/*.cc",
29 | "tests/**/*.h",
30 | ]),
31 | deps = [
32 | ":commands",
33 | "//hub/tests",
34 | "@boost//:range",
35 | "@com_google_googletest//:gtest",
36 | ],
37 | )
38 |
--------------------------------------------------------------------------------
/hub/commands/balance_subscription.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_COMMANDS_BALANCE_SUBSCRIPTION_H_
9 | #define HUB_COMMANDS_BALANCE_SUBSCRIPTION_H_
10 |
11 | #include
12 | #include
13 |
14 | #include "common/commands/command.h"
15 | #include "events.h"
16 | #include "hub/db/helper.h"
17 |
18 | namespace hub {
19 |
20 | namespace cmd {
21 |
22 | typedef struct BalanceSubscriptionRequest {
23 | uint64_t newerThan;
24 | } BalanceSubscriptionRequest;
25 |
26 | /// @param[in] BalanceSubscriptionRequest
27 | /// @param[out] std::vector events
28 | /// Collects records about balance actions to and from user addresses
29 | /// and hub's addresses as well (Depsoits/Withdrawals/Hub address actions)
30 | class BalanceSubscription : public common::Command> {
32 | public:
33 | using Command>::Command;
34 |
35 | static const std::string name() { return "BalanceSubscription"; }
36 |
37 | static std::shared_ptr create() {
38 | return std::shared_ptr(
39 | new BalanceSubscription(std::make_shared()));
40 | }
41 |
42 | virtual std::vector
43 | getAllUsersAccountBalancesSinceTimePoint(
44 | std::chrono::system_clock::time_point lastCheck);
45 |
46 | virtual std::vector
47 | getAllUserAddressesBalancesSinceTimePoint(
48 | std::chrono::system_clock::time_point lastCheck);
49 |
50 | virtual std::vector
51 | getAllHubAddressesBalancesSinceTimePoint(
52 | std::chrono::system_clock::time_point lastCheck);
53 |
54 | common::cmd::Error doProcess(
55 | const BalanceSubscriptionRequest* request,
56 | std::vector* events) noexcept override;
57 |
58 | boost::property_tree::ptree doProcess(
59 | const boost::property_tree::ptree& request) noexcept override;
60 | };
61 | } // namespace cmd
62 | } // namespace hub
63 | #endif // HUB_COMMANDS_BALANCE_SUBSCRIPTION_H_
64 |
--------------------------------------------------------------------------------
/hub/commands/converter.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_COMMANDS_PROTO_SQL_CONVERTER_H_
9 | #define HUB_COMMANDS_PROTO_SQL_CONVERTER_H_
10 |
11 | #include
12 |
13 | #include "hub/db/types.h"
14 | #include "proto/hub.pb.h"
15 |
16 | #include "events.h"
17 |
18 | namespace hub {
19 |
20 | namespace cmd {
21 |
22 | /// Account balance event
23 | hub::cmd::UserAccountBalanceEventReason userAccountBalanceEventReasonFromSql(
24 | hub::db::UserAccountBalanceReason reason);
25 |
26 | hub::rpc::UserAccountBalanceEventType userAccountBalanceEventReasonToProto(
27 | hub::cmd::UserAccountBalanceEventReason reason);
28 |
29 | std::string userAccountBalanceEventReasonToString(
30 | hub::cmd::UserAccountBalanceEventReason reason);
31 |
32 | /// User address balance event
33 | hub::cmd::UserAddressBalanceEventReason userAddressBalanceEventReasonFromSql(
34 | hub::db::UserAddressBalanceReason reason);
35 |
36 | hub::rpc::UserAddressBalanceReason userAddressBalanceEventReasonToProto(
37 | hub::cmd::UserAddressBalanceEventReason reason);
38 |
39 | std::string userAddressBalanceEventReasonToString(
40 | hub::cmd::UserAddressBalanceEventReason reason);
41 |
42 | /// Hub address balance event
43 | hub::cmd::HubAddressBalanceEventReason hubAddressBalanceReasonFromSql(
44 | hub::db::HubAddressBalanceReason reason);
45 |
46 | hub::rpc::HubAddressBalanceReason hubAddressBalanceReasonToProto(
47 | hub::cmd::HubAddressBalanceEventReason reason);
48 |
49 | std::string hubAddressBalanceReasonToString(
50 | hub::cmd::HubAddressBalanceEventReason reason);
51 |
52 | } // namespace cmd
53 | } // namespace hub
54 | #endif // HUB_COMMANDS_PROTO_SQL_CONVERTER_H_
55 |
--------------------------------------------------------------------------------
/hub/commands/create_user.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #include "hub/commands/factory.h"
9 | #include "hub/commands/helper.h"
10 | #include "hub/db/helper.h"
11 |
12 | #include "hub/commands/create_user.h"
13 |
14 | namespace hub {
15 | namespace cmd {
16 |
17 | static CommandFactoryRegistrator registrator;
18 |
19 | boost::property_tree::ptree CreateUser::doProcess(
20 | const boost::property_tree::ptree& request) noexcept {
21 | boost::property_tree::ptree tree;
22 | CreateUserRequest req;
23 | CreateUserReply rep;
24 | auto maybeUserId = request.get_optional("userId");
25 | if (!maybeUserId) {
26 | tree.add("error",
27 | common::cmd::getErrorString(common::cmd::MISSING_ARGUMENT));
28 | return tree;
29 | }
30 | req.userId = maybeUserId.value();
31 | auto status = doProcess(&req, &rep);
32 |
33 | if (status != common::cmd::OK) {
34 | tree.add("error", common::cmd::getErrorString(status));
35 | }
36 |
37 | return tree;
38 | }
39 |
40 | common::cmd::Error CreateUser::doProcess(const CreateUserRequest* request,
41 | CreateUserReply* response) noexcept {
42 | auto& connection = db::DBManager::get().connection();
43 |
44 | auto transaction = connection.transaction();
45 |
46 | try {
47 | connection.createUser(request->userId);
48 | transaction->commit();
49 | } catch (const sqlpp::exception& ex) {
50 | LOG(ERROR) << session() << " Commit failed: " << ex.what();
51 |
52 | try {
53 | transaction->rollback();
54 | } catch (const sqlpp::exception& ex) {
55 | LOG(ERROR) << session() << " Rollback failed: " << ex.what();
56 | }
57 |
58 | return common::cmd::USER_EXISTS;
59 | }
60 |
61 | LOG(INFO) << session() << " Created user: " << request->userId;
62 |
63 | return common::cmd::OK;
64 | }
65 |
66 | } // namespace cmd
67 |
68 | } // namespace hub
69 |
--------------------------------------------------------------------------------
/hub/commands/create_user.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_COMMANDS_CREATE_USER_H_
9 | #define HUB_COMMANDS_CREATE_USER_H_
10 |
11 | #include "common/commands/command.h"
12 |
13 | #include
14 |
15 | namespace hub {
16 | namespace cmd {
17 |
18 | typedef struct CreateUserRequest {
19 | std::string userId;
20 |
21 | } CreateUserRequest;
22 |
23 | typedef struct CreateUserReply {
24 | std::string userId;
25 |
26 | } CreateUserReply;
27 |
28 | /// Creates a new user with a specific id.
29 | /// @param[in] CreateUserRequest
30 | /// @param[in] CreateUserReply
31 | class CreateUser : public common::Command {
32 | public:
33 | using Command::Command;
34 |
35 | static std::shared_ptr create() {
36 | return std::shared_ptr(
37 | new CreateUser(std::make_shared()));
38 | }
39 |
40 | static const std::string name() { return "CreateUser"; }
41 |
42 | common::cmd::Error doProcess(const CreateUserRequest* request,
43 | CreateUserReply* response) noexcept override;
44 |
45 | boost::property_tree::ptree doProcess(
46 | const boost::property_tree::ptree& request) noexcept override;
47 | };
48 | } // namespace cmd
49 | } // namespace hub
50 |
51 | #endif // HUB_COMMANDS_CREATE_USER_H_
52 |
--------------------------------------------------------------------------------
/hub/commands/factory.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 IOTA Stiftung
3 | * https://github.com/iotaledger/hub
4 | *
5 | * Refer to the LICENSE file for licensing information
6 | */
7 |
8 | #ifndef HUB_COMMANDS_FACTORY_H_
9 | #define HUB_COMMANDS_FACTORY_H_
10 |
11 | #include