├── .dockerignore ├── .drone.yml ├── .gitignore ├── .rspec ├── .ruby-version ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── VERSION ├── bin ├── install.sh ├── install_webhook ├── quick-test.sh ├── set-env.sh └── start.sh ├── compose └── .gitkeep ├── config.ru ├── config ├── app.yml ├── applogic │ └── .gitkeep ├── arke │ └── .gitkeep ├── barong │ ├── authz_rules.yml │ └── barong.yml ├── frontend │ └── .gitkeep ├── gateway │ └── .gitkeep ├── influxdb │ ├── arke.sql │ ├── build_candles.sql │ └── peatio.sql ├── mailer │ └── templates │ │ ├── deposit_accepted.en.html.erb │ │ ├── email_confirmation.en.html.erb │ │ ├── email_confirmation.ru.html.erb │ │ ├── label.en.html.erb │ │ ├── new_beneficiary.en.html.erb │ │ ├── password_reset.en.html.erb │ │ ├── password_reset.ru.html.erb │ │ ├── session_create.en.html.erb │ │ └── withdraw_succeed.en.html.erb ├── mysql │ └── innodb.cnf ├── peatio │ ├── plugins.yml │ └── seed │ │ └── .gitkeep ├── secrets │ └── .gitkeep └── utils.yml ├── data ├── mysql │ ├── barong_production.sql │ └── peatio_production.sql └── parity │ └── .gitkeep ├── docs ├── aws-install.md ├── images │ └── OpenDAX-authorization.png ├── troubleshoot-barong-authz.md └── ubuntu-install.md ├── lib ├── opendax │ ├── payload.rb │ ├── renderer.rb │ ├── vault.rb │ └── webhook.rb └── tasks │ ├── db.rake │ ├── docker.rake │ ├── payload.rake │ ├── render.rake │ ├── service.rake │ ├── terraform.rake │ ├── toolbox.rake │ ├── vault.rake │ ├── vendor.rake │ ├── versions.rake │ └── wallets.rake ├── spec ├── opendax │ ├── payload_spec.rb │ ├── renderer_spec.rb │ └── server_spec.rb └── spec_helper.rb ├── templates ├── .env.erb ├── compose │ ├── app.yaml.erb │ ├── arke.yaml.erb │ ├── backend.yaml.erb │ ├── cryptonodes.yaml.erb │ ├── daemons.yaml.erb │ ├── frontend.yaml.erb │ ├── gateway.yaml.erb │ ├── monitoring.yaml.erb │ ├── proxy.yaml.erb │ ├── superset.yaml.erb │ └── vendor.yaml.erb ├── config │ ├── applogic.env.erb │ ├── applogic │ │ ├── management_api_v2.yml.erb │ │ └── schedule.yml.erb │ ├── arke.env.erb │ ├── arke │ │ └── strategies.yml.erb │ ├── barong.env.erb │ ├── barong │ │ ├── abilities.yml.erb │ │ ├── management_api.yml.erb │ │ └── seeds.yml.erb │ ├── bitcoin.conf.erb │ ├── finex │ │ ├── config.yaml.erb │ │ └── rsa-key.pub.erb │ ├── frontend │ │ ├── env.js.erb │ │ └── tower.js.erb │ ├── gateway │ │ └── envoy.yaml.erb │ ├── litecoin.conf.erb │ ├── mailer.yml.erb │ ├── mysql │ │ └── innodb.cnf.erb │ ├── peatio.env.erb │ ├── peatio │ │ ├── abilities.yml.erb │ │ ├── management_api_v1.yml.erb │ │ └── seed │ │ │ ├── accounts.yml.erb │ │ │ ├── blockchains.yml.erb │ │ │ ├── currencies.yml.erb │ │ │ ├── engines.yml.erb │ │ │ ├── markets.yml.erb │ │ │ ├── trading_fees.yml.erb │ │ │ └── wallets.yml.erb │ ├── rango.env.erb │ ├── toolbox.yaml.erb │ └── vault │ │ ├── barong.hcl.erb │ │ ├── finex_engine.hcl.erb │ │ ├── peatio_crypto.hcl.erb │ │ ├── peatio_matching.hcl.erb │ │ ├── peatio_rails.hcl.erb │ │ └── peatio_upstream.hcl.erb ├── terraform │ └── terraform.tfvars.erb └── webhook.service ├── terraform ├── main.tf └── variables.tf └── vendor └── .gitkeep /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | .git 4 | .gitignore 5 | LICENSE 6 | README 7 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | name: default 3 | 4 | steps: 5 | - name: Run rspec 6 | image: ruby:2.6.5 7 | commands: 8 | - gem install bundler 9 | - bundle 10 | - bundle exec rspec 11 | when: 12 | event: 13 | - pull_request 14 | - name: Bump and tag 15 | image: quay.io/openware/sdk-tools:0.0.3 16 | environment: 17 | BRANCH_NAME: ${DRONE_BRANCH} 18 | REPO_NAME: ${DRONE_REPO} 19 | BOT_USERNAME: kite-bot 20 | BOT_NAME: Kite Bot 21 | BOT_EMAIL: kite-bot@heliostech.fr 22 | GITHUB_API_KEY: 23 | from_secret: kite_bot_key 24 | commands: 25 | - BUNDLE_GEMFILE=/sdk/Gemfile bundle exec rake --rakefile=/sdk/Rakefile release:push 26 | when: 27 | event: [push] 28 | branch: [master] 29 | 30 | image_pull_secrets: 31 | - dockerconfigjson 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | config/acme.json 2 | config/frontend/*.js 3 | config/gateway/mapping.yaml 4 | config/peatio/management_api_v1.yml 5 | config/barong/management_api.yml 6 | config/finex/* 7 | config/toolbox.yaml 8 | config/traefik.toml 9 | config/*.env 10 | config/secrets/* 11 | !config/secrets/.gitkeep 12 | config/peatio/seed/* 13 | !config/peatio/seed/.gitkeep 14 | config/applogic/* 15 | !config/applogic/.gitkeep 16 | vendor/ 17 | !vendor/.gitkeep 18 | .terraform/ 19 | *.tfvars 20 | terraform.tfstate* 21 | !data/parity/.gitkeep 22 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.6.6 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.6.1 2 | 3 | ENV APP_HOME=/home/app 4 | 5 | ARG UID=1000 6 | ARG GID=1000 7 | 8 | RUN groupadd -r --gid ${GID} app \ 9 | && useradd --system --create-home --home ${APP_HOME} --shell /sbin/nologin --no-log-init \ 10 | --gid ${GID} --uid ${UID} app 11 | 12 | USER app 13 | WORKDIR $APP_HOME 14 | 15 | COPY --chown=app:app . . 16 | 17 | RUN bundle install --jobs=$(nproc) --deployment 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 6 | 7 | ruby '~>2.6' 8 | 9 | gem 'rake' 10 | gem 'sshkey' # SSH key generation gem 11 | 12 | # webhook server deps 13 | gem 'bump' 14 | gem 'rack' 15 | gem 'sinatra' 16 | gem 'puma' 17 | gem 'rspec' 18 | gem 'jwt' 19 | gem 'faraday' 20 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | bump (0.9.0) 5 | diff-lcs (1.3) 6 | faraday (1.0.0) 7 | multipart-post (>= 1.2, < 3) 8 | jwt (2.2.1) 9 | multipart-post (2.1.1) 10 | mustermann (1.1.1) 11 | ruby2_keywords (~> 0.0.1) 12 | nio4r (2.5.8) 13 | puma (4.3.12) 14 | nio4r (~> 2.0) 15 | rack (2.2.6.2) 16 | rack-protection (2.0.8.1) 17 | rack 18 | rake (13.0.1) 19 | rspec (3.9.0) 20 | rspec-core (~> 3.9.0) 21 | rspec-expectations (~> 3.9.0) 22 | rspec-mocks (~> 3.9.0) 23 | rspec-core (3.9.1) 24 | rspec-support (~> 3.9.1) 25 | rspec-expectations (3.9.0) 26 | diff-lcs (>= 1.2.0, < 2.0) 27 | rspec-support (~> 3.9.0) 28 | rspec-mocks (3.9.1) 29 | diff-lcs (>= 1.2.0, < 2.0) 30 | rspec-support (~> 3.9.0) 31 | rspec-support (3.9.2) 32 | ruby2_keywords (0.0.2) 33 | sinatra (2.0.8.1) 34 | mustermann (~> 1.0) 35 | rack (~> 2.0) 36 | rack-protection (= 2.0.8.1) 37 | tilt (~> 2.0) 38 | sshkey (2.0.0) 39 | tilt (2.0.10) 40 | 41 | PLATFORMS 42 | ruby 43 | 44 | DEPENDENCIES 45 | bump 46 | faraday 47 | jwt 48 | puma 49 | rack 50 | rake 51 | rspec 52 | sinatra 53 | sshkey 54 | 55 | RUBY VERSION 56 | ruby 2.6.3p62 57 | 58 | BUNDLED WITH 59 | 2.1.4 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Cryptocurrency Exchange Platform - OpenDAX](https://github.com/openware/meta/raw/main/images/github_opendax.png) 2 | 3 |

4 | Guide | 5 | API Docs | 6 | Consulting | 7 | Community 8 |

9 |
OpenDAX Trading Platform
10 | 11 | # OpenDAX 12 | 13 | OpenDAX is an open-source cloud-native multi-service platform for building a Blockchain/FinTech exchange of digital assets, cryptocurrency and security tokens. 14 | 15 | ## Getting started with OpenDAX 16 | 17 | ### 1. Get a VM 18 | 19 | Minimum VM requirements for OpenDAX: 20 | * 8GB of RAM (12GB recommended) 21 | * 4 cores vCPU (6 cores recommended) 22 | * 300GB disk space (SSD recommended) 23 | 24 | A VM from any cloud provider like DigitalOcean, Vultr, GCP, AWS as well as any dedicated server with Ubuntu, Debian or Centos would work 25 | 26 | ### 2. Prepare the VM 27 | 28 | #### 2.1 Create Unix user 29 | SSH using root user, then create new user for the application 30 | ```bash 31 | useradd -g users -s `which bash` -m app 32 | ``` 33 | 34 | #### 2.2 Install Docker and docker compose 35 | 36 | We highly recommend using docker and compose from docker.com install guide instead of the system provided package, which would most likely be deprecated. 37 | 38 | Docker follow instruction here: [docker](https://docs.docker.com/install/) 39 | Docker compose follow steps: [docker compose](https://docs.docker.com/compose/install/) 40 | 41 | #### 2.3 Install ruby in user app 42 | 43 | ##### 2.3.1 Change user using 44 | ```bash 45 | su - app 46 | ``` 47 | 48 | ##### 2.3.2 Clone OpenDAX 49 | ```bash 50 | git clone https://github.com/openware/opendax.git 51 | ``` 52 | 53 | ##### 2.3.3 Install RVM 54 | ```bash 55 | gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB 56 | curl -sSL https://get.rvm.io | bash -s stable 57 | cd opendax 58 | rvm install . 59 | ``` 60 | 61 | ### 3. Bundle install dependencies 62 | 63 | ```bash 64 | bundle install 65 | rake -T # To see if ruby and lib works 66 | ``` 67 | 68 | Using `rake -T` you can see all available commands, and can create new ones in `lib/tasks` 69 | 70 | ### 4. Run everything 71 | 72 | #### 4.1 Configure your domain 73 | If using a VM you can point your domain name to the VM ip address before this stage. 74 | Recommended if you enabled SSL, for local development edit the `/etc/hosts` 75 | 76 | Insert in file `/etc/hosts` 77 | ``` 78 | 0.0.0.0 www.app.local 79 | ``` 80 | 81 | #### 4.2 Bring everything up 82 | 83 | ```bash 84 | rake service:all 85 | ``` 86 | 87 | You can login on `www.app.local` with the following default users from seeds.yaml 88 | ``` 89 | Seeded users: 90 | Email: admin@barong.io, password: 0lDHd9ufs9t@ 91 | Email: john@barong.io, password: Am8icnzEI3d! 92 | ``` 93 | 94 | ### [Optional] KYCAID 95 | 96 | In order to accelerate customer interaction, reduce risks and simplify business processes you can use KYC Verification Service from KYCaid. 97 | KYC goal is to prevent fraud and to decline users that don’t fulfill certain standards of credibility. 98 | To learn more about KYCaid and pricing you can visit their website - [kycaid.com](https://www.kycaid.com/) 99 | 100 | #### How to configure KYCAID on the platform? 101 | 102 | KYCAID is already integrated into our stack, to use it you'd need to create an account on [kycaid.com](https://www.kycaid.com/), and set up authentification creds there and the callback url: https://example.com/api/v2/barong/public/kyc 103 | 104 | After that all you have to do is to change several lines in `config/app.yml`: 105 | 106 | ```yaml 107 | kyc: 108 | provider: kycaid 109 | authorization_token: changeme # your production API token from the 'Settings' section of kycaid.com 110 | sandbox_mode: true # 'true' for test environments - documents will be verified/rejected automatically, without payment for verification 111 | api_endpoint: https://api.kycaid.com/ 112 | ``` 113 | 114 | ##### Additional settings for KYCAID 115 | 116 | * Be sure to check `BARONG_REQUIRED_DOCS_EXPIRE` ENV value inside `config/barong.env` to be `false` if you want to include `address` verification in your KYC process. You can set it to `true` if you need the document check only. 117 | * Check if you have the correct list of `document_types` in the `config/barong/barong.yml` file: 118 | - Passport 119 | - Identity card 120 | - Driver license 121 | - Address 122 | * Frontend KYC steps can be configured in `templates/config/frontend/env.js.erb` via the `kycSteps` field 123 | * Tower KYC labels can be configured in `templates/config/frontend/tower.js.erb` via the `labelSwitcher` field 124 | 125 | ## Usage 126 | 127 | ### Initial configuration 128 | 129 | All the OpenDAX deployment files have their confguration stored in `config/app.yml`. 130 | 131 | #### app.yml 132 | 133 | The following table lists the configurable parameters of the config/app.yml configuration file and its default values. 134 | 135 | Parameter | Description | Default 136 | --- | --- | --- 137 | `app.name` | global application name | `"OpenDax"` 138 | `app.domain` | base domain name | `app.local` 139 | `app.subdomain` | subdomain | `www` 140 | `app.show_landing` | enable/disable landing page display for the frontend application | `true` 141 | `render_protect` | enable read-only mode for rendered files | `false` 142 | `csrfEnabled` | enable CSRF protection on Barong | `false` 143 | `ssl.enabled` | enable SSL certificate generation | `false` 144 | `ssl.email` | email address used for SSL certificate issuing | `"support@example.com"` 145 | `updateVersions` | update all image tags by fetching global ones for OpenDAX | `false` 146 | `images` | Docker image tags per component 147 | `vendor.frontend` | optional Git URL for a development frontend repo | `git@github.com:openware/baseapp.git` 148 | `kyc.provider` | KYC provider, can be `kycaid` or `local` | `kycaid` 149 | `kyc.authorization_token` | optional API token for KYCAID use | `changeme` 150 | `kyc.sandbox` | enable KYCAID test mode | `true` 151 | `kyc.api_endpoint` | API endpoint for KYCAID | `https://api.kycaid.com/` 152 | `vault.root_token` | Root Vault authentication token | `changeme ` 153 | `vault.peatio_rails_token` | Peatio Server Vault authentication token | `changeme ` 154 | `vault.peatio_crypto_token` | Peatio Daemons (cron_job, deposit, deposit_coin_address, withdraw_coin) Vault authentication token | `changeme ` 155 | `vault.peatio_upstream_token` | Peatio Upstream Daemon Vault authentication token | `changeme ` 156 | `vault.peatio_matching_token` | Peatio Daemons (matching, order_processor, trade_executor) Vault authentication token | `changeme ` 157 | `vault.barong_token` | Barong Vault authentication token | `changeme ` 158 | `vault.finex_engine_token` | Finex Engine Vault authentication token | `changeme ` 159 | `database.adapter`| database adapter kind either `mysql` or `postgresql` |`mysql` 160 | `database.host` | database host name | `db` 161 | `database.port` | database port | `3306 ` 162 | `database.user` | database username | `root` 163 | `database.password` | database root password | `changeme` 164 | `storage.provider` | object storage provider | `"Google"` 165 | `storage.bucketname` | storage bucket name | `"opendax-barong-docs-bucket"` 166 | `storage.endpoint` | S3-compatible storage API endpoint | `"https://fra1.digitaloceanspaces.com"` 167 | `storage.region` | storage region | `"fra1"` 168 | `storage.signatureVersion` | S3-compatible storage API signature version(2 or 4) | `"fra1"` 169 | `storage.secretkey`, `storage.accesskey` | storage access keys | `"changeme"` 170 | `twilio` | [Twilio](https://www.twilio.com/) SMS provider configs 171 | `gaTrackerKey` | [Google Analytics](https://analytics.google.com/) tracker key inserted into the frontend app 172 | `smtp` | SMTP configs used for sending platform emails 173 | `captcha` | captcha configuration([Recaptcha](https://www.google.com/recaptcha) or [Geetest](https://www.geetest.com)) 174 | `wallets` | configs for wallets seeded during the initial deployment of Peatio 175 | `parity` | Parity cryptonode configuration 176 | `bitcoind` | Bitcoind cryptonode configuration 177 | `litecoind` | Litecoind cryptonode configuration 178 | `terraform.credentials` | local path to a GCP service account JSON key | `"~/safe/opendax.json"` 179 | `terraform.project` | GCP project name | `"example-opendax"` 180 | 181 | ### utils.yml 182 | 183 | The following table lists configurable parameters of the `config/utils.yml` file: 184 | 185 | Parameter | Description | Default 186 | --- | --- | --- 187 | images | Docker image tags per component | 188 | superset | Superset BI tool configs | 189 | arke | Arke liquidity bot configs | 190 | 191 | Once you're done with the configuration, render the files using `rake render:config`. You can easily apply your changes at any time by running this command. 192 | 193 | Note: be sure to append all the subdomains based on app.domain to your 194 | /etc/hosts file if you're running OpenDax locally 195 | 196 | ### Bringing up the stack 197 | 198 | The OpenDAX stack can be brought up using two ways: 199 | 200 | 1. Bootstrap all the components at once using `rake service:all[start]` 201 | 2. Start every component one-by-one using `rake service:*component*[start]` 202 | 203 | The components included in the stack are: 204 | 205 | - `proxy` - [Traefik](https://traefik.io/), a robust cloud-native edge router/reverse proxy written in Go 206 | - `backend` - [Vault](https://www.vaultproject.io), [MySQL](https://www.mysql.com), [Redis](https://redis.io) and [RabbitMQ](https://www.rabbitmq.com) grouped together 207 | - `cryptonodes` - cryptocurrency nodes such as [parity](https://github.com/paritytech/parity-ethereum) **[Optional]** 208 | - `daemons` - Peatio and Ranger daemons **[Optional]** 209 | - `setup` - setup hooks for Peatio and Barong to run before the application starts (DB migration etc.) 210 | - `app` - Peatio is the [crypto exchange software](https://www.openware.com/), [Barong](https://github.com/openware/barong) and the [Ambassador](https://www.getambassador.io) API gateway 211 | - `frontend` - the frontend application located at `vendor/frontend` 212 | - `tower` - the Tower admin panel application located at `vendor/tower` 213 | - `monitoring` - [cAdvisor](https://github.com/google/cadvisor) and [Node Exporter](https://github.com/prometheus/node_exporter) monitoring tools **[Optional]** 214 | 215 | For example, to start the `backend` services, you'll simply need to run `rake service:backend[start]` 216 | 217 | Note: all the components marked as [Optional] need to be installed using 218 | rake service:*component*[start] explicitly 219 | 220 | Go ahead and try your own OpenDAX exchange deployment! 221 | 222 | ### Stopping and restarting components 223 | 224 | Any component from the stack can be easily stopped or restarted using `rake service:*component*[stop]` and `rake service:*component*[restart]`. 225 | 226 | For example, `rake service:frontend[stop]` would stop the frontend application container and `rake service:proxy[restart]` would completely restart the reverse proxy container. 227 | 228 | # Managing component deployments 229 | 230 | Each component has a config file (ex. `config/frontend/tower.js`) and a compose file (ex. `compose/frontend.yaml`). 231 | 232 | All config files are mounted into respective component container, except from `config/app.yml` - this file contains all the neccessary configuration of opendax deployment 233 | 234 | Compose files contain component images, environment configuration etc. 235 | 236 | These files get rendered from their respective templates that are located under `templates` directory. 237 | 238 | ## How to update component image? 239 | 240 | Modify `config/app.yml` with correct image and run `rake service:all` 241 | This will rerender all the files from `templates` directory and restart all the running services. 242 | 243 | Alternitavely you can update the following files: 244 | * `config/app.yml` 245 | * `templates/compose/*component*.yml` 246 | * `compose/*component*.yml` 247 | And run `rake service:component[start]` 248 | 249 | ## How to update component config? 250 | 251 | Modify `config/*component*/*config*` and run `rake service:component[start]`, 252 | if you want the changes to be persistent, you also need to update `templates/config/*components*/*config*` 253 | 254 | #### Render compose file 255 | ``` 256 | # Delete all generated files 257 | git clean -fdx 258 | 259 | # Re-generate config from config/app.yml values 260 | rake render:config 261 | 262 | # Restart the container you need to reload config 263 | docker-compose up frontend -Vd 264 | ``` 265 | 266 | #### Clone the vendors and start 267 | ``` 268 | source ./bin/set-env.sh 269 | rake vendor:clone 270 | docker-compose -f compose/vendor.yaml up -d 271 | ``` 272 | 273 | ## Vault management 274 | Opendax uses [Vault Policies](https://www.vaultproject.io/docs/concepts/policies) to restrict components' access to sensitive data. Each component has its own Vault token which allows granular access only to the data required. 275 | 276 | OpenDAX has 2 rake tasks for Vault management: 277 | ```sh 278 | rake vault:setup # Initial Vault configuration (root token generation, unseal, endpoints configuration) 279 | rake vault:load_policies # Components' Vault token generation 280 | ``` 281 | 282 | ### Troubleshooting 283 | #### Vault is sealed 284 | 285 | In case of such error: 286 | 1. Run `rake vault:setup` 287 | 2. Restart the component 288 | 289 | Make sure you're not using an existing Docker volume for Vault(i.e. one left after a different Vault container deployment): 290 | ```sh 291 | docker volume ls | grep vault 292 | ``` 293 | 294 | In case there are existing volumes, remove the running Vault container via `docker rm -f *id*` and run `docker volume rm -f *volume name*` 295 | Afterward, run `docker-compose up -Vd vault` and re-run `rake vault:setup`. 296 | 297 | #### Vault permission denied 298 | Usually, this means that one of your Vault tokens has expired. 299 | 300 | To fix the issue: 301 | 1. Run `rake vault:load_policies` 302 | 2. Run `rake render:config` 303 | 3. Restart Vault dependant components: 304 | 305 | ``` 306 | docker-compose up -Vd barong peatio cron_job deposit deposit_coin_address withdraw_coin upstream 307 | 308 | # If you are using Finex 309 | docker-compose up -Vd finex-engine 310 | 311 | # If you are using Peatio Matching Engine 312 | docker-compose up -Vd matching order_processor trade_executor 313 | ``` 314 | 315 | ## Terraform Infrastructure as Code Provisioning 316 | 317 | You can easily deploy OpenDAX from scratch on Google Cloud Platform using [Terraform](https://www.terraform.io)! 318 | 319 | To do this, just follow these simple steps: 320 | - Fill `app.yml` with correct values 321 | - Run `rake terraform:apply` 322 | - Access your VM from the GCP Cloud Console 323 | 324 | To destroy the provisioned infrastructure, just run `rake terraform:destroy` 325 | 326 | ## Installer tool 327 | 328 | ``` 329 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/openware/opendax/master/bin/install)" 330 | ``` 331 | 332 | ## Using an OpenDAX deployment for local frontend development 333 | 334 | If you'd like to use a real API from an existing OpenDAX deployment when developing frontend components(e.g. [baseapp](https://github.com/openware/baseapp)), modify `templates/config/gateway/envoy.yaml.erb` file the following way: 335 | 336 | 1. Set `allow_origin` as `"*"` 337 | 338 | 2. Configure all the needed HTTP methods in `allow_methods`. For example: `allow_methods: "PUT, GET, POST, DELETE, PATCH"` 339 | 340 | 3. Add `'total, page, x-csrf-token'` to `allow_headers` value 341 | 342 | 4. Configure `expose_headers` in a similar way `expose_headers: "total, page, x-csrf-token"` 343 | 344 | 5. Add `allow_credentials: true` to your CORS configuration 345 | 346 | After completing these steps, you should have the following config: 347 | ``` 348 | cors: 349 | allow_origin: 350 | - "*" 351 | allow_methods: "PUT, GET, POST, DELETE, PATCH" 352 | allow_headers: "content-type, x-grpc-web, total, page, x-csrf-token" 353 | expose_headers: "total, page, x-csrf-token" 354 | allow_credentials: true 355 | ``` 356 | 357 | Afterwards, apply the config onto your deployment: 358 | ``` 359 | rake render:config 360 | docker-compose up -Vd gateway 361 | ``` 362 | 363 | ## Happy trading with OpenDAX! 364 | 365 | If you have any comments, feedback and suggestions, we are happy to hear from you here at GitHub or here: [crypto exchange software](https://www.openware.com/) 366 | 367 | ## 2.6 Migration guide 368 | 369 | To migrate from 2.5 to 2.6, do the following: 370 | 1. Pull 2-6-stable branch 371 | While rebasing, rename your `vault.token` to `vault.root_token` in `config/app.yml` 372 | 2. Run `rake render:config` 373 | 3. Run `dc up -Vd vault` 374 | 4. Run `rake service:all` 375 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | require 'base64' 3 | require 'erb' 4 | 5 | CONFIG_PATH = 'config/app.yml'.freeze 6 | UTILS_PATH = 'config/utils.yml'.freeze 7 | 8 | @config = YAML.load_file(CONFIG_PATH) 9 | @utils = YAML.load_file(UTILS_PATH) 10 | 11 | # Add your own tasks in files placed in lib/tasks ending in .rake 12 | Dir.glob('lib/tasks/*.rake').each do |task| 13 | load task 14 | end 15 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.1.57 2 | -------------------------------------------------------------------------------- /bin/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | COMPOSE_VERSION="1.23.2" 4 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" 5 | 6 | # Opendax bootstrap script 7 | install_core() { 8 | sudo bash < /etc/docker/daemon.json 25 | EOS 26 | } 27 | 28 | # Docker installation 29 | install_docker() { 30 | curl -fsSL https://get.docker.com/ | bash 31 | sudo bash < webhook.service 4 | sed -i s#OPENDAX_DIRECTORY#${PWD}#g webhook.service 5 | 6 | echo "Generated Secret: ${SECRET}" 7 | 8 | sudo mv ./webhook.service /etc/systemd/system/webhook.service 9 | sudo systemctl daemon-reload 10 | sudo systemctl start webhook 11 | -------------------------------------------------------------------------------- /bin/quick-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | http --session barong POST http://www.app.local/api/v2/barong/identity/sessions email='admin@barong.io' password='0lDHd9ufs9t@' 6 | http --session barong GET http://www.app.local/api/v2/barong/resource/users/me 7 | http --session barong GET http://www.app.local/api/v2/peatio/account/balances 8 | -------------------------------------------------------------------------------- /bin/set-env.sh: -------------------------------------------------------------------------------- 1 | export UID=$(id -u) 2 | export GID=$(id -g) 3 | alias dc=docker-compose 4 | -------------------------------------------------------------------------------- /bin/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | COMPOSE_VERSION="1.23.2" 4 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" 5 | 6 | install_opendax() { 7 | sudo -u deploy bash < 2 | 3 |   4 | 5 | 6 | 7 | 10 | 11 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %> 9 |
12 |   13 | 14 | 15 |   16 | 17 |
18 | 19 | 20 | 21 | 35 | 36 | 37 | 38 |
39 | 40 | 50 | 51 | 52 |   53 | 54 | 55 | -------------------------------------------------------------------------------- /config/mailer/templates/email_confirmation.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /config/mailer/templates/email_confirmation.ru.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /config/mailer/templates/label.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /config/mailer/templates/new_beneficiary.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /config/mailer/templates/password_reset.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /config/mailer/templates/password_reset.ru.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /config/mailer/templates/session_create.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /config/mailer/templates/withdraw_succeed.en.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /config/mysql/innodb.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | innodb_buffer_pool_size = 2G 3 | innodb_buffer_pool_instances = 2 4 | innodb_log_buffer_size = 128M 5 | innodb_log_file_size = 512M 6 | innodb_flush_log_at_trx_commit = 0 7 | -------------------------------------------------------------------------------- /config/peatio/plugins.yml: -------------------------------------------------------------------------------- 1 | # Be sure to run "bin/install_plugins" when you modify this file. 2 | # 3 | # This file is used for listing Peatio plugins. 4 | # The plugins must be listed as an array. Each element of array described the plugin using the next variables: 5 | # 6 | # * name 7 | # Mandatory. Specify plugin name. The name must be compatible with filesystem rules. 8 | # 9 | # * git 10 | # Mandatory. Specify Git repository URL. 11 | # 12 | # * commit 13 | # Mandatory. Specify commit hash which Peatio will checkout via "bin/install_plugins". 14 | # 15 | # * require 16 | # Optional. Specify relative path to file from vendor/plugins which should be required by Peatio. 17 | # You may set this value to "false" if you don't want Peatio to require the plugin. 18 | 19 | # Example configuration: 20 | #- name: peatio-plugin-example 21 | # git: https://github.com/rubykube/peatio-plugin-example.git 22 | # commit: 11edd2e7c0bef229516f42fde79615a68a008d45 23 | -------------------------------------------------------------------------------- /config/peatio/seed/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/config/peatio/seed/.gitkeep -------------------------------------------------------------------------------- /config/secrets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/config/secrets/.gitkeep -------------------------------------------------------------------------------- /config/utils.yml: -------------------------------------------------------------------------------- 1 | images: 2 | applogic: rubykube/applogic:latest 3 | arke: quay.io/openware/arke:2.6.0-bccb72c 4 | superset: amancevice/superset:0.28.1 5 | superset: 6 | email: superset-admin@openware.com 7 | username: admin 8 | password: changeme 9 | arke: 10 | log_level: INFO 11 | accounts: 12 | - id: 1 13 | driver: bitfaker 14 | debug: false 15 | host: "http://www.app.local" 16 | ws: "ws://www.app.local" 17 | key: "" 18 | secret: "" 19 | delay: 1 20 | 21 | - id: 2 22 | driver: bitfaker 23 | host: "api.binance.com" 24 | key: 25 | secret: 26 | delay: 1 27 | 28 | strategies: 29 | - id: 1 30 | type: copy 31 | debug: true 32 | enabled: true 33 | period: 10 34 | params: 35 | spread_bids: 0.003 36 | spread_asks: 0.003 37 | limit_asks_base: 0.05 38 | limit_bids_base: 0.05 39 | levels_size: 0.25 40 | levels_count: 10 41 | side: both 42 | enable_orderback: false 43 | target: 44 | account_id: 1 45 | market: 46 | id: BTCUSD 47 | base: btc 48 | quote: usd 49 | base_precision: 2 50 | quote_precision: 2 51 | min_ask_amount: 1.5 52 | min_bid_amount: 1.5 53 | sources: 54 | - account_id: 2 55 | market: 56 | id: BTCUSD 57 | base: BTC 58 | quote: USD 59 | base_precision: 8 60 | quote_precision: 8 61 | min_order_back_amount: 1.5 62 | 63 | - id: 2 64 | type: microtrades 65 | debug: true 66 | period: 5 67 | period_random_delay: 10 68 | params: 69 | linked_strategy_id: 1 70 | min_amount: 0.05 71 | max_amount: 10 72 | min_price: 100 73 | max_price: 1000 74 | target: 75 | account_id: 1 76 | market: 77 | id: BTCUSD 78 | base: btc 79 | quote: usd 80 | base_precision: 2 81 | quote_precision: 2 82 | min_ask_amount: 1.5 83 | min_bid_amount: 1.5 84 | strategy: 85 | type: copy 86 | volume_ratio: 0.1 87 | target: 88 | driver: rubykube 89 | market: 'FTHUSD' 90 | host: "http://www.app.local" 91 | key: "" 92 | secret: "" 93 | rate_limit: 1 94 | sources: 95 | - driver: bitfaker 96 | market: 'tETHUSD' 97 | host: "api.bitfinex.com" 98 | key: "" 99 | secret: "" 100 | rate_limit: 0.2 101 | - driver: bitfinex 102 | market: 'tETHUSD' 103 | host: "api.bitfinex.com" 104 | key: "" 105 | secret: "" 106 | rate_limit: 0.2 107 | - driver: binance 108 | market: 'ETHUSDT' 109 | host: "api.binance.com" 110 | key: "" 111 | secret: "" 112 | rate_limit: 0.2 113 | -------------------------------------------------------------------------------- /data/parity/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/data/parity/.gitkeep -------------------------------------------------------------------------------- /docs/aws-install.md: -------------------------------------------------------------------------------- 1 | # AWS Installation Guide 2 | 3 | ## Step 1: Prepare the infrastructure 4 | 5 | Infrastructural requirements for the installation are: 6 | 7 | - An EC2 m5.xlarge **Debian** instance with a 200 GB disk storage 8 | - An Elastic Container Registry repository with the baseapp image 9 | - A DNS record to point to the machine(e.g. `example.domain.com`) 10 | 11 | Create these resources before starting the installation and provision them with your RSA key to be able to connect to the VM instance using SSH. 12 | 13 | ## Step 2: Configure the instance 14 | 15 | Connect to the instance over SSH as a `root`/`admin` user and perform the following steps. 16 | 17 | ### Core dependencies 18 | 19 | ```bash 20 | apt-get update 21 | apt-get install -y -q git tmux gnupg2 dirmngr dbus htop curl libmariadbclient-dev-compat build-essential 22 | ``` 23 | 24 | ### Docker installation 25 | 26 | ```bash 27 | curl -fsSL https://get.docker.com/ | bash 28 | usermod -a -G docker $USER 29 | 30 | COMPOSE_VERSION="1.23.2" 31 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" 32 | 33 | curl -L "$COMPOSE_URL" -o /usr/local/bin/docker-compose 34 | chmod +x /usr/local/bin/docker-compose 35 | ``` 36 | 37 | ### User creation 38 | 39 | ```bash 40 | groupadd app 41 | useradd --create-home --home /home/app --shell /bin/bash \ 42 | --gid app --groups docker,sudo app 43 | ``` 44 | 45 | ### Ruby installation 46 | 47 | As the `app` user(`sudo su app`), run: 48 | 49 | ```bash 50 | gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB 51 | curl -sSL https://get.rvm.io | bash -s stable 52 | source /home/app/.rvm/scripts/rvm 53 | rvm install --quiet-curl 2.6.1 54 | rvm use --default 2.6.1 55 | gem install bundler 56 | ``` 57 | 58 | ## Step 3: Prepare the deployment 59 | 60 | Clone the opendax repo to `/home/app` 61 | 62 | ```bash 63 | git clone git@git.openware.com:opendax 64 | ``` 65 | 66 | `cd` into the `opendax` directory and prepare `config/app.yml` according to the [README](../README.md). 67 | 68 | When the configuration is ready, run 69 | 70 | ```bash 71 | bundle install 72 | rake render:config 73 | rake parity:import && \ 74 | until rake wallet:create['deposit','http://0.0.0.0:8545','changeme']; do sleep 15; done && \ 75 | rake wallet:create['hot','http://0.0.0.0:8545','changeme'] && \ 76 | rake wallet:create['warm','http://0.0.0.0:8545','changeme'] && \ 77 | rake render:config && \ 78 | rake service:all && \ 79 | chmod +x bin/install_webhook 80 | ./bin/install_webhook 81 | ``` 82 | 83 | After the deployment process is finished, the frontend would be accessible from the domain provided in the configuration. -------------------------------------------------------------------------------- /docs/images/OpenDAX-authorization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/docs/images/OpenDAX-authorization.png -------------------------------------------------------------------------------- /docs/troubleshoot-barong-authz.md: -------------------------------------------------------------------------------- 1 | # Troubleshoot barong authorization process and envoy routing 2 | 3 | ## Architecture overview 4 | 5 | Before establishing a connection to a microservice (for example ***rango***) envoy verifies the authorization by sending a request to ***barong authz***. Barong authz verifies the cookie (when using the UI) and the HMAC signature (when using API) and returns a signed token (JWT) if everything is valid. 6 | 7 | ![OpenDAX authorization](./images/OpenDAX-authorization.png) 8 | 9 | 10 | ## Enable envoy debug logs 11 | 12 | To troubleshoot connection problems with a microservice of the stack, you can enable envoy logs to understand in which step the connection problem appears. 13 | 14 | To do so you need to: 15 | 16 | 1. Edit *templates/compose/gateway.yaml.erb* 17 | 18 | 2. Change *info* by *debug* in the following lines: 19 | 20 | ```yaml 21 | command: /usr/local/bin/envoy -l debug -c /etc/envoy/envoy.yaml 22 | ``` 23 | 24 | 3. Render the configuration files 25 | 26 | ```bash 27 | rake render:config 28 | ``` 29 | 30 | 4. Restart envoy 31 | 32 | ```bash 33 | docker-compose up -dV gateway 34 | ``` 35 | 36 | 5. Finally you can inspect the envoy logs 37 | 38 | ```bash 39 | docker-compose logs -f --tail 100 gateway 40 | ``` 41 | 42 | Here are the relevant logs: 43 | 44 | 1. Initial websocket connection 45 | ```log 46 | gateway_1 | [2020-12-02 07:50:30.169][13][debug][http] [source/common/http/conn_manager_impl.cc:580] [C184][S12609685784760114286] request headers complete (end_stream=false): 47 | gateway_1 | ':authority', 'www.app.local' 48 | gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers' 49 | gateway_1 | ':method', 'GET' 50 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36' 51 | gateway_1 | 'accept-encoding', 'gzip, deflate' 52 | gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8' 53 | gateway_1 | 'cache-control', 'no-cache' 54 | gateway_1 | 'connection', 'Upgrade' 55 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46' 56 | gateway_1 | 'origin', 'http://www.app.local' 57 | gateway_1 | 'pragma', 'no-cache' 58 | gateway_1 | 'sec-websocket-key', 'b16LunIyXls4CtNZ1lYWsw==' 59 | gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits' 60 | gateway_1 | 'sec-websocket-version', '13' 61 | gateway_1 | 'upgrade', 'websocket' 62 | gateway_1 | 'x-forwarded-for', '172.20.0.1' 63 | gateway_1 | 'x-forwarded-host', 'www.app.local' 64 | gateway_1 | 'x-forwarded-port', '80' 65 | gateway_1 | 'x-forwarded-proto', 'ws' 66 | gateway_1 | 'x-forwarded-server', '41e065adb32e' 67 | gateway_1 | 'x-real-ip', '172.20.0.1' 68 | ``` 69 | 70 | 2. Request to Barong authz 71 | ```log 72 | gateway_1 | [2020-12-02 07:50:30.183][13][debug][router] [source/common/router/router.cc:320] [C0][S3254558628791445120] cluster 'barong' match for URL '/api/v2/auth/api/v2/ranger/private/?stream=global.tickers' 73 | gateway_1 | [2020-12-02 07:50:30.184][13][debug][router] [source/common/router/router.cc:381] [C0][S3254558628791445120] router decoding headers: 74 | gateway_1 | ':method', 'GET' 75 | gateway_1 | ':path', '/api/v2/auth/api/v2/ranger/private/?stream=global.tickers' 76 | gateway_1 | ':authority', 'www.app.local' 77 | gateway_1 | ':scheme', 'http' 78 | gateway_1 | 'content-length', '0' 79 | gateway_1 | 'x-forwarded-for', '172.20.0.1,172.20.0.8' 80 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46' 81 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36' 82 | gateway_1 | 'x-forwarded-host', 'www.app.local' 83 | gateway_1 | 'x-forwarded-proto', 'ws' 84 | gateway_1 | 'x-envoy-internal', 'true' 85 | gateway_1 | 'x-envoy-expected-rq-timeout-ms', '1000' 86 | ``` 87 | 88 | 3. Routing the connection to rango 89 | 90 | ```log 91 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][filter] [source/extensions/filters/http/ext_authz/ext_authz.cc:175] [C186][S2592169017517480399] ext_authz filter accepted the request 92 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][router] [source/common/router/router.cc:320] [C186][S2592169017517480399] cluster 'rango' match for URL '/api/v2/ranger/private/?stream=global.tickers' 93 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][router] [source/common/router/router.cc:381] [C186][S2592169017517480399] router decoding headers: 94 | gateway_1 | ':authority', 'www.app.local' 95 | gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers' 96 | gateway_1 | ':method', 'GET' 97 | gateway_1 | ':scheme', 'http' 98 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36' 99 | gateway_1 | 'accept-encoding', 'gzip, deflate' 100 | gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8' 101 | gateway_1 | 'cache-control', 'no-cache' 102 | gateway_1 | 'connection', 'Upgrade' 103 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46' 104 | gateway_1 | 'origin', 'http://www.app.local' 105 | gateway_1 | 'pragma', 'no-cache' 106 | gateway_1 | 'sec-websocket-key', 'tocGzAPK8TACk8zzRX7n3g==' 107 | gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits' 108 | gateway_1 | 'sec-websocket-version', '13' 109 | gateway_1 | 'upgrade', 'websocket' 110 | gateway_1 | 'x-forwarded-for', '172.20.0.1' 111 | gateway_1 | 'x-forwarded-host', 'www.app.local' 112 | gateway_1 | 'x-forwarded-port', '80' 113 | gateway_1 | 'x-forwarded-proto', 'ws' 114 | gateway_1 | 'x-forwarded-server', '41e065adb32e' 115 | gateway_1 | 'x-real-ip', '172.20.0.1' 116 | gateway_1 | 'content-length', '0' 117 | gateway_1 | 'x-envoy-internal', 'true' 118 | gateway_1 | 'x-request-id', '5b87e64a-4155-498e-916c-b8b998725a71' 119 | gateway_1 | 'x-envoy-expected-rq-timeout-ms', '15000' 120 | gateway_1 | ':status', '200' 121 | gateway_1 | 'authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2MDY4OTU0MzAsImV4cCI6MTYwNjg5OTAzMCwic3ViIjoic2Vzc2lvbiIsImlzcyI6ImJhcm9uZyIsImF1ZCI6WyJwZWF0aW8iLCJiYXJvbmciXSwianRpIjoiNTllNGIwNTA3YTgyMGNjMzYzMTIiLCJ1aWQiOiJJRDVGRkE5OERDMjciLCJlbWFpbCI6ImFkbWluQGJhcm9uZy5pbyIsInJvbGUiOiJhZG1pbiIsImxldmVsIjozLCJzdGF0ZSI6ImFjdGl2ZSIsInJlZmVycmFsX2lkIjpudWxsfQ.Br6-yujI5MgU_BktVDYNaEPNtHOMxQZbNS89deQfxNiPPkx6B8ZUDXL9og5DQ6nWBExlHydyPPcCSUvO5BCth_UWiuttY_ldy7TIr_JrXT0td8WN8fq8QadOWFuJ7wvMEklRGVKQmvOrooHNKz_WwcY4xmaSO3SVgQdFSkmt626MOXmo9Wa3nYsL6EafCMe--9PHWop4L-B1w5ndvbGuGLbJaqEktXsudOX0A9Js2sKuHPxSe8QJKN5XwmOFPAWM28-VkaU5cmshMK2CwJaSRhVoL0gIi9VUGpFVVJ1ciD0VHjRfxuFTzph7utRuO_M9N-bweLL8YCCA8RkwlVyuLg' 122 | gateway_1 | 'content-type', 'text/html; charset=utf-8' 123 | gateway_1 | 'cache-control', 'no-cache' 124 | gateway_1 | 'set-cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46; path=/; expires=Thu, 03 Dec 2020 07:50:30 GMT; HttpOnly' 125 | gateway_1 | 'x-request-id', '8ff80928-9091-40b0-b6f0-c0b46f8d72fe' 126 | gateway_1 | 'x-runtime', '0.031033' 127 | gateway_1 | 'vary', 'Origin' 128 | gateway_1 | 'transfer-encoding', 'chunked' 129 | gateway_1 | 'x-envoy-upstream-service-time', '37' 130 | ``` 131 | 132 | 133 | ## Authz configuration 134 | 135 | In case of authorization problem check the following configuration files: 136 | 137 | 1. *config/barong/authz_rules.yml* 138 | This file contains the default public endpoints and blocked endpoints. 139 | If you have a problem accessing a public endpoint make sure the URL is present in the *rules.pass* section. 140 | 141 | 2. *templates/config/barong/seeds.yml.erb* 142 | Check the *permissions* section to make sure the role of the user is allowed to access the resource. 143 | 144 | Run the following command to apply the changes: 145 | 146 | ```bash 147 | rake service:setup 148 | ``` 149 | -------------------------------------------------------------------------------- /docs/ubuntu-install.md: -------------------------------------------------------------------------------- 1 | # Install OpenDax in Ubuntu 18.04 2 | 3 | ## Step 1: Install Docker 4 | 5 | To install Docker you will need to do those steps with `sudo` or login as root user with `sudo -i` 6 | 7 | Create a Unix user for holding your application 8 | ``` 9 | groupadd app 10 | useradd -d /home/app -s `which bash` -g app -m app 11 | ``` 12 | 13 | ### Installing from apt-get 14 | 15 | First, update your existing list of packages: 16 | 17 | ``` 18 | apt update 19 | ``` 20 | 21 | Next, install a few prerequisite packages which let apt use packages over HTTPS: 22 | 23 | ``` 24 | apt install apt-transport-https ca-certificates curl software-properties-common 25 | ``` 26 | 27 | Then add the GPG key for the official Docker repository to your system: 28 | 29 | ``` 30 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - 31 | ``` 32 | 33 | Add the Docker repository to APT sources: 34 | 35 | ``` 36 | add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" 37 | ``` 38 | 39 | Next, update the package database with the Docker packages from the newly added repo: 40 | 41 | ``` 42 | apt update 43 | ``` 44 | 45 | Make sure you are about to install from the Docker repo instead of the default Ubuntu repo: 46 | 47 | Finally, install Docker: 48 | 49 | ``` 50 | apt install docker-ce 51 | ``` 52 | 53 | Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it's running: 54 | 55 | ``` 56 | systemctl status docker 57 | ``` 58 | 59 | Add your app user into the docker group 60 | 61 | ``` 62 | usermod -aG docker app 63 | ``` 64 | 65 | ## Step 2: Install Docker Compose 66 | 67 | Run this command to download the latest version of Docker Compose: 68 | 69 | ``` 70 | curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 71 | 72 | chmod +x /usr/local/bin/docker-compose 73 | ``` 74 | 75 | ## Step 3: Clone OpenDax 76 | 77 | Login to your app user: 78 | ``` 79 | su - app 80 | ``` 81 | 82 | Clone opendax repository 83 | ``` 84 | cd $HOME 85 | git clone https://github.com/rubykube/opendax.git 86 | cd opendax 87 | ``` 88 | 89 | ## Step 4: Clone your frontend 90 | 91 | Edit config file `config/app.yml` 92 | -------------------------------------------------------------------------------- /lib/opendax/payload.rb: -------------------------------------------------------------------------------- 1 | require 'jwt' 2 | 3 | module Opendax 4 | 5 | class Error < StandardError 6 | end 7 | 8 | class Payload 9 | def initialize(params) 10 | @secret = params[:secret] 11 | @expire = params[:expire] || 600 12 | 13 | raise Opendax::Error.new unless @secret 14 | raise Opendax::Error.new unless @expire > 0 15 | end 16 | 17 | def generate!(params) 18 | raise Opendax::Error.new unless params[:service] 19 | raise Opendax::Error.new unless params[:image] 20 | 21 | token = params.merge({ 22 | 'iat': Time.now.to_i, 23 | 'exp': (Time.now + @expire).to_i 24 | }) 25 | 26 | JWT.encode token, @secret, 'HS256' 27 | end 28 | 29 | def decode!(token) 30 | JWT.decode(token, @secret, true, { 31 | algorithm: 'HS256' 32 | }).first 33 | end 34 | 35 | def safe_decode(token) 36 | begin 37 | decode!(token) 38 | rescue JWT::ExpiredSignature 39 | rescue JWT::ImmatureSignature 40 | rescue JWT::VerificationError 41 | rescue JWT::DecodeError 42 | nil 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/opendax/renderer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'openssl' 4 | require 'sshkey' 5 | require 'pathname' 6 | require 'yaml' 7 | require 'base64' 8 | require 'fileutils' 9 | 10 | module Opendax 11 | # Renderer is class for rendering Opendax templates. 12 | class Renderer 13 | TEMPLATE_PATH = Pathname.new('./templates') 14 | 15 | BARONG_KEY = 'config/secrets/barong.key' 16 | APPLOGIC_KEY = 'config/secrets/applogic.key' 17 | SSH_KEY = 'config/secrets/app.key' 18 | 19 | def render 20 | @config ||= config 21 | @utils ||= utils 22 | @name ||= @config['app']['name'].downcase 23 | @barong_key ||= OpenSSL::PKey::RSA.new(File.read(BARONG_KEY), '') 24 | @applogic_key ||= OpenSSL::PKey::RSA.new(File.read(APPLOGIC_KEY), '') 25 | @barong_private_key ||= Base64.urlsafe_encode64(@barong_key.to_pem) 26 | @barong_public_key ||= Base64.urlsafe_encode64(@barong_key.public_key.to_pem) 27 | @applogic_private_key ||= Base64.urlsafe_encode64(@applogic_key.to_pem) 28 | @applogic_public_key ||= Base64.urlsafe_encode64(@applogic_key.public_key.to_pem) 29 | 30 | Dir.glob("#{TEMPLATE_PATH}/**/*.erb", File::FNM_DOTMATCH).each do |file| 31 | output_file = template_name(file) 32 | FileUtils.chmod 0o644, output_file if File.exist?(output_file) 33 | render_file(file, output_file) 34 | FileUtils.chmod 0o444, output_file if @config['render_protect'] 35 | end 36 | end 37 | 38 | def render_file(file, out_file) 39 | puts "Rendering #{out_file}" 40 | result = ERB.new(File.read(file), trim_mode: '-').result(binding) 41 | dir = File.dirname(out_file) 42 | FileUtils.mkdir(dir) unless Dir.exist?(dir) 43 | File.write(out_file, result) 44 | end 45 | 46 | def ssl_helper(arg) 47 | @config['ssl']['enabled'] ? arg << 's' : arg 48 | end 49 | 50 | def template_name(file) 51 | path = Pathname.new(file) 52 | out_path = path.relative_path_from(TEMPLATE_PATH).sub('.erb', '') 53 | 54 | File.join('.', out_path) 55 | end 56 | 57 | def render_keys 58 | generate_key(BARONG_KEY) 59 | generate_key(APPLOGIC_KEY) 60 | generate_key(SSH_KEY, public: true) 61 | end 62 | 63 | def generate_key(filename, public: false) 64 | return if File.file?(filename) 65 | 66 | key = SSHKey.generate(type: 'RSA', bits: 2048) 67 | File.write(filename, key.private_key) 68 | File.write("#{filename}.pub", key.ssh_public_key) if public 69 | end 70 | 71 | def config 72 | YAML.load_file('./config/app.yml') 73 | end 74 | 75 | def utils 76 | YAML.load_file('./config/utils.yml') 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/opendax/vault.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Opendax 4 | class Vault 5 | POLICIES_NAMES = ["barong", "finex_engine", "peatio_rails", "peatio_crypto", "peatio_upstream", "peatio_matching"] 6 | 7 | def vault_secrets_path 8 | 'config/vault-secrets.yml' 9 | end 10 | 11 | def vault_exec(command) 12 | `docker-compose exec -T vault sh -c '#{command}'` 13 | end 14 | 15 | def secrets(command, endpoints, options = '') 16 | endpoints.each { |endpoint| vault_exec("vault secrets #{command} #{options} #{endpoint}") } 17 | end 18 | 19 | def setup 20 | puts '----- Checking Vault status -----' 21 | vault_status = YAML.safe_load(vault_exec('vault status -format yaml')) 22 | 23 | return if vault_status.nil? 24 | 25 | if vault_status['initialized'] 26 | puts '----- Vault is initialized -----' 27 | begin 28 | vault_secrets = YAML.safe_load(File.read(vault_secrets_path)) 29 | rescue SystemCallError => e 30 | puts 'Vault keys are missing' 31 | return 32 | end 33 | vault_root_token = vault_secrets['root_token'] 34 | unseal_keys = vault_secrets['unseal_keys_b64'][0, 3] 35 | else 36 | puts '----- Initializing Vault -----' 37 | vault_init_output = YAML.safe_load(vault_exec('vault operator init -format yaml --recovery-shares=3 --recovery-threshold=2')) 38 | File.write(vault_secrets_path, YAML.dump(vault_init_output)) 39 | vault_root_token = vault_init_output['root_token'] 40 | unseal_keys = vault_init_output['unseal_keys_b64'][0, 3] 41 | end 42 | 43 | if vault_status['sealed'] 44 | puts '----- Unsealing Vault -----' 45 | unseal_keys.each { |key| vault_exec("vault operator unseal #{key}") } 46 | else 47 | puts '----- Vault is unsealed -----' 48 | end 49 | 50 | return vault_root_token if vault_status['initialized'] 51 | 52 | puts '----- Vault login -----' 53 | vault_exec("vault login #{vault_root_token}") 54 | 55 | puts '----- Configuring the endpoints -----' 56 | secrets('enable', %w[totp transit]) 57 | secrets('disable', ['secret']) 58 | secrets('enable', ['kv'], '-path=secret -version=1') 59 | vault_root_token 60 | end 61 | 62 | def load_policies(deployment_name, vault_root_token) 63 | puts '----- Vault login -----' 64 | vault_exec("vault login #{vault_root_token}") 65 | 66 | tokens = {} 67 | POLICIES_NAMES.each do |policy| 68 | name = "#{deployment_name.downcase}_#{policy}" 69 | 70 | puts "Loading #{name} policy..." 71 | vault_exec("vault policy write #{name} /tmp/policies/#{policy}.hcl") 72 | 73 | puts "Creating the #{name} token..." 74 | vault_token_create_output = YAML.safe_load(vault_exec("vault token create -policy=#{name} -renewable=true -ttl=240h -period=240h -format=yaml")) 75 | tokens["#{policy}_token"] = vault_token_create_output["auth"]["client_token"] 76 | end 77 | 78 | tokens 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/opendax/webhook.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra/base' 2 | require 'json' 3 | require 'yaml' 4 | 5 | require_relative 'payload' 6 | require_relative 'renderer' 7 | 8 | class Webhook < Sinatra::Base 9 | CONFIG_PATH = 'config/app.yml'.freeze 10 | 11 | set :show_exceptions, false 12 | 13 | def initialize 14 | super 15 | @services = %w[barong peatio frontend tower applogic finex-engine finex-api] 16 | secret = ENV['WEBHOOK_JWT_SECRET'] 17 | raise 'WEBHOOK_JWT_SECRET is not set' if secret.to_s.empty? 18 | @decoder = Opendax::Payload.new(secret: secret) 19 | end 20 | 21 | def update_config(service, image) 22 | config = YAML.load_file(CONFIG_PATH) 23 | config["images"][service] = image 24 | File.open(CONFIG_PATH, 'w') {|f| f.write config.to_yaml } 25 | end 26 | 27 | before do 28 | content_type 'application/json' 29 | end 30 | 31 | get '/deploy/ping' do 32 | 'pong' 33 | end 34 | 35 | get '/deploy/:token' do |token| 36 | decoded = @decoder.safe_decode(token) 37 | return answer(400, 'invalid token') unless decoded 38 | 39 | service = decoded['service'] 40 | image = decoded['image'] 41 | 42 | return answer(400, 'service is not specified') unless service 43 | return answer(400, 'image is not specified') unless image 44 | return answer(404, 'unknown service') unless @services.include? service 45 | return answer(400, 'invalid image') if (%r(^(([-_\w\.]){,20}(\/|:))+([-\w\.]{,20})$) =~ image) == nil 46 | 47 | system "docker image pull #{image}" 48 | 49 | unless $?.success? 50 | system("docker image inspect #{image} > /dev/null") 51 | return answer(404, 'invalid image') unless $?.success? 52 | end 53 | 54 | if $?.success? 55 | update_config(service, image) 56 | 57 | renderer = Opendax::Renderer.new 58 | renderer.render 59 | 60 | system "docker-compose up -Vd #{service}" 61 | end 62 | 63 | return answer(500, 'could not restart container') unless $?.success? 64 | return answer(200, "service #{service} updated with image #{image}") 65 | end 66 | 67 | def answer(response_status, message) 68 | status response_status 69 | 70 | { 71 | message: message 72 | }.to_json 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/tasks/db.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | 3 | def mysql_cli 4 | return "mysql -u root -h db -P 3306 -pchangeme" 5 | end 6 | 7 | desc 'Create database' 8 | task :create do 9 | sh 'docker-compose run --rm peatio bundle exec rake db:create' 10 | sh 'docker-compose run --rm barong bundle exec rake db:create' 11 | end 12 | 13 | desc 'Load database dump' 14 | task :load => :create do 15 | sh %Q{cat data/mysql/peatio_production.sql | docker-compose run --rm db #{mysql_cli} peatio_production} 16 | sh %Q{cat data/mysql/barong_production.sql | docker-compose run --rm db #{mysql_cli} barong_production} 17 | sh 'docker-compose run --rm peatio bundle exec rake db:migrate' 18 | sh 'docker-compose run --rm barong bundle exec rake db:migrate' 19 | end 20 | 21 | desc 'Drop all databases' 22 | task :drop do 23 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE peatio_production'") 24 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE barong_production'") 25 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE superset'") 26 | end 27 | 28 | desc 'Database Console' 29 | task :console do 30 | sh "docker-compose run --rm db #{mysql_cli}" 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/tasks/docker.rake: -------------------------------------------------------------------------------- 1 | namespace :docker do 2 | desc 'Stop all runnning docker contrainers' 3 | task :down do 4 | sh 'docker-compose down' 5 | end 6 | 7 | desc 'Clean up all docker volumes' 8 | task :clean do 9 | sh 'docker volume prune -f' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/tasks/payload.rake: -------------------------------------------------------------------------------- 1 | require_relative '../opendax/payload' 2 | require 'faraday' 3 | 4 | namespace :payload do 5 | desc 'Generate JWT' 6 | task :send, [:service, :image, :url] do |_, args| 7 | secret = ENV['WEBHOOK_JWT_SECRET'] 8 | abort 'WEBHOOK_JWT_SECRET not set' if secret.to_s.empty? 9 | coder = Opendax::Payload.new(secret: secret) 10 | jwt = coder.generate!(service: args.service, image: args.image) 11 | url = "#{args.url}/deploy/#{jwt}" 12 | response = Faraday::Connection.new.get(url) do |request| 13 | request.options.timeout = 300 14 | end 15 | pp response.body 16 | fail unless response.status == 200 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/tasks/render.rake: -------------------------------------------------------------------------------- 1 | 2 | require_relative '../opendax/renderer' 3 | 4 | namespace :render do 5 | desc 'Render configuration and compose files and keys' 6 | task :config do 7 | renderer = Opendax::Renderer.new 8 | renderer.render_keys 9 | renderer.render 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/tasks/service.rake: -------------------------------------------------------------------------------- 1 | namespace :service do 2 | ENV['APP_DOMAIN'] = @config['app']['domain'] 3 | 4 | @switch = Proc.new do |args, start, stop| 5 | case args.command 6 | when 'start' 7 | start.call 8 | when 'stop' 9 | stop.call 10 | when 'restart' 11 | stop.call 12 | start.call 13 | else 14 | puts "unknown command #{args.command}" 15 | end 16 | end 17 | 18 | desc 'Run Traefik (reverse-proxy)' 19 | task :proxy, [:command] do |task, args| 20 | args.with_defaults(:command => 'start') 21 | 22 | def start 23 | puts '----- Starting the proxy -----' 24 | File.new('config/acme.json', File::CREAT, 0600) unless File.exist? 'config/acme.json' 25 | sh 'docker-compose up -d proxy' 26 | end 27 | 28 | def stop 29 | puts '----- Stopping the proxy -----' 30 | sh 'docker-compose rm -fs proxy' 31 | end 32 | 33 | @switch.call(args, method(:start), method(:stop)) 34 | end 35 | 36 | desc 'Run backend (vault db redis rabbitmq)' 37 | task :backend, [:command] do |task, args| 38 | args.with_defaults(:command => 'start') 39 | 40 | def start 41 | puts '----- Starting dependencies -----' 42 | sh 'docker-compose up -d vault db redis rabbitmq' 43 | sleep 7 # time for db to start, we can get connection refused without sleeping 44 | end 45 | 46 | def stop 47 | puts '----- Stopping dependencies -----' 48 | sh 'docker-compose rm -fs vault db redis rabbitmq' 49 | end 50 | 51 | 52 | @switch.call(args, method(:start), method(:stop)) 53 | end 54 | 55 | desc 'Run influxdb' 56 | task :influxdb, [:command] do |task, args| 57 | args.with_defaults(:command => 'start') 58 | 59 | def start 60 | puts '----- Starting influxdb -----' 61 | sh 'docker-compose up -d influxdb' 62 | sh 'docker-compose exec influxdb bash -c "cat peatio.sql | influx"' 63 | end 64 | 65 | def stop 66 | puts '----- Stopping influxdb -----' 67 | sh 'docker-compose rm -fs influxdb' 68 | end 69 | 70 | @switch.call(args, method(:start), method(:stop)) 71 | end 72 | 73 | desc '[Optional] Run arke-maker' 74 | task :arke_maker, [:command] do |task, args| 75 | args.with_defaults(:command => 'start') 76 | 77 | def start 78 | puts '----- Starting arke -----' 79 | sh 'docker-compose up -d arke-maker' 80 | end 81 | 82 | def stop 83 | puts '----- Stopping arke -----' 84 | sh 'docker-compose rm -fs arke-maker' 85 | end 86 | 87 | @switch.call(args, method(:start), method(:stop)) 88 | end 89 | 90 | desc '[Optional] Run daemons (rango, peatio daemons, barong sidekiq)' 91 | task :daemons, [:command] do |_task, args| 92 | @daemons = %w[rango blockchain cron_job upstream deposit deposit_coin_address withdraw_coin influx_writer barong_sidekiq] 93 | 94 | if @config['finex']['enabled'] 95 | @daemons |= %w[finex-engine finex-api] 96 | else 97 | @daemons |= %w[matching order_processor trade_executor] 98 | end 99 | 100 | args.with_defaults(:command => 'start') 101 | 102 | def start 103 | puts '----- Starting daemons -----' 104 | sh "docker-compose up -d #{@daemons.join(' ')}" 105 | end 106 | 107 | def stop 108 | puts '----- Stopping daemons -----' 109 | sh "docker-compose rm -fs #{@daemons.join(' ')}" 110 | end 111 | 112 | @switch.call(args, method(:start), method(:stop)) 113 | end 114 | 115 | desc '[Optional] Run cryptonodes' 116 | task :cryptonodes, [:command] do |task, args| 117 | args.with_defaults(:command => 'start') 118 | 119 | def start 120 | puts '----- Starting cryptonodes -----' 121 | sh 'docker-compose up -d parity' 122 | if @config['bitcoind']['enabled'] 123 | sh 'docker-compose up -d bitcoind' 124 | end 125 | end 126 | 127 | def stop 128 | puts '----- Stopping cryptonodes -----' 129 | sh 'docker-compose rm -fs parity' 130 | if @config['bitcoind']['enabled'] 131 | sh 'docker-compose rm -fs bitcoind' 132 | end 133 | end 134 | 135 | @switch.call(args, method(:start), method(:stop)) 136 | end 137 | 138 | desc 'Run setup hooks for peatio, barong' 139 | task :setup, [:command] => ['vault:setup', 'vault:load_policies'] do |task, args| 140 | if args.command != 'stop' 141 | Rake::Task["render:config"].execute 142 | puts '----- Running hooks -----' 143 | sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:create db:migrate"' 144 | sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:seed"' 145 | sh 'docker-compose run --rm barong bash -c "./bin/init_config && bundle exec rake db:create db:migrate"' 146 | sh 'docker-compose run --rm barong bash -c "./bin/link_config && bundle exec rake db:seed"' 147 | end 148 | end 149 | 150 | desc 'Run mikro app (barong, peatio)' 151 | task :app, [:command] => [:backend, :setup] do |task, args| 152 | args.with_defaults(:command => 'start') 153 | 154 | def start 155 | puts '----- Starting app -----' 156 | sh 'docker-compose up -d peatio barong gateway' 157 | end 158 | 159 | def stop 160 | puts '----- Stopping app -----' 161 | sh 'docker-compose rm -fs peatio barong gateway' 162 | end 163 | 164 | @switch.call(args, method(:start), method(:stop)) 165 | end 166 | 167 | desc 'Run the frontend application' 168 | task :frontend, [:command] do |task, args| 169 | args.with_defaults(:command => 'start') 170 | 171 | def start 172 | puts '----- Starting the frontend -----' 173 | sh 'docker-compose up -d frontend' 174 | end 175 | 176 | def stop 177 | puts '----- Stopping the frontend -----' 178 | sh 'docker-compose rm -fs frontend' 179 | end 180 | 181 | @switch.call(args, method(:start), method(:stop)) 182 | end 183 | 184 | desc 'Run the tower application' 185 | task :tower, [:command] do |task, args| 186 | args.with_defaults(:command => 'start') 187 | 188 | def start 189 | puts '----- Starting the tower -----' 190 | sh 'docker-compose up -d tower' 191 | end 192 | 193 | def stop 194 | puts '----- Stopping the tower -----' 195 | sh 'docker-compose rm -fs tower' 196 | end 197 | 198 | @switch.call(args, method(:start), method(:stop)) 199 | end 200 | 201 | desc '[Optional] Run utils (mailer)' 202 | task :utils, [:command] do |task, args| 203 | args.with_defaults(:command => 'start') 204 | 205 | def start 206 | puts '----- Starting utils -----' 207 | sh 'docker-compose up -d mailer' 208 | end 209 | 210 | def stop 211 | puts '----- Stopping Utils -----' 212 | sh 'docker-compose rm -fs mailer' 213 | end 214 | 215 | @switch.call(args, method(:start), method(:stop)) 216 | end 217 | 218 | desc '[Optional] Run monitoring' 219 | task :monitoring, [:command] do |task, args| 220 | args.with_defaults(:command => 'start') 221 | 222 | def start 223 | puts '----- Starting monitoring -----' 224 | sh 'docker-compose up -d node_exporter' 225 | sh 'docker-compose up -d cadvisor' 226 | end 227 | 228 | def stop 229 | puts '----- Stopping monitoring -----' 230 | sh 'docker-compose rm -fs node_exporter' 231 | sh 'docker-compose rm -fs cadvisor' 232 | end 233 | 234 | @switch.call(args, method(:start), method(:stop)) 235 | end 236 | 237 | desc '[Optional] Run superset' 238 | task :superset, [:command] do |task, args| 239 | args.with_defaults(:command => 'start') 240 | 241 | def start 242 | conf = @utils['superset'] 243 | init_params = [ 244 | '--app', 'superset', 245 | '--firstname', 'Admin', 246 | '--lastname', 'Superset', 247 | '--username', conf['username'], 248 | '--email', conf['email'], 249 | '--password', conf['password'] 250 | ].join(' ') 251 | 252 | puts '----- Initializing Superset -----' 253 | sh [ 254 | 'docker-compose run --rm superset', 255 | 'sh -c "', 256 | "fabmanager create-admin #{init_params}", 257 | '&& superset db upgrade', 258 | '&& superset init"' 259 | ].join(' ') 260 | 261 | puts '----- Starting Superset -----' 262 | sh 'docker-compose up -d superset' 263 | end 264 | 265 | def stop 266 | puts '----- Stopping Superset -----' 267 | sh 'docker-compose rm -fs superset' 268 | end 269 | 270 | @switch.call(args, method(:start), method(:stop)) 271 | end 272 | desc 'Set up and start all services with dependencies (does not run optional ones)' 273 | task :all, [:command] => ['versions:update', 'render:config'] do |task, args| 274 | args.with_defaults(:command => 'start') 275 | 276 | def start 277 | Rake::Task["service:proxy"].invoke('start') 278 | Rake::Task["service:backend"].invoke('start') 279 | Rake::Task["service:influxdb"].invoke('start') 280 | puts 'Wait 5 second for backend' 281 | sleep(5) 282 | Rake::Task["service:setup"].invoke('start') 283 | Rake::Task["service:app"].invoke('start') 284 | Rake::Task["service:frontend"].invoke('start') 285 | Rake::Task["service:tower"].invoke('start') 286 | Rake::Task["service:utils"].invoke('start') 287 | Rake::Task["service:daemons"].invoke('start') 288 | end 289 | 290 | def stop 291 | Rake::Task["service:proxy"].invoke('stop') 292 | Rake::Task["service:backend"].invoke('stop') 293 | Rake::Task["service:influxdb"].invoke('stop') 294 | Rake::Task["service:setup"].invoke('stop') 295 | Rake::Task["service:app"].invoke('stop') 296 | Rake::Task["service:frontend"].invoke('stop') 297 | Rake::Task["service:tower"].invoke('stop') 298 | Rake::Task["service:utils"].invoke('stop') 299 | Rake::Task["service:daemons"].invoke('stop') 300 | end 301 | 302 | @switch.call(args, method(:start), method(:stop)) 303 | end 304 | end 305 | -------------------------------------------------------------------------------- /lib/tasks/terraform.rake: -------------------------------------------------------------------------------- 1 | namespace :terraform do 2 | desc 'Initialize the Terraform configuration' 3 | task :init do 4 | Dir.chdir('terraform') { sh 'terraform init' } 5 | end 6 | 7 | desc 'Apply the Terraform configuration' 8 | task :apply => ['render:config', :init] do 9 | Dir.chdir('terraform') { sh 'terraform apply' } 10 | end 11 | 12 | desc 'Destroy the Terraform infrastructure' 13 | task :destroy do 14 | Dir.chdir('terraform') { sh 'terraform destroy' } 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/tasks/toolbox.rake: -------------------------------------------------------------------------------- 1 | namespace :toolbox do 2 | desc 'Run the toolbox' 3 | task :run do 4 | run_cmd = %w[docker-compose run --rm toolbox run] 5 | 6 | YAML.safe_load(File.read('config/toolbox.yaml')) 7 | .transform_keys { |k| '--' << k } 8 | .each_pair { |k, v| run_cmd << k << v.to_s } 9 | 10 | sh *run_cmd 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/tasks/vault.rake: -------------------------------------------------------------------------------- 1 | 2 | require_relative '../opendax/vault' 3 | 4 | namespace :vault do 5 | desc 'Initialize, unseal and set secrets for Vault' 6 | task :setup do 7 | vault = Opendax::Vault.new 8 | vault_root_token = vault.setup 9 | unless vault_root_token.nil? 10 | @config["vault"]["root_token"] = vault_root_token 11 | File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) } 12 | end 13 | end 14 | 15 | task :load_policies do 16 | vault = Opendax::Vault.new 17 | vault_tokens = vault.load_policies(@config["app"]["name"], @config["vault"]["root_token"]) 18 | unless vault_tokens.empty? 19 | vault_tokens.each do |k, v| 20 | @config["vault"][k] = v 21 | File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) } 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/tasks/vendor.rake: -------------------------------------------------------------------------------- 1 | namespace :vendor do 2 | desc 'Clone the frontend apps repos into vendor/' 3 | task :clone do 4 | puts '----- Clone the frontend apps repos -----' 5 | puts 6 | @config['vendor'].each do |name, repo_url| 7 | sh "git clone #{repo_url} vendor/#{name}" 8 | puts 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/tasks/versions.rake: -------------------------------------------------------------------------------- 1 | require 'faraday' 2 | 3 | namespace :versions do 4 | desc 'Fetch global image versions and update config/app.yaml' 5 | task :update do 6 | unless @config['updateVersions'] 7 | puts "To enable version updates, set updateVersions to true" 8 | next 9 | end 10 | 11 | puts "Fetching latest global versions" 12 | response = Faraday.get 'https://raw.githubusercontent.com/openware/versions/master/opendax/2-6/versions.yaml' 13 | 14 | if response.status >= 400 || response.status >= 500 15 | raise "Error fetching global versions, got #{response.body}" 16 | end 17 | 18 | versions = YAML.load(response.body) 19 | 20 | versions.each { |k, v| update_image_tag(k, v['image']['tag']) if @config['images'].key? k } 21 | 22 | File.write(CONFIG_PATH, YAML.dump(@config)) 23 | 24 | puts 'Version update complete!' 25 | end 26 | end 27 | 28 | def update_image_tag(component, tag) 29 | image = @config['images'][component].split(':') 30 | image[-1] = tag 31 | 32 | @config['images'][component] = image.join(':') 33 | end 34 | -------------------------------------------------------------------------------- /lib/tasks/wallets.rake: -------------------------------------------------------------------------------- 1 | require 'faraday' 2 | require 'json' 3 | require 'yaml' 4 | 5 | namespace :wallet do 6 | desc 'Generate ethereum wallet from a cryptonode' 7 | task :create, [:kind,:url,:secret] do |_, args| 8 | response = Faraday::Connection.new.post(args.url) do |request| 9 | request.headers["Content-Type"] = "application/json" 10 | request.body = "{\"jsonrpc\":\"2.0\",\"method\":\"personal_newAccount\",\"params\":[\"#{args.secret}\"],\"id\":1}" 11 | request.options.timeout = 300 12 | end 13 | address = JSON.parse(response.body)['result'] 14 | puts "----- Generating a new #{args.kind} wallet -----", "Address: " + address 15 | 16 | @config['wallets']['eth'].find { |w| w['kind'] == args.kind }.update('address' => address, 'secret' => args.secret) 17 | 18 | File.open(CONFIG_PATH, 'w') {|f| f.write @config.to_yaml } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/opendax/payload_spec.rb: -------------------------------------------------------------------------------- 1 | require 'opendax/payload' 2 | 3 | describe Opendax::Payload do 4 | let(:secret) { 'myTailorIsRich42' } 5 | let(:encoder) { Opendax::Payload.new(secret: secret) } 6 | let(:valid_decoder) { encoder } 7 | let(:invalid_decoder) { Opendax::Payload.new(secret: 'randomSecret') } 8 | let(:service) { 'barong' } 9 | let(:image) { 'rubykube/barong:2.0.8-alpha' } 10 | let(:jwt) { encoder.generate!(service: service, image: image) } 11 | 12 | it 'should encode a JWT HMAC' do 13 | token = encoder.generate!(service: service, image: image) 14 | 15 | expect(token).not_to be_nil 16 | expect(token).to match /[A-Za-z0-9\-\._~\+\/]+=*/ 17 | end 18 | 19 | it 'should decode a token with valid secret' do 20 | decoded = valid_decoder.safe_decode(jwt) 21 | 22 | expect(decoded).not_to be_nil 23 | expect(decoded['service']).to eq service 24 | expect(decoded['image']).to eq image 25 | end 26 | 27 | it 'should not decode a token with invalid secret' do 28 | decoded = invalid_decoder.safe_decode(jwt) 29 | 30 | expect(decoded).to be_nil 31 | end 32 | 33 | it 'defines an API' do 34 | pgen = Opendax::Payload.new(secret: '0x42', expire: 600) 35 | token = pgen.generate!(service: service, image: image) 36 | pgen.decode!(token) 37 | pgen.safe_decode(token) 38 | end 39 | 40 | it 'expire time should be configurable' do 41 | exp_time = 4200 42 | exp_coder = Opendax::Payload.new(secret: 'ab', expire: exp_time) 43 | encoded = exp_coder.generate!(service: service, image: image) 44 | decoded = exp_coder.decode!(encoded) 45 | computed_exp = decoded['exp'] - decoded['iat'] 46 | 47 | expect(computed_exp).to eq exp_time 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/opendax/renderer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'opendax/renderer' 2 | 3 | describe Opendax::Renderer do 4 | let(:renderer) { Opendax::Renderer.new } 5 | let(:fake_erb_result) { { 'data' => 'this is fake data'} } 6 | let(:config) do 7 | { 8 | 'app' => { 9 | 'name' => 'Opendax', 10 | 'domain' => 'app.test' 11 | }, 12 | 'render_protect' => false, 13 | 'ssl' => { 14 | 'enabled' => 'true', 15 | 'email' => 'support@example.com' 16 | }, 17 | 'images' => { 18 | 'peatio' => 'rubykube/peatio:latest', 19 | 'barong' => 'rubykube/barong:latest', 20 | 'frontend' => 'rubykube/mikroapp:latest', 21 | 'tower' => 'rubykube/tower:latest' 22 | }, 23 | 'vendor' => { 24 | 'frontend' => 'https://github.com/rubykube/mikroapp.git' 25 | } 26 | } 27 | end 28 | 29 | it 'should load configuration' do 30 | allow(YAML).to receive(:load_file).and_return(config) 31 | expect(renderer.config).to eq(config) 32 | end 33 | 34 | describe '.config' do 35 | it 'should load configuration' do 36 | allow(YAML).to receive(:load_file).and_return(config) 37 | expect(renderer.config).to eq(config) 38 | end 39 | end 40 | 41 | describe '.generate_key' do 42 | it 'should generate a private RSA key by default' do 43 | renderer.generate_key('config/secrets/barong.key') 44 | expect(File).to exist('config/secrets/barong.key') 45 | end 46 | 47 | it 'should generate a public RSA key in addition when the flag is passed' do 48 | renderer.generate_key('config/secrets/app.key', public: true) 49 | expect(File).to exist('config/secrets/app.key') 50 | expect(File).to exist('config/secrets/app.key.pub') 51 | end 52 | end 53 | 54 | describe '.render_keys' do 55 | it 'should create files with private and public RSA keys' do 56 | renderer.render_keys 57 | expect(File).to exist('config/secrets/barong.key') 58 | expect(File).to exist('config/secrets/app.key') 59 | expect(File).to exist('config/secrets/app.key.pub') 60 | end 61 | end 62 | 63 | describe '.render_file' do 64 | it 'should render file' do 65 | expect(ERB).to receive(:new).once.and_call_original 66 | expect_any_instance_of(ERB).to receive(:result).once.and_return(fake_erb_result) 67 | expect(File).to receive(:write).with('./config/peatio.env', fake_erb_result).once.and_call_original 68 | 69 | renderer.render_file('./templates/config/peatio.env.erb', './config/peatio.env') 70 | end 71 | end 72 | 73 | describe '.template_name' do 74 | it 'should exclude "templates" directory' do 75 | file_name = renderer.template_name('./templates/config/peatio.env.erb') 76 | expect(file_name).not_to start_with('./templates') 77 | end 78 | 79 | it 'should return relative path to file' do 80 | file_name = renderer.template_name('./templates/compose/app.yaml.erb') 81 | expect(file_name).to start_with('.') 82 | end 83 | end 84 | 85 | let(:renderer) { Opendax::Renderer.new } 86 | 87 | describe '.render' do 88 | it 'should call exact amount of helper functions' do 89 | number_of_files = Dir.glob('./templates/**/*.erb', File::FNM_DOTMATCH).length 90 | expect(renderer).to receive(:render_file).exactly(number_of_files).times 91 | 92 | renderer.render 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/opendax/server_spec.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/spec/opendax/server_spec.rb -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 16 | RSpec.configure do |config| 17 | # rspec-expectations config goes here. You can use an alternate 18 | # assertion/expectation library such as wrong or the stdlib/minitest 19 | # assertions if you prefer. 20 | config.expect_with :rspec do |expectations| 21 | # This option will default to `true` in RSpec 4. It makes the `description` 22 | # and `failure_message` of custom matchers include text for helper methods 23 | # defined using `chain`, e.g.: 24 | # be_bigger_than(2).and_smaller_than(4).description 25 | # # => "be bigger than 2 and smaller than 4" 26 | # ...rather than: 27 | # # => "be bigger than 2" 28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 29 | end 30 | 31 | # rspec-mocks config goes here. You can use an alternate test double 32 | # library (such as bogus or mocha) by changing the `mock_with` option here. 33 | config.mock_with :rspec do |mocks| 34 | # Prevents you from mocking or stubbing a method that does not exist on 35 | # a real object. This is generally recommended, and will default to 36 | # `true` in RSpec 4. 37 | mocks.verify_partial_doubles = true 38 | end 39 | 40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 41 | # have no way to turn it off -- the option exists only for backwards 42 | # compatibility in RSpec 3). It causes shared context metadata to be 43 | # inherited by the metadata hash of host groups and examples, rather than 44 | # triggering implicit auto-inclusion in groups with matching metadata. 45 | config.shared_context_metadata_behavior = :apply_to_host_groups 46 | 47 | # The settings below are suggested to provide a good initial experience 48 | # with RSpec, but feel free to customize to your heart's content. 49 | =begin 50 | # This allows you to limit a spec run to individual examples or groups 51 | # you care about by tagging them with `:focus` metadata. When nothing 52 | # is tagged with `:focus`, all examples get run. RSpec also provides 53 | # aliases for `it`, `describe`, and `context` that include `:focus` 54 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 55 | config.filter_run_when_matching :focus 56 | 57 | # Allows RSpec to persist some state between runs in order to support 58 | # the `--only-failures` and `--next-failure` CLI options. We recommend 59 | # you configure your source control system to ignore this file. 60 | config.example_status_persistence_file_path = "spec/examples.txt" 61 | 62 | # Limits the available syntax to the non-monkey patched syntax that is 63 | # recommended. For more details, see: 64 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 65 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 66 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 67 | config.disable_monkey_patching! 68 | 69 | # This setting enables warnings. It's recommended, but in some cases may 70 | # be too noisy due to issues in dependencies. 71 | config.warnings = true 72 | 73 | # Many RSpec users commonly either run the entire suite or an individual 74 | # file, and it's useful to allow more verbose output when running an 75 | # individual spec file. 76 | if config.files_to_run.one? 77 | # Use the documentation formatter for detailed output, 78 | # unless a formatter has already been configured 79 | # (e.g. via a command-line flag). 80 | config.default_formatter = "doc" 81 | end 82 | 83 | # Print the 10 slowest examples and example groups at the 84 | # end of the spec run, to help surface which specs are running 85 | # particularly slow. 86 | config.profile_examples = 10 87 | 88 | # Run specs in random order to surface order dependencies. If you find an 89 | # order dependency and want to debug it, you can fix the order by providing 90 | # the seed, which is printed after each run. 91 | # --seed 1234 92 | config.order = :random 93 | 94 | # Seed global randomization in this process using the `--seed` CLI option. 95 | # Setting this allows you to use `--seed` to deterministically reproduce 96 | # test failures related to randomization by passing the same `--seed` value 97 | # as the one that triggered the failure. 98 | Kernel.srand config.seed 99 | =end 100 | end 101 | -------------------------------------------------------------------------------- /templates/.env.erb: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=<%= @config['app']['name'].downcase %> 2 | COMPOSE_FILE=compose/app.yaml:compose/backend.yaml:compose/gateway.yaml:compose/proxy.yaml:compose/daemons.yaml:compose/frontend.yaml:compose/cryptonodes.yaml:compose/arke.yaml:compose/superset.yaml:compose/monitoring.yaml 3 | PEATIO_RAILS_VAULT_TOKEN=<%= @config['vault']['peatio_rails_token'] %> 4 | PEATIO_CRYPTO_VAULT_TOKEN=<%= @config['vault']['peatio_crypto_token'] %> 5 | PEATIO_UPSTREAM_VAULT_TOKEN=<%= @config['vault']['peatio_upstream_token'] %> 6 | PEATIO_MATCHING_VAULT_TOKEN=<%= @config['vault']['peatio_matching_token'] %> 7 | -------------------------------------------------------------------------------- /templates/compose/app.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | peatio: 5 | restart: always 6 | image: "<%= @config['images']['peatio'] %>" 7 | environment: 8 | - VAULT_TOKEN=${PEATIO_RAILS_VAULT_TOKEN} 9 | env_file: 10 | - ../config/peatio.env 11 | expose: 12 | - "8000" 13 | volumes: 14 | - ../config/peatio/seed:/opt/peatio/config/seed 15 | - ../config/peatio/management_api_v1.yml:/opt/peatio/config/management_api_v1.yml 16 | - ../config/peatio/plugins.yml:/opt/peatio/config/plugins.yml 17 | - ../config/peatio/abilities.yml:/opt/peatio/config/abilities.yml 18 | labels: {} 19 | command: bash -c "bin/link_config && bundle exec puma --config config/puma.rb" 20 | 21 | barong: 22 | restart: always 23 | image: "<%= @config['images']['barong'] %>" 24 | env_file: 25 | - ../config/barong.env 26 | volumes: 27 | - ../config/secrets:/secrets:ro 28 | - ../config/barong/seeds.yml:/home/app/config/seeds.yml 29 | - ../config/barong/barong.yml:/home/app/config/barong.yml 30 | - ../config/barong/authz_rules.yml:/home/app/config/authz_rules.yml 31 | - ../config/barong/management_api.yml:/home/app/config/management_api.yml 32 | - ../config/barong/abilities.yml:/home/app/config/abilities.yml 33 | 34 | <% if @config['finex']['enabled'] %> 35 | finex-api: 36 | restart: always 37 | image: "<%= @config['finex']['image'] %>" 38 | command: "./orderapi" 39 | volumes: 40 | - ../config/finex:/app/config:ro 41 | 42 | finex-engine: 43 | restart: always 44 | image: "<%= @config['finex']['image'] %>" 45 | command: "./finex" 46 | volumes: 47 | - ../config/finex:/app/config:ro 48 | <% end %> 49 | 50 | applogic: 51 | restart: always 52 | image: "<%= @utils['images']['applogic'] %>" 53 | env_file: 54 | - ../config/applogic.env 55 | expose: 56 | - "8081" 57 | volumes: 58 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml 59 | -------------------------------------------------------------------------------- /templates/compose/arke.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | arke-maker: 5 | restart: always 6 | image: "<%= @utils['images']['arke'] %>" 7 | env_file: 8 | - ../config/arke.env 9 | volumes: 10 | - ../config/arke/strategies.yml:/home/app/config/strategies.yml 11 | command: bundle exec ./bin/arke start 12 | -------------------------------------------------------------------------------- /templates/compose/backend.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | db: 5 | restart: always 6 | <%- if @config['database']['adapter'] == 'mysql' %> 7 | image: mysql:5.7 8 | volumes: 9 | - db_data:/var/lib/mysql 10 | - ../config/mysql:/etc/mysql/conf.d 11 | environment: 12 | MYSQL_ROOT_PASSWORD: <%= @config['database']['password'] %> 13 | <%- elsif @config['database']['adapter'] == 'postgresql' %> 14 | image: postgres:13 15 | volumes: 16 | - db_data:/var/lib/postgresql/data 17 | environment: 18 | POSTGRES_USER: <%= @config['database']['user'] %> 19 | POSTGRES_PASSWORD: <%= @config['database']['password'] %> 20 | <%- end %> 21 | 22 | influxdb: 23 | image: influxdb:1.7.10 24 | restart: always 25 | volumes: 26 | - influx_data:/var/lib/influxdb 27 | - ../config/influxdb/build_candles.sql:/build_candles.sql 28 | - ../config/influxdb/arke.sql:/arke.sql 29 | - ../config/influxdb/peatio.sql:/peatio.sql 30 | - ../config/arke/historical_data:/data/historical_data 31 | environment: 32 | INFLUXDB_ADMIN_ENABLED: "true" 33 | 34 | redis: 35 | image: redis:4.0.10 36 | restart: always 37 | volumes: 38 | - redis_data:/data 39 | 40 | rabbitmq: 41 | image: rabbitmq:3.7.6-management 42 | restart: always 43 | volumes: 44 | - rabbitmq_data:/var/lib/rabbitmq 45 | 46 | vault: 47 | image: vault:1.3.0 48 | restart: always 49 | volumes: 50 | - vault_data:/vault 51 | - ../config/vault:/tmp/policies 52 | command: 53 | - server 54 | cap_add: 55 | - IPC_LOCK 56 | environment: 57 | VAULT_LOCAL_CONFIG: '{"storage": {"file": { "path": "/vault/data" }}, "listener": {"tcp":{"address": "0.0.0.0:8200","tls_disable":"1"}}}' 58 | VAULT_ADDR: http://vault:8200 59 | 60 | volumes: 61 | db_data: 62 | rabbitmq_data: 63 | redis_data: 64 | vault_data: 65 | influx_data: 66 | -------------------------------------------------------------------------------- /templates/compose/cryptonodes.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | parity: 5 | image: parity/parity:v2.7.2-stable 6 | restart: always 7 | command: | 8 | --chain=kovan 9 | --mode=active 10 | --interface=all 11 | --warp=true 12 | --snapshot-peers=10 13 | --min-peers=5 14 | --max-peers=10 15 | --jsonrpc-interface=0.0.0.0 16 | --jsonrpc-cors=all 17 | --jsonrpc-hosts=all 18 | --jsonrpc-apis=all 19 | --db-compaction=ssd 20 | --no-persistent-txqueue 21 | volumes: 22 | - ../data/parity:/home/parity/.local/share/io.parity.ethereum 23 | ports: 24 | - "127.0.0.1:8545:8545" 25 | 26 | bitcoind: 27 | image: quay.io/openware/bitcoind:0.19.1 28 | restart: always 29 | user: root 30 | command: bitcoind 31 | volumes: 32 | - ../data/bitcoin:/bitcoin 33 | - ../config/bitcoin.conf:/bitcoin/.bitcoin/bitcoin.conf 34 | 35 | litecoind: 36 | image: quay.io/openware/litecoind:0.16.3 37 | restart: always 38 | volumes: 39 | - ../data/litecoin:/litecoin 40 | - ../config/litecoin.conf:/litecoin/litecoin.conf 41 | -------------------------------------------------------------------------------- /templates/compose/daemons.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | x-daemon: &peatio-daemon 4 | image: "<%= @config['images']['peatio'] %>" 5 | restart: always 6 | env_file: 7 | - ../config/peatio.env 8 | volumes: 9 | - ../config/peatio:/opt/peatio/config:ro 10 | 11 | services: 12 | blockchain: 13 | << : *peatio-daemon 14 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb blockchain" 15 | 16 | cron_job: 17 | << : *peatio-daemon 18 | environment: 19 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN} 20 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb cron_job" 21 | 22 | deposit: 23 | << : *peatio-daemon 24 | environment: 25 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN} 26 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb deposit" 27 | 28 | upstream: 29 | << : *peatio-daemon 30 | environment: 31 | - VAULT_TOKEN=${PEATIO_UPSTREAM_VAULT_TOKEN} 32 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb upstream" 33 | 34 | deposit_coin_address: 35 | << : *peatio-daemon 36 | environment: 37 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN} 38 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb deposit_coin_address" 39 | 40 | withdraw_coin: 41 | << : *peatio-daemon 42 | environment: 43 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN} 44 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb withdraw_coin" 45 | 46 | influx_writer: 47 | << : *peatio-daemon 48 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb influx_writer" 49 | 50 | rango: 51 | restart: always 52 | image: "<%= @config['images']['rango'] %>" 53 | env_file: 54 | - ../config/rango.env 55 | 56 | <% unless @config['finex']['enabled'] %> 57 | matching: 58 | << : *peatio-daemon 59 | environment: 60 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN} 61 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb matching" 62 | 63 | order_processor: 64 | << : *peatio-daemon 65 | environment: 66 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN} 67 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb order_processor" 68 | 69 | trade_executor: 70 | << : *peatio-daemon 71 | environment: 72 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN} 73 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb trade_executor" 74 | <% end %> 75 | 76 | mailer: 77 | restart: always 78 | image: "<%= @config['images']['barong'] %>" 79 | env_file: 80 | - ../config/barong.env 81 | volumes: 82 | - ../config/secrets:/secrets:ro 83 | - ../config/mailer/templates:/home/app/app/views/postmaster 84 | - ../config/mailer.yml:/home/app/config/mailer.yml 85 | command: bash -c "bin/mailer run" 86 | 87 | applogic_sidekiq: 88 | restart: always 89 | image: "<%= @utils['images']['applogic'] %>" 90 | env_file: 91 | - ../config/barong.env 92 | volumes: 93 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml 94 | - ../config/applogic/schedule.yml:/home/app/config/schedule.yml 95 | command: bash -c "bundle exec sidekiq" 96 | 97 | barong_sidekiq: 98 | restart: always 99 | image: "<%= @config['images']['barong'] %>" 100 | env_file: 101 | - ../config/barong.env 102 | volumes: 103 | - ../config/secrets:/secrets:ro 104 | - ../config/barong/seeds.yml:/home/app/config/seeds.yml 105 | - ../config/barong/barong.yml:/home/app/config/barong.yml 106 | - ../config/barong/authz_rules.yml:/home/app/config/authz_rules.yml 107 | - ../config/barong/management_api.yml:/home/app/config/management_api.yml 108 | command: bash -c "bundle exec sidekiq" 109 | 110 | listener: 111 | restart: always 112 | image: "<%= @utils['images']['applogic'] %>" 113 | env_file: 114 | - ../config/applogic.env 115 | volumes: 116 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml 117 | command: bash -c "bundle exec rake event_api_listener" 118 | -------------------------------------------------------------------------------- /templates/compose/frontend.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | frontend: 5 | restart: always 6 | image: "<%= @config['images']['frontend'] %>" 7 | volumes: 8 | - ../config/frontend/env.js:/usr/share/nginx/html/config/env.js 9 | labels: 10 | - "traefik.http.routers.frontend-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/`)" 11 | - "traefik.enable=true" 12 | - "traefik.http.services.frontend-<%= @name %>.loadbalancer.server.port=3000" 13 | <%- if @config['ssl']['enabled'] -%> 14 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=websecure" 15 | - "traefik.http.routers.frontend-<%= @name %>.tls=true" 16 | - "traefik.http.routers.frontend-<%= @name %>.tls.certresolver=myresolver" 17 | <%- else -%> 18 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=web" 19 | <%- end -%> 20 | 21 | tower: 22 | restart: always 23 | image: "<%= @config['images']['tower'] %>" 24 | volumes: 25 | - ../config/frontend/tower.js:/home/app/env.js 26 | labels: 27 | - "traefik.http.routers.tower-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/tower`)" 28 | - "traefik.enable=true" 29 | - "traefik.http.services.tower-<%= @name %>.loadbalancer.server.port=8080" 30 | <%- if @config['ssl']['enabled'] -%> 31 | - "traefik.http.routers.tower-<%= @name %>.entrypoints=websecure" 32 | - "traefik.http.routers.tower-<%= @name %>.tls=true" 33 | - "traefik.http.routers.tower-<%= @name %>.tls.certresolver=myresolver" 34 | <%- else -%> 35 | - "traefik.http.routers.tower-<%= @name %>.entrypoints=web" 36 | <%- end -%> 37 | -------------------------------------------------------------------------------- /templates/compose/gateway.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | gateway: 5 | restart: always 6 | image: envoyproxy/envoy:v1.10.0 7 | volumes: 8 | - ../config/gateway:/etc/envoy/ 9 | command: /usr/local/bin/envoy -l info -c /etc/envoy/envoy.yaml 10 | labels: 11 | - "traefik.http.routers.gateway-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/api`,`/admin`,`/assets/`)" 12 | - "traefik.enable=true" 13 | - "traefik.http.services.gateway-<%= @name %>.loadbalancer.server.port=8099" 14 | <%- if @config['ssl']['enabled'] -%> 15 | - "traefik.http.routers.gateway-<%= @name %>.entrypoints=websecure" 16 | - "traefik.http.routers.gateway-<%= @name %>.tls=true" 17 | - "traefik.http.routers.gateway-<%= @name %>.tls.certresolver=myresolver" 18 | <%- else -%> 19 | - "traefik.http.routers.gateway-<%= @name %>.entrypoints=web" 20 | <%- end -%> 21 | -------------------------------------------------------------------------------- /templates/compose/monitoring.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | node_exporter: 5 | image: prom/node-exporter:v0.18.1 6 | container_name: node_exporter 7 | volumes: 8 | - /proc:/host/proc:ro 9 | - /sys:/host/sys:ro 10 | - /:/rootfs:ro 11 | command: 12 | - '--path.procfs=/host/proc' 13 | - '--path.rootfs=/rootfs' 14 | - '--path.sysfs=/host/sys' 15 | - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)' 16 | ports: 17 | - 9100:9100 18 | 19 | cadvisor: 20 | image: gcr.io/google-containers/cadvisor:v0.34.0 21 | container_name: cadvisor 22 | volumes: 23 | - /var/run:/var/run:rw 24 | - /var/lib/docker/:/var/lib/docker:ro 25 | - /:/rootfs:ro 26 | - /sys:/sys:ro 27 | ports: 28 | - 8080:8080 29 | -------------------------------------------------------------------------------- /templates/compose/proxy.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | proxy: 5 | restart: always 6 | image: traefik:2.1.8 7 | ports: 8 | - "80:80" 9 | - "443:443" 10 | volumes: 11 | - /var/run/docker.sock:/var/run/docker.sock 12 | <%- if @config['ssl']['enabled'] -%> 13 | - ../config/acme.json:/acme.json 14 | <%- end -%> 15 | command: 16 | - "--log.level=DEBUG" 17 | - "--api.insecure=true" 18 | - "--providers.docker=true" 19 | - "--providers.docker.exposedbydefault=false" 20 | - "--entryPoints.web.address=:80" 21 | - "--entryPoints.web.forwardedHeaders.insecure" 22 | <%- if @config['ssl']['enabled'] -%> 23 | - "--entryPoints.websecure.address=:443" 24 | - "--entryPoints.websecure.forwardedHeaders.insecure" 25 | - "--certificatesresolvers.myresolver.acme.httpchallenge=true" 26 | - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" 27 | - "--certificatesresolvers.myresolver.acme.email=<%= @config['ssl']['email'] %>" 28 | - "--certificatesresolvers.myresolver.acme.storage=/acme.json" 29 | labels: 30 | - "traefik.enable=true" 31 | - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:[a-z-.]+}`)" 32 | - "traefik.http.routers.http-catchall.entrypoints=web" 33 | - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" 34 | - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" 35 | - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true" 36 | <%- end -%> 37 | -------------------------------------------------------------------------------- /templates/compose/superset.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | superset: 5 | image: "<%= @utils['images']['superset'] %>" 6 | restart: always 7 | volumes: 8 | - superset_db:/var/lib/superset 9 | labels: 10 | - "traefik.http.routers.superset-<%= @name %>.rule=Host(`superset.<%= @config['app']['domain'] %>`)" 11 | - "traefik.http.services.superset-<%= @name %>.loadbalancer.server.port=8088" 12 | - "traefik.enable=true" 13 | <%- if @config['ssl']['enabled'] -%> 14 | - "traefik.http.routers.superset-<%= @name %>.entrypoints=websecure" 15 | <%- else -%> 16 | - "traefik.http.routers.superset-<%= @name %>.entrypoints=web" 17 | <%- end -%> 18 | 19 | volumes: 20 | superset_db: 21 | -------------------------------------------------------------------------------- /templates/compose/vendor.yaml.erb: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | frontend: 5 | image: node:11 6 | restart: always 7 | user: "${UID}:${GID}" 8 | volumes: 9 | - ../vendor/frontend:/home/node 10 | command: 11 | - sh 12 | - -c 13 | - | 14 | cd /home/node 15 | yarn 16 | yarn start 17 | labels: 18 | - "traefik.http.routers.frontend-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/`)" 19 | - "traefik.http.services.frontend-<%= @name %>.loadbalancer.server.port=3000" 20 | - "traefik.enable=true" 21 | <%- if @config['ssl']['enabled'] -%> 22 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=websecure" 23 | - "traefik.http.routers.frontend-<%= @name %>.tls=true" 24 | - "traefik.http.routers.frontend-<%= @name %>.tls.certresolver=myresolver" 25 | <%- else -%> 26 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=web" 27 | <%- end -%> 28 | -------------------------------------------------------------------------------- /templates/config/applogic.env.erb: -------------------------------------------------------------------------------- 1 | RAILS_ENV=production 2 | RAILS_ROOT=/home/app 3 | 4 | BARONG_URL=http://barong:8001 5 | PEATIO_URL=http://peatio:8000 6 | REDIS_URL=redis://redis:6379 7 | 8 | PORT=8081 9 | DATABASE_HOST=db 10 | DATABASE_USER=root 11 | DATABASE_PASSWORD=changeme 12 | 13 | EVENT_API_RABBITMQ_HOST=rabbitmq 14 | EVENT_API_RABBITMQ_PORT=5672 15 | EVENT_API_RABBITMQ_USERNAME=guest 16 | EVENT_API_RABBITMQ_PASSWORD=guest 17 | 18 | BARONG_EVENT_API_JWT_PUBLIC_KEY=<%= @barong_public_key %> 19 | BARONG_EVENT_API_JWT_ALGORITHM=RS256 20 | 21 | EVENT_API_APPLICATION=barong 22 | EVENT_API_EVENT_CATEGORY=model 23 | EVENT_API_EVENT_NAME=profile.created 24 | 25 | JWT_PUBLIC_KEY=<%= @barong_public_key %> 26 | JWT_PRIVATE_KEY=<%= @applogic_private_key %> 27 | 28 | RAILS_LOG_TO_STDOUT=true 29 | SECRET_KEY_BASE=b609ebad4856c8f8a4f465fa785c74fb 30 | -------------------------------------------------------------------------------- /templates/config/applogic/management_api_v2.yml.erb: -------------------------------------------------------------------------------- 1 | barong: 2 | keychain: 3 | applogic: 4 | algorithm: RS256 5 | value: <%= @applogic_private_key %> 6 | 7 | jwt: {} 8 | 9 | actions: 10 | read_users: 11 | required_signatures: ['applogic'] 12 | requires_barong_totp: false 13 | 14 | peatio: 15 | keychain: 16 | applogic: 17 | algorithm: RS256 18 | value: <%= @applogic_private_key %> 19 | 20 | jwt: {} 21 | 22 | actions: 23 | read_operations: 24 | required_signatures: ['applogic'] 25 | requires_barong_totp: false 26 | -------------------------------------------------------------------------------- /templates/config/applogic/schedule.yml.erb: -------------------------------------------------------------------------------- 1 | users_sync_job: 2 | cron: "0 0 * * *" # it will retrieve data every 1 day 3 | class: "UsersSyncWorker" 4 | args: 5 | period: '1' 6 | action: 'sync' # you also can start a new job with action 'reg' to pull new users 7 | -------------------------------------------------------------------------------- /templates/config/arke.env.erb: -------------------------------------------------------------------------------- 1 | PORT=8081 2 | 3 | LOG_LEVEL=debug 4 | 5 | DISABLE_SPRING=true 6 | 7 | RAILS_ENV=production 8 | 9 | SECRET_KEY_BASE=64 10 | 11 | INFLUXDB_HOST=influxdb 12 | 13 | RABBITMQ_HOST=rabbitmq 14 | -------------------------------------------------------------------------------- /templates/config/arke/strategies.yml.erb: -------------------------------------------------------------------------------- 1 | <%= @utils['arke'].to_yaml %> 2 | -------------------------------------------------------------------------------- /templates/config/barong.env.erb: -------------------------------------------------------------------------------- 1 | PORT=8001 2 | 3 | LOG_LEVEL=warn 4 | 5 | DISABLE_SPRING=true 6 | 7 | RAILS_ENV=production 8 | 9 | SECRET_KEY_BASE=64 10 | 11 | <%- if @config['database']['adapter'] == 'postgresql' %> 12 | DATABASE_COLLATION="" 13 | DATABASE_ADAPTER="postgresql" 14 | <%- elsif @config['database']['adapter'] == 'mysql' %> 15 | DATABASE_ADAPTER="mysql2" 16 | <%- end %> 17 | DATABASE_HOST=<%= @config['database']['host'] %> 18 | DATABASE_PORT=<%= @config['database']['port'] %> 19 | DATABASE_USER=<%= @config['database']['user'] %> 20 | DATABASE_PASS=<%= @config['database']['password'] %> 21 | 22 | <%- if @config['twilio']['enabled'] -%> 23 | BARONG_PHONE_VERIFICATION=twilio_sms 24 | BARONG_TWILIO_PHONE_NUMBER=<%= @config['twilio']['phone_number'] %> 25 | BARONG_TWILIO_ACCOUNT_SID=<%= @config['twilio']['account_sid'] %> 26 | BARONG_TWILIO_AUTH_TOKEN=<%= @config['twilio']['auth_token'] %> 27 | <%- end -%> 28 | 29 | BARONG_KYC_PROVIDER=<%= @config['kyc']['provider'] %> 30 | 31 | <%- if @config['kyc']['provider'] == 'kycaid' -%> 32 | BARONG_KYCAID_AUTHORIZATION_TOKEN=<%= @config['kyc']['authorization_token'] %> 33 | BARONG_KYCAID_SANDBOX_MODE=<%= @config['kyc']['sandbox_mode'] %> 34 | BARONG_KYCAID_API_ENDPOINT=<%= @config['kyc']['api_endpoint'] %> 35 | <%- end -%> 36 | 37 | BARONG_STORAGE_PROVIDER=<%= @config['storage']['provider'] %> 38 | BARONG_STORAGE_BUCKET_NAME=<%= @config['storage']['bucketName'] %> 39 | BARONG_STORAGE_ACCESS_KEY=<%= @config['storage']['accessKey'] %> 40 | BARONG_STORAGE_SECRET_KEY=<%= @config['storage']['secretKey'] %> 41 | BARONG_STORAGE_ENDPOINT=<%= @config['storage']['endpoint'] %> 42 | BARONG_STORAGE_SIGNATURE_VERSION=<%= @config['storage']['signatureVersion'] %> 43 | BARONG_STORAGE_REGION=<%= @config['storage']['region'] %> 44 | 45 | BARONG_CAPTCHA=<%= @config['captcha']['type'] %> 46 | <% if @config['captcha']['type'] == 'recaptcha' %> 47 | BARONG_RECAPTCHA_SITE_KEY=<%= @config['captcha']['siteKey'] %> 48 | BARONG_RECAPTCHA_SECRET_KEY=<%= @config['captcha']['secretKey'] %> 49 | <% elsif @config['captcha']['type'] == 'geetest' %> 50 | BARONG_GEETEST_ID=<%= @config['captcha']['siteKey'] %> 51 | BARONG_GEETEST_KEY=<%= @config['captcha']['secretKey'] %> 52 | <% end %> 53 | 54 | JWT_PUBLIC_KEY=<%= @barong_public_key %> 55 | JWT_PRIVATE_KEY_PATH=/secrets/barong.key 56 | 57 | BARONG_VAULT_TOKEN=<%= @config['vault']['barong_token'] %> 58 | BARONG_VAULT_ADDRESS=http://vault:8200 59 | BARONG_VAULT_APP_NAME=<%= @config['app']['name'].downcase %> 60 | 61 | REDIS_URL=redis://redis:6379 62 | BARONG_REDIS_URL=redis://redis:6379 63 | 64 | BARONG_EVENT_API_JWT_PRIVATE_KEY=<%= @barong_private_key %> 65 | BARONG_EVENT_API_JWT_ALGORITHM=RS256 66 | BARONG_EVENT_API_RABBITMQ_HOST=rabbitmq 67 | BARONG_EVENT_API_RABBITMQ_PORT=5672 68 | BARONG_EVENT_API_RABBITMQ_USERNAME=guest 69 | BARONG_EVENT_API_RABBITMQ_PASSWORD=guest 70 | 71 | BARONG_SMTP_HOST=<%= @config['smtp']['host'] %> 72 | BARONG_SMTP_PORT=<%= @config['smtp']['port'] %> 73 | BARONG_SMTP_USER=<%= @config['smtp']['user'] %> 74 | BARONG_SMTP_PASSWORD=<%= @config['smtp']['password'] %> 75 | BARONG_SMTP_LOGO_LINK=<%= @config['smtp']['sender_logo'] %> 76 | BARONG_DEFAULT_LANGUAGE=en 77 | 78 | BARONG_SENDER_NAME=<%= @config['smtp']['sender_name'] %> 79 | BARONG_SENDER_EMAIL=<%= @config['smtp']['sender_email'] %> 80 | 81 | BARONG_KYCAID_AUTHORIZATION_TOKEN=<%= @config['kyc']['authorization_token'] %> 82 | BARONG_KYCAID_SANDBOX_MODE=<%= @config['kyc']['sandbox_mode'] %> 83 | BARONG_KYCAID_API_ENDPOINT=<%= @config['kyc']['api_endpoint'] %> 84 | 85 | BARONG_PASSWORD_MIN_ENTROPY=14 86 | BARONG_PASSWORD_USE_DICTIONARY=false 87 | 88 | BARONG_CSRF_PROTECTION=<%= @config['csrfEnabled'] %> 89 | 90 | BARONG_APP_NAME=<%= @config['app']['name'] %> 91 | BARONG_DOMAIN=<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %> 92 | -------------------------------------------------------------------------------- /templates/config/barong/abilities.yml.erb: -------------------------------------------------------------------------------- 1 | roles: 2 | - superadmin 3 | - admin 4 | - technical 5 | - accountant 6 | - compliance 7 | - support 8 | 9 | admin_permissions: 10 | superadmin: 11 | manage: 12 | - Ability 13 | - User 14 | - Level 15 | - Label 16 | - Profile 17 | - Activity 18 | - APIKey 19 | - Permission 20 | - Restriction 21 | - Document 22 | admin: 23 | read: 24 | - Activity 25 | manage: 26 | - Ability 27 | - User 28 | - Level 29 | - Label 30 | - Profile 31 | - APIKey 32 | - Restriction 33 | - Document 34 | technical: 35 | read: 36 | - Ability 37 | - User 38 | - Level 39 | - Label 40 | - Profile 41 | - Activity 42 | manage: 43 | - APIKey 44 | - Restriction 45 | accountant: 46 | read: 47 | - Ability 48 | - User 49 | - Level 50 | - Label 51 | - Profile 52 | - Activity 53 | compliance: 54 | read: 55 | - Ability 56 | - Document 57 | manage: 58 | - User 59 | - Level 60 | - Label 61 | - Profile 62 | support: 63 | read: 64 | - Ability 65 | - Label 66 | - Level 67 | - Profile 68 | - Activity 69 | manage: 70 | - User 71 | -------------------------------------------------------------------------------- /templates/config/barong/management_api.yml.erb: -------------------------------------------------------------------------------- 1 | keychain: 2 | applogic: 3 | algorithm: RS256 4 | value: <%= @applogic_public_key %> 5 | 6 | scopes: 7 | read_users: 8 | mandatory_signers: 9 | - applogic 10 | permitted_signers: 11 | - applogic 12 | -------------------------------------------------------------------------------- /templates/config/bitcoin.conf.erb: -------------------------------------------------------------------------------- 1 | <%- bitcoind = @config['bitcoind'] -%> 2 | txindex=1 3 | dnsseed=1 4 | upnp=0 5 | printtoconsole=1 6 | 7 | server=1 8 | 9 | <%- unless bitcoind['network'] == 'mainnet' -%> 10 | <%= "#{bitcoind['network']}=1" %> 11 | [test] 12 | <%- end -%> 13 | rpcuser=<%= bitcoind['rpcuser'] %> 14 | rpcpassword=<%= bitcoind['rpcpassword'] %> 15 | port=<%= bitcoind['port'] %> 16 | rpcport=<%= bitcoind['rpcport'] %> 17 | rpcbind=0.0.0.0 18 | rpcallowip=0.0.0.0/0 19 | -------------------------------------------------------------------------------- /templates/config/finex/config.yaml.erb: -------------------------------------------------------------------------------- 1 | metrics: 2 | enabled: true 3 | license: <%= @config['finex']['license_key'] %> 4 | influx: 5 | host: influxdb 6 | port: 8086 7 | scheme: http 8 | database: peatio_production 9 | database: 10 | driver: mysql 11 | name: peatio_production 12 | username: <%= @config['database']['user'] %> 13 | password: <%= @config['database']['password'] %> 14 | host: <%= @config['database']['host'] %> 15 | port: <%= @config['database']['port'] %> 16 | log_level: 17 | log_observer: info 18 | vault: 19 | host: http://vault:8200 20 | token: <%= @config['vault']['finex_engine_token'] %> 21 | app_name: <%= @config['app']['name'].downcase %> 22 | messaging: 23 | driver: amqp 24 | username: guest 25 | password: guest 26 | host: rabbitmq 27 | port: 5672 28 | exchanges: 29 | - name: finex.orderapi 30 | type: direct 31 | durable: false 32 | - name: finex.events.websocket 33 | type: topic 34 | durable: false 35 | - name: peatio.events.ranger 36 | type: topic 37 | durable: false 38 | - name: peatio.trade 39 | type: headers 40 | durable: false 41 | - name: peatio.events 42 | type: direct 43 | durable: false 44 | - name: peatio.matching 45 | type: direct 46 | durable: false 47 | queues: 48 | - name: finex.gateway 49 | - name: finex.events.processor 50 | - name: finex.influx.writer 51 | orderbook: 52 | max_publish_size: 300 53 | gateway: 54 | rate: 55 | maker: 56 | - limit: 500 57 | period: 10s 58 | admin: 59 | - limit: 500 60 | period: 10s 61 | superadmin: 62 | - limit: 500 63 | period: 10s 64 | bench: 65 | - limit: 9000 66 | period: 1s 67 | default: 68 | - limit: 50 69 | period: 10s 70 | - limit: 10000 71 | period: 24h 72 | api: 73 | bulk_limit: 100 74 | rate: 75 | maker: 76 | limit: 500 77 | period: 10s 78 | admin: 79 | limit: 500 80 | period: 10s 81 | superadmin: 82 | limit: 500 83 | period: 10s 84 | default: 85 | limit: 5 86 | period: 1s 87 | actions: 88 | trade: 89 | min_level: 2 90 | roles: [member, broker, trader, maker, admin, superadmin] 91 | bulk_api: 92 | min_level: 3 93 | roles: [maker, admin, superadmin] 94 | admin: 95 | min_level: 3 96 | roles: [admin, superadmin] 97 | -------------------------------------------------------------------------------- /templates/config/finex/rsa-key.pub.erb: -------------------------------------------------------------------------------- 1 | <%= Base64.decode64(@barong_public_key) %> 2 | -------------------------------------------------------------------------------- /templates/config/frontend/env.js.erb: -------------------------------------------------------------------------------- 1 | window.env = { 2 | api: { 3 | authUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/barong', 4 | tradeUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/peatio', 5 | finexUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/finex', 6 | applogicUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/applogic', 7 | rangerUrl: '<%= ssl_helper('ws') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/ranger', 8 | }, 9 | minutesUntilAutoLogout: '35', 10 | withCredentials: false, 11 | finex: <%= config['finex']['enabled'] %>, 12 | gaTrackerKey: '<%= @config['gaTrackerKey'] %>', 13 | rangerReconnectPeriod: '1', 14 | msAlertDisplayTime: '5000', 15 | incrementalOrderBook: true, 16 | isResizable: false, 17 | isDraggable: false, 18 | languages: ['en', 'ru'], 19 | sessionCheckInterval: '15000', 20 | balancesFetchInterval: '3000', 21 | passwordEntropyStep: 14, 22 | showLanding: <%= @config['app']['show_landing'] %>, 23 | sentryEnabled: false, 24 | kycSteps: [ 25 | 'email', 26 | 'phone', 27 | 'profile', 28 | 'document', 29 | 'address', 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /templates/config/frontend/tower.js.erb: -------------------------------------------------------------------------------- 1 | window.env = { 2 | applogicUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/applogic', 3 | authUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/barong', 4 | peatioUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/peatio', 5 | finexUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/finex', 6 | msAlertDisplayTime: '5000', 7 | tablePageLimit: 50, 8 | minutesUntilAutoLogout: '35', 9 | finex: <%= config['finex']['enabled'] %>, 10 | aml: false, 11 | captcha: { 12 | captchaType: '<%= @config['captcha']['type'] %>', 13 | siteKey: '<%= @config['captcha']['siteKey'] %>', 14 | }, 15 | labelSwitcher: [ 16 | { name: 'email', label: [{ email: 'verified' }] }, 17 | { name: 'phone', label: [{ phone: 'verified' }] }, 18 | { name: 'identity', label: [{ profile: 'partial' }, { id_document: 'verified' }, { liveness: 'verified' }] }, 19 | { name: 'residence', label: [{ document: 'verified' }] }, 20 | ], 21 | plugins: [], 22 | roleTypes: [ 23 | { 24 | value: 'Admin', 25 | key: 'admin', 26 | }, 27 | { 28 | value: 'Member', 29 | key: 'member', 30 | }, 31 | { 32 | value: 'Super Admin', 33 | key: 'superadmin', 34 | }, 35 | { 36 | value: 'Accountant', 37 | key: 'accountant', 38 | }, 39 | { 40 | value: 'Compliance', 41 | key: 'compliance', 42 | }, 43 | { 44 | value: 'Technical', 45 | key: 'technical', 46 | }, 47 | { 48 | value: 'Support', 49 | key: 'support', 50 | }, 51 | { 52 | value: 'Trader', 53 | key: 'trader', 54 | }, 55 | { 56 | value: 'Broker', 57 | key: 'broker', 58 | }, 59 | ], 60 | allowedRoles: [ 61 | 'admin', 62 | 'superadmin', 63 | 'accountant', 64 | 'compliance', 65 | 'support', 66 | 'technical', 67 | 'manager', 68 | ], 69 | withCredentials: false, 70 | sentryEnabled: false, 71 | devMode: true, 72 | minutesBeforeWarningMessage: '1', 73 | }; 74 | -------------------------------------------------------------------------------- /templates/config/gateway/envoy.yaml.erb: -------------------------------------------------------------------------------- 1 | static_resources: 2 | listeners: 3 | - address: 4 | socket_address: 5 | address: 0.0.0.0 6 | port_value: 8099 7 | filter_chains: 8 | - filters: 9 | - name: envoy.http_connection_manager 10 | config: 11 | codec_type: auto 12 | stat_prefix: ingress_http 13 | route_config: 14 | name: local_route 15 | virtual_hosts: 16 | - name: backend 17 | domains: 18 | - "*" 19 | cors: 20 | allow_origin: 21 | - "<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>" 22 | allow_methods: "PUT, GET, POST" 23 | allow_headers: "content-type, x-grpc-web" 24 | filter_enabled: 25 | default_value: 26 | numerator: 100 27 | denominator: HUNDRED 28 | runtime_key: cors.www.enabled 29 | routes: 30 | - match: 31 | prefix: "/api/v2/barong" 32 | route: 33 | cluster: barong 34 | prefix_rewrite: "/api/v2/" 35 | - match: 36 | prefix: "/api/v2/applogic" 37 | route: 38 | cluster: applogic 39 | prefix_rewrite: "/api/v2/" 40 | - match: 41 | prefix: "/api/v2/arke" 42 | route: 43 | cluster: arke 44 | prefix_rewrite: "/api/v2/" 45 | - match: 46 | prefix: "/api/v2/peatio" 47 | route: 48 | cluster: peatio 49 | prefix_rewrite: "/api/v2/" 50 | - match: 51 | prefix: "/api/v2/finex" 52 | route: 53 | cluster: finex 54 | prefix_rewrite: "/api/v2/" 55 | - match: 56 | prefix: "/admin" 57 | route: 58 | cluster: peatio 59 | - match: 60 | prefix: "/assets/" 61 | route: 62 | cluster: peatio 63 | - match: 64 | prefix: "/api/v2/ranger/public" 65 | route: 66 | cluster: rango 67 | prefix_rewrite: "" 68 | upgrade_configs: 69 | upgrade_type: "websocket" 70 | - match: 71 | prefix: "/api/v2/ranger/private" 72 | route: 73 | cluster: rango 74 | prefix_rewrite: "" 75 | upgrade_configs: 76 | upgrade_type: "websocket" 77 | http_filters: 78 | - name: envoy.cors 79 | typed_config: {} 80 | - name: envoy.ext_authz 81 | config: 82 | with_request_body: 83 | max_request_bytes: 90000000 84 | allow_partial_message: true 85 | http_service: 86 | authorization_request: 87 | allowed_headers: 88 | patterns: 89 | - exact: cookie 90 | - exact: x-auth-apikey 91 | - exact: x-auth-nonce 92 | - exact: x-auth-signature 93 | - exact: x-csrf-token 94 | - exact: user-agent 95 | - exact: x-forwarded-host 96 | - exact: x-forwarded-for 97 | - exact: from 98 | - exact: x-forwarded-proto 99 | - exact: proxy-authorization 100 | authorization_response: 101 | allowed_upstream_headers: 102 | patterns: 103 | - exact: authorization 104 | allowed_client_headers: 105 | patterns: 106 | - exact: set-cookie 107 | - exact: proxy-authenticate 108 | - exact: www-authenticate 109 | - exact: location 110 | path_prefix: "/api/v2/auth" 111 | server_uri: 112 | cluster: barong 113 | timeout: 1.000s 114 | uri: http://barong:8001 115 | - name: envoy.router 116 | config: {} 117 | perConnectionBufferLimitBytes: 10000000 118 | clusters: 119 | - name: barong 120 | connect_timeout: 0.25s 121 | type: strict_dns 122 | lb_policy: round_robin 123 | hosts: 124 | - socket_address: 125 | address: barong 126 | port_value: 8001 127 | - name: applogic 128 | connect_timeout: 0.25s 129 | type: strict_dns 130 | lb_policy: round_robin 131 | hosts: 132 | - socket_address: 133 | address: applogic 134 | port_value: 8081 135 | - name: arke 136 | connect_timeout: 0.25s 137 | type: strict_dns 138 | lb_policy: round_robin 139 | hosts: 140 | - socket_address: 141 | address: arke 142 | port_value: 8081 143 | - name: peatio 144 | connect_timeout: 0.25s 145 | type: strict_dns 146 | lb_policy: round_robin 147 | hosts: 148 | - socket_address: 149 | address: peatio 150 | port_value: 8000 151 | - name: finex 152 | connect_timeout: 0.25s 153 | type: strict_dns 154 | lb_policy: round_robin 155 | hosts: 156 | - socket_address: 157 | address: finex-api 158 | port_value: 8080 159 | - name: rango 160 | connect_timeout: 0.25s 161 | type: strict_dns 162 | lb_policy: round_robin 163 | hosts: 164 | - socket_address: 165 | address: rango 166 | port_value: 8080 167 | admin: 168 | access_log_path: "/dev/null" 169 | address: 170 | socket_address: 171 | address: 0.0.0.0 172 | port_value: 9099 173 | -------------------------------------------------------------------------------- /templates/config/litecoin.conf.erb: -------------------------------------------------------------------------------- 1 | <%- litecoind = @config['litecoind'] -%> 2 | txindex=1 3 | dnsseed=1 4 | upnp=0 5 | printtoconsole=1 6 | 7 | server=1 8 | 9 | onlynet=ipv4 10 | 11 | <%- unless litecoind['network'] == 'mainnet' -%> 12 | <%= "#{litecoind['network']}=1" %> 13 | [test] 14 | <%- end -%> 15 | rpcuser=<%= litecoind['rpcuser'] %> 16 | rpcpassword=<%= litecoind['rpcpassword'] %> 17 | port=<%= litecoind['port'] %> 18 | rpcport=<%= litecoind['rpcport'] %> 19 | rpcbind=0.0.0.0 20 | rpcallowip=0.0.0.0/0 21 | -------------------------------------------------------------------------------- /templates/config/mailer.yml.erb: -------------------------------------------------------------------------------- 1 | keychain: 2 | barong: 3 | algorithm: RS256 4 | value: "<%= @barong_public_key %>" 5 | peatio: 6 | algorithm: RS256 7 | value: "<%= @barong_public_key %>" 8 | 9 | exchanges: 10 | barong_system: 11 | name: barong.events.system 12 | signer: barong 13 | barong_model: 14 | name: barong.events.model 15 | signer: barong 16 | peatio: 17 | name: peatio.events.model 18 | signer: peatio 19 | 20 | events: 21 | - name: Email Confirmation 22 | key: user.email.confirmation.token 23 | exchange: barong_system 24 | templates: 25 | EN: 26 | subject: Registration Confirmation 27 | template_path: email_confirmation.en.html.erb 28 | RU: 29 | subject: Подтверждение Регистрации 30 | template_path: email_confirmation.ru.html.erb 31 | 32 | - name: Password Reset 33 | key: user.password.reset.token 34 | exchange: barong_system 35 | templates: 36 | EN: 37 | subject: Password Reset 38 | template_path: password_reset.en.html.erb 39 | RU: 40 | subject: Сброс Пароля 41 | template_path: password_reset.ru.html.erb 42 | 43 | - name: Label Created 44 | key: label.created 45 | exchange: barong_model 46 | expression: | 47 | record.key in ["phone", "profile", "document"] && 48 | record.value in ["verified", "rejected"] 49 | templates: 50 | EN: 51 | subject: Account Details Updated 52 | template_path: label_created.en.html.erb 53 | 54 | - name: Label Updated 55 | key: label.updated 56 | exchange: barong_model 57 | expression: | 58 | record.key in ["phone", "profile", "document"] && 59 | record.value in ["verified", "rejected"] 60 | templates: 61 | EN: 62 | subject: Account Details Updated 63 | template_path: label_created.en.html.erb 64 | 65 | - name: Deposit Accepted 66 | key: deposit.updated 67 | exchange: peatio 68 | expression: changes.state == "submitted" && record.state == "accepted" 69 | templates: 70 | EN: 71 | subject: Deposit Accepted 72 | template_path: deposit_accepted.en.html.erb 73 | 74 | - name: Session Create 75 | key: session.create 76 | exchange: barong_system 77 | templates: 78 | EN: 79 | subject: New Login 80 | template_path: session_create.en.html.erb 81 | 82 | - name: Withdrawal Succeed 83 | key: withdraw.updated 84 | exchange: peatio 85 | expression: changes.state in ["succeed", "rejected", "canceled", "failed", "accepted"] && record.state in ["succeed", "rejected", "canceled", "failed"] 86 | templates: 87 | EN: 88 | subject: Withdrawal Succeed 89 | template_path: withdraw_succeed.en.html.erb 90 | 91 | - name: New Beneficiary 92 | key: beneficiary.created 93 | exchange: peatio 94 | templates: 95 | EN: 96 | subject: New Beneficiary 97 | template_path: new_beneficiary.en.html.erb 98 | 99 | - name: Resend beneficiary 100 | key: beneficiary.updated 101 | exchange: peatio 102 | expression: 103 | and: 104 | record.state: 'pending' 105 | templates: 106 | EN: 107 | subject: Resend Beneficiary 108 | template_path: new_beneficiary.en.html.erb 109 | -------------------------------------------------------------------------------- /templates/config/mysql/innodb.cnf.erb: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | innodb_buffer_pool_size = 2G 3 | innodb_buffer_pool_instances = 2 4 | innodb_log_buffer_size = 128M 5 | innodb_log_file_size = 512M 6 | innodb_flush_log_at_trx_commit = 0 7 | -------------------------------------------------------------------------------- /templates/config/peatio.env.erb: -------------------------------------------------------------------------------- 1 | RAILS_ENV=production 2 | RAILS_ROOT=/home/app 3 | 4 | PORT=8000 5 | URL_HOST=<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %> 6 | 7 | LOG_LEVEL=warn 8 | 9 | ADMIN=admin@barong.io 10 | 11 | <%- if @config['database']['adapter'] == 'postgresql' %> 12 | DATABASE_COLLATION="" 13 | DATABASE_ADAPTER="postgresql" 14 | <%- elsif @config['database']['adapter'] == 'mysql' %> 15 | DATABASE_ADAPTER="mysql2" 16 | <%- end %> 17 | DATABASE_HOST=<%= @config['database']['host'] %> 18 | DATABASE_PORT=<%= @config['database']['port'] %> 19 | DATABASE_USER=<%= @config['database']['user'] %> 20 | DATABASE_PASS=<%= @config['database']['password'] %> 21 | 22 | VAULT_ADDR=http://vault:8200 23 | VAULT_TOKEN= 24 | VAULT_APP_NAME=<%= @config['app']['name'].downcase %> 25 | 26 | REDIS_URL=redis://redis:6379 27 | 28 | RABBITMQ_HOST=rabbitmq 29 | 30 | 31 | MARKETS_CONFIG=/opt/peatio/config/seed/markets.yml 32 | CURRENCIES_CONFIG=/opt/peatio/config/seed/currencies.yml 33 | MANAGEMENT_API_V1_CONFIG=/opt/peatio/config/management_api_v1.yml 34 | 35 | JWT_AUDIENCE=peatio,barong 36 | JWT_PUBLIC_KEY=<%= @barong_public_key %> 37 | 38 | INFLUXDB_HOST=influxdb 39 | 40 | EVENT_API_JWT_PRIVATE_KEY=<%= @barong_private_key %> 41 | EVENT_API_JWT_ALGORITHM=RS256 42 | EVENT_API_RABBITMQ_HOST=rabbitmq 43 | EVENT_API_RABBITMQ_PORT=5672 44 | EVENT_API_RABBITMQ_USERNAME=guest 45 | EVENT_API_RABBITMQ_PASSWORD=guest 46 | 47 | MINIMUM_MEMBER_LEVEL_FOR_DEPOSIT=1 48 | MINIMUM_MEMBER_LEVEL_FOR_WITHDRAW=3 49 | MINIMUM_MEMBER_LEVEL_FOR_TRADING=2 50 | 51 | SECRET_KEY_BASE=faiba2shei0Ae5gahCh4aipoh3meyaFi 52 | FORCE_SECURE_CONNECTION="false" 53 | -------------------------------------------------------------------------------- /templates/config/peatio/abilities.yml.erb: -------------------------------------------------------------------------------- 1 | roles: 2 | - superadmin 3 | - admin 4 | - technical 5 | - accountant 6 | - compliance 7 | - support 8 | - member 9 | - broker 10 | - trader 11 | - maker 12 | - sa_maker 13 | 14 | admin_permissions: 15 | superadmin: 16 | manage: 17 | - Operations::Account 18 | - Operations::Asset 19 | - Operations::Expense 20 | - Operations::Liability 21 | - Operations::Revenue 22 | - Member 23 | - Account 24 | - Beneficiary 25 | - PaymentAddress 26 | - Deposit 27 | - Withdraw 28 | - WithdrawLimit 29 | - Blockchain 30 | - Currency 31 | - Engine 32 | - Market 33 | - TradingFee 34 | - Wallet 35 | - Adjustment 36 | - InternalTransfer 37 | - WhitelistedSmartContract 38 | read: 39 | - Trade 40 | - Order 41 | create: 42 | - Deposits::Fiat 43 | update: 44 | - Order 45 | admin: 46 | manage: 47 | - Operations::Account 48 | - Operations::Asset 49 | - Operations::Expense 50 | - Operations::Liability 51 | - Operations::Revenue 52 | - Beneficiary 53 | - Deposit 54 | - Withdraw 55 | - WithdrawLimit 56 | - Engine 57 | - Market 58 | - TradingFee 59 | - Wallet 60 | - Adjustment 61 | - InternalTransfer 62 | - WhitelistedSmartContract 63 | - Currency 64 | - Blockchain 65 | read: 66 | - Trade 67 | - Order 68 | - Account 69 | - PaymentAddress 70 | - Member 71 | create: 72 | - Deposits::Fiat 73 | update: 74 | - Order 75 | - Member 76 | technical: 77 | read: 78 | - Operations::Account 79 | - Operations::Asset 80 | - Operations::Expense 81 | - Operations::Liability 82 | - Trade 83 | - Order 84 | - Member 85 | - InternalTransfer 86 | manage: 87 | - WithdrawLimit 88 | - Blockchain 89 | - Currency 90 | - Engine 91 | - Market 92 | - TradingFee 93 | - Wallet 94 | - WhitelistedSmartContract 95 | update: 96 | - Order 97 | accountant: 98 | read: 99 | - Operations::Account 100 | - Operations::Asset 101 | - Operations::Expense 102 | - Operations::Liability 103 | - Operations::Revenue 104 | - Member 105 | - Account 106 | - Beneficiary 107 | - PaymentAddress 108 | - Deposit 109 | - Withdraw 110 | - WithdrawLimit 111 | - Blockchain 112 | - Currency 113 | - Engine 114 | - Market 115 | - TradingFee 116 | - Wallet 117 | - Trade 118 | - Order 119 | - Adjustment 120 | - InternalTransfer 121 | create: 122 | - Deposits::Fiat 123 | - Adjustment 124 | compliance: 125 | read: 126 | - Operations::Account 127 | - Operations::Asset 128 | - Operations::Expense 129 | - Operations::Liability 130 | - Member 131 | - Account 132 | - Beneficiary 133 | - PaymentAddress 134 | - Deposit 135 | - Withdraw 136 | - Currency 137 | - Engine 138 | - Market 139 | - Trade 140 | - Order 141 | support: 142 | read: 143 | - Operations::Account 144 | - Operations::Asset 145 | - Operations::Expense 146 | - Operations::Liability 147 | - Member 148 | - Account 149 | - Beneficiary 150 | - PaymentAddress 151 | - Deposit 152 | - Withdraw 153 | - Currency 154 | - Engine 155 | - Market 156 | - Trade 157 | - Order 158 | - InternalTransfer 159 | 160 | user_permissions: 161 | superadmin: 162 | manage: all 163 | admin: 164 | manage: all 165 | technical: 166 | manage: all 167 | accountant: 168 | manage: all 169 | compliance: 170 | manage: all 171 | support: 172 | manage: all 173 | member: 174 | manage: all 175 | broker: 176 | manage: all 177 | trader: 178 | manage: all 179 | maker: 180 | manage: all 181 | sa_maker: 182 | read: 183 | - Operations::Account 184 | - Order 185 | - Trade 186 | - StatsMemberPnl 187 | create: 188 | - Order 189 | update: 190 | - Order 191 | -------------------------------------------------------------------------------- /templates/config/peatio/management_api_v1.yml.erb: -------------------------------------------------------------------------------- 1 | keychain: 2 | applogic: 3 | algorithm: RS256 4 | value: <%= @applogic_public_key %> 5 | 6 | scopes: 7 | read_operations: 8 | mandatory_signers: 9 | - applogic 10 | permitted_signers: 11 | - applogic 12 | 13 | jwt: {} 14 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/accounts.yml.erb: -------------------------------------------------------------------------------- 1 | - code: 101 2 | type: asset 3 | kind: main 4 | currency_type: fiat 5 | description: Main Fiat Assets Account 6 | scope: platform 7 | 8 | - code: 102 9 | type: asset 10 | kind: main 11 | currency_type: coin 12 | description: Main Crypto Assets Account 13 | scope: platform 14 | 15 | - code: 201 16 | type: liability 17 | kind: main 18 | currency_type: fiat 19 | description: Main Fiat Liabilities Account 20 | scope: member 21 | 22 | - code: 202 23 | type: liability 24 | kind: main 25 | currency_type: coin 26 | description: Main Crypto Liabilities Account 27 | scope: member 28 | 29 | - code: 211 30 | type: liability 31 | kind: locked 32 | currency_type: fiat 33 | description: Locked Fiat Liabilities Account 34 | scope: member 35 | 36 | - code: 212 37 | type: liability 38 | kind: locked 39 | currency_type: coin 40 | description: Locked Crypto Liabilities Account 41 | scope: member 42 | 43 | - code: 301 44 | type: revenue 45 | kind: main 46 | currency_type: fiat 47 | description: Main Fiat Revenues Account 48 | scope: platform 49 | 50 | - code: 302 51 | type: revenue 52 | kind: main 53 | currency_type: coin 54 | description: Main Crypto Revenues Account 55 | scope: platform 56 | 57 | - code: 401 58 | type: expense 59 | kind: main 60 | currency_type: fiat 61 | description: Main Fiat Expenses Account 62 | scope: platform 63 | 64 | - code: 402 65 | type: expense 66 | kind: main 67 | currency_type: coin 68 | description: Main Crypto Expenses Account 69 | scope: platform 70 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/blockchains.yml.erb: -------------------------------------------------------------------------------- 1 | - key: eth-<%= @config['parity']['network'] %> 2 | name: Ethereum <%= @config['parity']['network'].capitalize %> 3 | client: parity 4 | server: http://<%= @config['parity']['address'] %>:<%= @config['parity']['rpcport'] %> 5 | height: 8670000 6 | min_confirmations: 6 7 | explorer: 8 | address: https://etherscan.io/address/#{address} 9 | transaction: https://etherscan.io/tx/#{txid} 10 | status: active 11 | 12 | <% if @config['bitcoind']['enabled'] %> 13 | - key: btc-<%= @config['bitcoind']['network'] %> 14 | name: Bitcoin <%= @config['bitcoind']['network'].capitalize %> 15 | client: bitcoin 16 | server: http://<%= @config['bitcoind']['rpcuser'] %>:<%= @config['bitcoind']['rpcpassword'] %>@<%= @config['bitcoind']['address'] %>:<%= @config['bitcoind']['rpcport'] %> 17 | height: 597000 18 | min_confirmations: 6 19 | explorer: 20 | address: https://blockchain.info/address/#{address} 21 | transaction: https://blockchain.info/tx/#{txid} 22 | status: active 23 | <% end %> 24 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/currencies.yml.erb: -------------------------------------------------------------------------------- 1 | - id: usd 2 | name: US Dollar 3 | type: fiat 4 | precision: 2 5 | base_factor: 1 6 | visible: true 7 | deposit_enabled: true 8 | withdrawal_enabled: true 9 | min_deposit_amount: 0.01 10 | min_collection_amount: 0.01 11 | withdraw_limit_24h: 100 12 | withdraw_limit_72h: 200 13 | deposit_fee: 0 14 | withdraw_fee: 0 15 | position: 1 16 | options: {} 17 | 18 | - id: eth 19 | name: Ethereum 20 | blockchain_key: eth-<%= @config['parity']['network'] %> 21 | type: coin 22 | precision: 8 23 | base_factor: 1_000_000_000_000_000_000 24 | visible: true 25 | deposit_enabled: true 26 | withdrawal_enabled: true 27 | # Deposits with less amount are skipped during blockchain synchronization. 28 | # We advise to set value 10 times bigger than the network fee to prevent losses. 29 | min_deposit_amount: 0.00021 30 | min_collection_amount: 0.00021 31 | withdraw_limit_24h: 0.2 32 | withdraw_limit_72h: 0.5 33 | deposit_fee: 0 34 | withdraw_fee: 0 35 | position: 3 36 | options: 37 | # ETH tx fees configurations. 38 | # 39 | # Maximum amount of gas you're willing to spend on a particular transaction. 40 | gas_limit: 21_000 41 | # Internal price that is paid for running a transaction on the Ethereum network. 42 | gas_price: 1_000_000_000 43 | 44 | - id: trst 45 | name: WeTrust 46 | blockchain_key: eth-<%= @config['parity']['network'] %> 47 | type: coin 48 | precision: 8 49 | base_factor: 1_000_000 # IMPORTANT: Don't forget to update this variable according 50 | # to your ERC20-based currency requirements 51 | # (usually can be found on the official website). 52 | visible: true 53 | deposit_enabled: true 54 | withdrawal_enabled: true 55 | # Deposits with less amount are skipped during blockchain synchronization. 56 | # We advise to set value 10 times bigger than the network fee to prevent losses. 57 | # NOTE: Network fee is paid in ETH but min_deposit_amount is in TRST. 58 | min_deposit_amount: 2 59 | min_collection_amount: 2 60 | withdraw_limit_24h: 300 # (usually can be found on the official website). 61 | withdraw_limit_72h: 600 62 | deposit_fee: 0 63 | withdraw_fee: 0 64 | position: 4 65 | options: 66 | # ERC20 tx fees configurations. 67 | # 68 | # Maximum amount of gas you're willing to spend on a particular transaction. 69 | gas_limit: 90_000 70 | # Internal price that is paid for running a contract on the Ethereum network. 71 | gas_price: 1_000_000_000 72 | # 73 | # ERC20 configuration. 74 | erc20_contract_address: '0x87099add3bcc0821b5b151307c147215f839a110' # Always wrap this value in quotes! 75 | <% if @config['bitcoind']['enabled'] %> 76 | - id: btc 77 | name: Bitcoin 78 | blockchain_key: btc-<%= @config['bitcoind']['network'] %> 79 | type: coin 80 | precision: 8 81 | base_factor: 100_000_000 82 | visible: true 83 | deposit_enabled: true 84 | withdrawal_enabled: true 85 | # Deposits with less amount are skipped during blockchain synchronization. 86 | # We advise to set value 10 times bigger than the network fee to prevent losses. 87 | min_deposit_amount: 0.0000356 88 | min_collection_amount: 0.0000356 89 | withdraw_limit_24h: 0.1 90 | withdraw_limit_72h: 0.2 91 | deposit_fee: 0 92 | withdraw_fee: 0 93 | position: 2 94 | options: {} 95 | <% end %> 96 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/engines.yml.erb: -------------------------------------------------------------------------------- 1 | - name: peatio-default-engine 2 | driver: peatio 3 | state: online 4 | - name: local-finex-spot-engine 5 | driver: finex-spot 6 | state: online 7 | - name: opendax-finex-spot-engine 8 | driver: opendax 9 | url: https://www.opendax.io/api/v2/finex 10 | key: "" 11 | secret: "" 12 | # The data field for store some special data engine 13 | # Can be used in upstream worker 14 | data: | 15 | { 16 | "rest"=>"https://www.opendax.io/api/v2/finex", 17 | "websocket"=>"wss://www.opendax.io/api/v2/ranger", 18 | "trade_proxy"=>true, 19 | } 20 | state: online 21 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/markets.yml.erb: -------------------------------------------------------------------------------- 1 | - id: ethusd 2 | engine_name: peatio-default-engine 3 | base_unit: eth 4 | quote_unit: usd 5 | amount_precision: 5 6 | price_precision: 2 7 | min_price: 0.01 8 | max_price: 1000.0 9 | min_amount: 0.00001 10 | position: 2 11 | state: enabled 12 | data: {} 13 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/trading_fees.yml.erb: -------------------------------------------------------------------------------- 1 | - market_id: any 2 | group: any 3 | maker: 0.002 4 | taker: 0.002 5 | 6 | - market_id: any 7 | group: vip-0 8 | maker: 0.001 9 | taker: 0.002 10 | 11 | - market_id: any 12 | group: vip-1 13 | maker: 0.0008 14 | taker: 0.0018 15 | 16 | - market_id: any 17 | group: vip-2 18 | maker: 0.0006 19 | taker: 0.0016 20 | 21 | - market_id: any 22 | group: vip-3 23 | maker: 0.0 24 | taker: 0.0014 25 | -------------------------------------------------------------------------------- /templates/config/peatio/seed/wallets.yml.erb: -------------------------------------------------------------------------------- 1 | <% @config['wallets']['eth'].each do |wallet| -%> 2 | - name: Ethereum <%= wallet['kind'].capitalize %> Wallet 3 | blockchain_key: eth-<%= @config['parity']['network'] %> 4 | currency_ids: eth,trst 5 | address: '<%= wallet['address'] %>' 6 | kind: <%= wallet['kind'] %> 7 | max_balance: <%= wallet['max_balance'] %> 8 | status: active 9 | gateway: parity 10 | settings: 11 | uri: http://<%= @config['parity']['address'] %>:<%= @config['parity']['rpcport'] %> 12 | secret: '<%= wallet['secret'] %>' 13 | <% end %> 14 | 15 | <% if @config['bitcoind']['enabled'] %> 16 | <% @config['wallets']['btc'].each do |wallet| -%> 17 | - name: Bitcoin <%= wallet['kind'].capitalize %> Wallet 18 | blockchain_key: btc-<%= @config['bitcoind']['network'] %> 19 | currency_ids: btc 20 | address: '<%= wallet['address'] %>' 21 | kind: <%= wallet['kind'] %> 22 | max_balance: <%= wallet['max_balance'] %> 23 | status: active 24 | gateway: bitcoind 25 | settings: 26 | uri: http://<%= @config['bitcoind']['rpcuser'] %>:<%= @config['bitcoind']['rpcpassword'] %>@<%= @config['bitcoind']['address'] %>:<%= @config['bitcoind']['rpcport'] %> 27 | <% end %> 28 | <% end %> 29 | -------------------------------------------------------------------------------- /templates/config/rango.env.erb: -------------------------------------------------------------------------------- 1 | RANGER_HOST=0.0.0.0 2 | RANGER_PORT=8080 3 | RANGER_CONNECT_SECURE="false" 4 | 5 | LOG_LEVEL=info 6 | 7 | RABBITMQ_HOST=rabbitmq 8 | 9 | JWT_PUBLIC_KEY=<%= @barong_public_key %> 10 | -------------------------------------------------------------------------------- /templates/config/toolbox.yaml.erb: -------------------------------------------------------------------------------- 1 | # For other configuration options, see https://github.com/rubykube/toolbox/blob/master/bin/stress_trading 2 | 3 | root-url: http://www.wb.local 4 | 5 | currencies: usd,eur 6 | markets: eurusd 7 | 8 | orders: 100 9 | traders: 10 10 | threads: 5 11 | management-api-v1-jwt-signer: toolbox 12 | api-v2-jwt-key: "<%= @barong_private_key %>" 13 | management-api-v1-jwt-key: "<%= @toolbox_jwt_private_key %>" 14 | -------------------------------------------------------------------------------- /templates/config/vault/barong.hcl.erb: -------------------------------------------------------------------------------- 1 | # Access system health status 2 | path "sys/health" { 3 | capabilities = ["read", "list"] 4 | } 5 | # Manage the transit secrets engine 6 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 7 | capabilities = ["create", "read", "list"] 8 | } 9 | # Encrypt API keys 10 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_apikeys_*" { 11 | capabilities = ["create", "read", "update"] 12 | } 13 | # Decrypt API keys 14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_apikeys_*" { 15 | capabilities = ["create", "read", "update"] 16 | } 17 | # Renew tokens 18 | path "auth/token/renew" { 19 | capabilities = ["update"] 20 | } 21 | # Lookup tokens 22 | path "auth/token/lookup" { 23 | capabilities = ["update"] 24 | } 25 | # Manage otp keys 26 | path "totp/keys/<%= @config['app']['name'].downcase %>_*" { 27 | capabilities = ["create", "read", "update", "delete"] 28 | } 29 | # Verify an otp code 30 | path "totp/code/<%= @config['app']['name'].downcase %>_*" { 31 | capabilities = ["update"] 32 | } 33 | -------------------------------------------------------------------------------- /templates/config/vault/finex_engine.hcl.erb: -------------------------------------------------------------------------------- 1 | path "transit/<%= @config['app']['name'].downcase %>_*" { 2 | capabilities = [ "read" ] 3 | } 4 | # Decrypt secrets 5 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_*" { 6 | capabilities = [ "create", "update" ] 7 | } 8 | # Use key for signing 9 | path "transit/sign/<%= @config['app']['name'].downcase %>_*" { 10 | capabilities = ["update"] 11 | } 12 | # Create transit key 13 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 14 | capabilities = ["create"] 15 | } 16 | # Renew tokens 17 | path "auth/token/renew" { 18 | capabilities = ["update"] 19 | } 20 | # Lookup tokens 21 | path "auth/token/lookup" { 22 | capabilities = ["update"] 23 | } 24 | -------------------------------------------------------------------------------- /templates/config/vault/peatio_crypto.hcl.erb: -------------------------------------------------------------------------------- 1 | # Manage the transit secrets engine 2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 3 | capabilities = ["create", "read", "list"] 4 | } 5 | # Encrypt Payment Addresses secrets 6 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_payment_addresses_*" { 7 | capabilities = ["create", "read", "update"] 8 | } 9 | # Decrypt Payment Addresses secrets 10 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_payment_addresses_*" { 11 | capabilities = ["create", "read", "update"] 12 | } 13 | # Decrypt wallets secrets 14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_wallets_*" { 15 | capabilities = ["create", "read", "update"] 16 | } 17 | # Encrypt blockchains data 18 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_blockchains_*" { 19 | capabilities = ["create", "read", "update"] 20 | } 21 | # Decrypt blockchains data 22 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_blockchains_*" { 23 | capabilities = ["create", "read", "update"] 24 | } 25 | # Renew tokens 26 | path "auth/token/renew" { 27 | capabilities = ["update"] 28 | } 29 | # Lookup tokens 30 | path "auth/token/lookup" { 31 | capabilities = ["update"] 32 | } 33 | -------------------------------------------------------------------------------- /templates/config/vault/peatio_matching.hcl.erb: -------------------------------------------------------------------------------- 1 | path "transit/<%= @config['app']['name'].downcase %>_*" { 2 | capabilities = [ "read" ] 3 | } 4 | # Decrypt secrets 5 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_*" { 6 | capabilities = [ "create", "update" ] 7 | } 8 | # Use key for signing 9 | path "transit/sign/<%= @config['app']['name'].downcase %>_*" { 10 | capabilities = ["update"] 11 | } 12 | # Create transit key 13 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 14 | capabilities = ["create"] 15 | } 16 | # Renew tokens 17 | path "auth/token/renew" { 18 | capabilities = ["update"] 19 | } 20 | # Lookup tokens 21 | path "auth/token/lookup" { 22 | capabilities = ["update"] 23 | } 24 | -------------------------------------------------------------------------------- /templates/config/vault/peatio_rails.hcl.erb: -------------------------------------------------------------------------------- 1 | # Manage the transit secrets engine 2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 3 | capabilities = ["create", "read", "list"] 4 | } 5 | # Encrypt engines secrets 6 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_engines_*" { 7 | capabilities = ["create", "read", "update"] 8 | } 9 | # Encrypt blockchains data 10 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_blockchains_*" { 11 | capabilities = ["create", "read", "update"] 12 | } 13 | # Decrypt blockchains data 14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_blockchains_*" { 15 | capabilities = ["create", "read", "update"] 16 | } 17 | # Encrypt wallets secrets 18 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_wallets_*" { 19 | capabilities = ["create", "read", "update"] 20 | } 21 | # Encrypt beneficiaries data 22 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_beneficiaries_*" { 23 | capabilities = [ "create", "read", "update" ] 24 | } 25 | # Decrypt beneficiaries data 26 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_beneficiaries_*" { 27 | capabilities = [ "create", "read", "update" ] 28 | } 29 | # Renew tokens 30 | path "auth/token/renew" { 31 | capabilities = ["update"] 32 | } 33 | # Lookup tokens 34 | path "auth/token/lookup" { 35 | capabilities = ["update"] 36 | } 37 | # Verify an otp code 38 | path "totp/code/<%= @config['app']['name'].downcase %>_*" { 39 | capabilities = ["update"] 40 | } 41 | -------------------------------------------------------------------------------- /templates/config/vault/peatio_upstream.hcl.erb: -------------------------------------------------------------------------------- 1 | # Manage the transit secrets engine 2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" { 3 | capabilities = ["create", "read", "list"] 4 | } 5 | # Decrypt Engines secrets 6 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_engines_*" { 7 | capabilities = ["create", "read", "update"] 8 | } 9 | # Renew tokens 10 | path "auth/token/renew" { 11 | capabilities = ["update"] 12 | } 13 | # Lookup tokens 14 | path "auth/token/lookup" { 15 | capabilities = ["update"] 16 | } 17 | -------------------------------------------------------------------------------- /templates/terraform/terraform.tfvars.erb: -------------------------------------------------------------------------------- 1 | credentials = "<%= @config['terraform']['credentials'] %>" 2 | project = "<%= @config['terraform']['project'] %>" 3 | region = "<%= @config['terraform']['region'] %>" 4 | zone = "<%= @config['terraform']['zone'] %>" 5 | ssh_user = "deploy" 6 | ssh_public_key = "../config/secrets/app.key.pub" 7 | ssh_private_key = "../config/secrets/app.key" 8 | instance_name = "<%= @config['terraform']['instance_name'] %>" 9 | machine_type = "<%= @config['terraform']['machine_type'] %>" 10 | image = "<%= @config['terraform']['image'] %>" 11 | -------------------------------------------------------------------------------- /templates/webhook.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=OpenDax Webhook service 3 | 4 | [Service] 5 | User=deploy 6 | Environment="WEBHOOK_JWT_SECRET=GENERATED_HMAC_SECRET" 7 | ExecStart=/bin/bash -c "source ~/.rvm/scripts/rvm; bundle exec rackup config.ru" 8 | Type=simple 9 | Restart=always 10 | WorkingDirectory=OPENDAX_DIRECTORY 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /terraform/main.tf: -------------------------------------------------------------------------------- 1 | provider "google" { 2 | credentials = file(var.credentials) 3 | project = var.project 4 | region = var.region 5 | } 6 | 7 | provider "random" { 8 | } 9 | 10 | resource "random_id" "opendax" { 11 | byte_length = 2 12 | } 13 | 14 | resource "google_compute_instance" "opendax" { 15 | name = "${var.instance_name}-${random_id.opendax.hex}" 16 | machine_type = var.machine_type 17 | zone = var.zone 18 | 19 | allow_stopping_for_update = true 20 | 21 | boot_disk { 22 | initialize_params { 23 | image = var.image 24 | type = "pd-ssd" 25 | size = 120 26 | } 27 | } 28 | 29 | network_interface { 30 | network = google_compute_network.opendax.name 31 | 32 | access_config { 33 | nat_ip = google_compute_address.opendax.address 34 | } 35 | } 36 | 37 | service_account { 38 | scopes = ["storage-ro"] 39 | } 40 | 41 | tags = ["allow-webhook"] 42 | 43 | metadata = { 44 | sshKeys = "${var.ssh_user}:${file(var.ssh_public_key)}" 45 | } 46 | 47 | provisioner "local-exec" { 48 | command = "mkdir -p /tmp/upload && rsync -rv --exclude=terraform ../ /tmp/upload/" 49 | } 50 | 51 | provisioner "remote-exec" { 52 | inline = [ 53 | "mkdir -p /home/${var.ssh_user}/opendax", 54 | ] 55 | 56 | connection { 57 | host = self.network_interface[0].access_config[0].nat_ip 58 | type = "ssh" 59 | user = var.ssh_user 60 | private_key = file(var.ssh_private_key) 61 | } 62 | } 63 | 64 | provisioner "file" { 65 | source = "/tmp/upload/" 66 | destination = "/home/${var.ssh_user}/opendax" 67 | 68 | connection { 69 | host = self.network_interface[0].access_config[0].nat_ip 70 | type = "ssh" 71 | user = var.ssh_user 72 | private_key = file(var.ssh_private_key) 73 | } 74 | } 75 | 76 | provisioner "remote-exec" { 77 | script = "../bin/install.sh" 78 | 79 | connection { 80 | host = self.network_interface[0].access_config[0].nat_ip 81 | type = "ssh" 82 | user = var.ssh_user 83 | private_key = file(var.ssh_private_key) 84 | } 85 | } 86 | 87 | provisioner "remote-exec" { 88 | script = "../bin/start.sh" 89 | 90 | connection { 91 | host = self.network_interface[0].access_config[0].nat_ip 92 | type = "ssh" 93 | user = var.ssh_user 94 | private_key = file(var.ssh_private_key) 95 | } 96 | } 97 | } 98 | 99 | resource "google_compute_firewall" "opendax" { 100 | name = "opendax-firewall-${random_id.opendax.hex}" 101 | network = google_compute_network.opendax.name 102 | 103 | allow { 104 | protocol = "tcp" 105 | ports = ["80", "8080", "1337", "443", "22"] 106 | } 107 | 108 | source_ranges = ["0.0.0.0/0"] 109 | 110 | target_tags = ["allow-webhook"] 111 | } 112 | 113 | resource "google_compute_address" "opendax" { 114 | name = "opendax-ip-${random_id.opendax.hex}" 115 | } 116 | 117 | resource "google_compute_network" "opendax" { 118 | name = "opendax-network-${random_id.opendax.hex}" 119 | } 120 | 121 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "credentials" { 2 | type = string 3 | } 4 | 5 | variable "ssh_user" { 6 | type = string 7 | description = "Name of the SSH user to use" 8 | default = "app" 9 | } 10 | 11 | variable "ssh_public_key" { 12 | type = string 13 | description = "Location of the public RSA key used for SSH-ing onto the main VM" 14 | } 15 | 16 | variable "ssh_private_key" { 17 | type = string 18 | description = "Location of the private RSA key used for SSH-ing onto the main VM" 19 | } 20 | 21 | variable "project" { 22 | type = string 23 | } 24 | 25 | variable "region" { 26 | type = string 27 | } 28 | 29 | variable "zone" { 30 | type = string 31 | } 32 | 33 | variable "machine_type" { 34 | type = string 35 | } 36 | 37 | variable "instance_name" { 38 | type = string 39 | } 40 | 41 | variable "image" { 42 | type = string 43 | } 44 | 45 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/vendor/.gitkeep --------------------------------------------------------------------------------