diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..0b4af7b428 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +templates +settings +web +.drone.yml +install.sh +uninstall.sh \ No newline at end of file diff --git a/server/README.md b/server/README.md index ea5b674043..192b25b462 100644 --- a/server/README.md +++ b/server/README.md @@ -1,8 +1,576 @@ # Server HollaEx Kit has a built in server based on express + swagger and provides API and Websocket communication for HollaEx Web or any other clients. -API +The main 3rd-party applications being used throughout the Server are: +- [HollaEx Tools Library](https://github.com/bitholla/hollaex-tools-lib) +- [HollaEx Node Library](https://github.com/bitholla/hollaex-node-lib#readme) +- [Express v4.16.2](https://expressjs.com/en/api.html) +- [SwaggerUI v2.0.0](https://swagger.io/docs/specification/2-0/basic-structure/) +- [Sequelize v4.37.7](https://sequelize.org/v4/) -Websocket +To edit your own HollaEx Kit Server, you should be at least familiar with the applications above. + +## API + +All folders and files related to the RESTful API are in the `api` directory. The structure of this directory is: +- controllers +- helpers +- swagger + +### Controllers + +The files in the controllers folder hold all the functions that the endpoints connect to. The files are separated by the action that endpoints are responsible for: +- `admin.js` +- `deposit.js` +- `notification.js` +- `order.js` +- `otp.js` +- `public.js` +- `tier.js` +- `trade.js` +- `user.js` +- `withdrawal.js` + +### Helpers + +The files in the helpers folder hold all the helper functions used by the controller files above. Currently it is empty, but feel free to add any helper functions you need when customizing your own HollaEx Kit. + +### Swagger + +This folder holds the `swagger.yaml` file that contains all the endpoints for the server's RESTful API. + +### Other Relevant Directories + +- db + - Contains the database functions, migration files, models, seeders, triggers, and redis clients. + - Database used is `postgreSQL` +- mail + - This directory holds everything relevant to emails. + - The `strings` directory holds all the strings that contain email messages. They are separated by langauge e.g. `en.js`, `fa.js`, etc. + - The `templates` directory holds all the email templates. They are separated by the emails being send e.g. `welcome.js`, `deposit.js`, etc. + - The library used for emails is `Nodemailer`. +- config + - This directory holds all the configurations for different functionalities e.g. the database, redis, and logger. + +## Websocket + +All websocket related files are contained in the `ws` directory. The HollaEx Kit websocket uses the following libraries: +- [HollaEx Node Library](https://github.com/bitholla/hollaex-node-lib#readme) - Used to connect to the HollaEx Network Websocket +- [ws](https://www.npmjs.com/package/ws) - Used to create the websocket server +- [ws-heartbeat](https://www.npmjs.com/package/ws-heartbeat) - Used to maintain websocket connection to the Network and also to disconnect any clients that don't send a message within 60 seconds + +### Structure +- `channel.js` - Manages all the websocket channels that are connected to the Kit +- `hub.js` - Manages the Kit's connection to the HollaEx Network +- `index.js` - Handles all connections made to the Kit websocket +- `publicData.js` - Holds public orderbook and trade data received from the HollaEx Network +- `server.js` - The Kit websocket server is created here +- `sub.js` - Handles messages received from subscribers to the Kit Websocket +- `chat` - This directory holds all files related to the chat functionality of the Kit + +### How it works +The HollaEx Kit websocket acts as a proxy between clients and the HollaEx Network. All it does is forward data received from the Network to connected users. Because of this nature, users will not be able to connect to your Kit's websocket if your Kit is not connected to the HollaEx Network's websocket. If the Kit's connection to the HollaEx Network disconnects, all connections to the Kit will be dropped. The hub websocket will reconnect automatically. + +All clients connected to the Kit will need to send a message at least once per minute or their connection will be dropped from the Kit. + +For an easier way to connect to the websocket, use the [HollaEx Node Library](https://github.com/bitholla/hollaex-node-lib/blob/2.0/NETWORK_README.md#websocket). + +### Usage + +#### Connecting +Connect to the websocket through the endpoint `(API_URL)/stream`. + +```javascript +const WebSocket = require('ws'); +const API_URL = 'https://api.hollaex.com' + +// Public connection +const publicSocket = new WebSocket(`${API_URL}/stream`); +``` + +#### Authentication +For private events, you will need to authenticate your connection. You can do this in two ways: +- By including query parameters `authorization` for Bearer Tokens or `api-key`, `api-signature`, and `api-expires` for Hmac keys during connection. +- By sending an authorization message after connection. + +Javascript Example: + +```javascript +const WebSocket = require('ws'); +const API_URL = 'https://api.hollaex.com' + +// Bearer Token +const privateSocket = new WebSocket(`${API_URL}/stream?authorization=${BEARER_TOKEN}`); + +// HMAC Authentication +const privateSocket = new WebSocket(`${API_URL}/stream?api-key=${API_KEY}&api-signature=${API_SIGNATURE}&api-expires=${API_EXPIRES}`); + +// Bearer Token +privateSocket.send( + JSON.stringify({ + op: 'auth', + args: [{ + authorization: BEARER_TOKEN + }] + }) +); + +// HMAC Authentication +privateSocket.send( + JSON.stringify({ + op: 'auth', + args: [{ + 'api-key': API_KEY, + 'api-signature': API_SIGNATURE, + 'api-expires': API_EXPIRES + }] + }) +); +``` + +#### Subscribing +There are four events you can subscribe to: +- orderbook +- trade +- wallet (private) +- order (private) + +To subscribe to an event, send a message with an `op` and `args` in a stringified object. You must authentication your connection for private events. For public events, you can also pass a symbol to subscribe to specific symbols. + +Javascript example: +``` javascript +publicSocket.on('open', () => { + publicSocket.send( + JSON.stringify({ + op: 'subscribe', + args: ['orderbook', 'trade:xht-usdt'] + }) + ); +}); + +privateSocket.on('open', () => { + privateSocket.send( + JSON.stringify({ + op: 'subscribe', + args: ['wallet', 'order'] + }) + ); +}); +``` + +#### Unsubscribing +You can unsubscribe by following the same format as subscription + +Javascript example: +``` javascript +publicSocket.send( + JSON.stringify({ + op: 'unsubscribe', + args: ['orderbook', 'trade:xht-usdt'] + }) +); + +privateSocket.send( + JSON.stringify({ + op: 'unsubscribe', + args: ['wallet', 'order'] + }) +); +``` + +#### Receiving Data +Once subscribed, you will receive data from events when the websocket `message` event triggers. + +Javascript example: +``` javascript +socket.on('message', (data) => { + data = JSON.parse(data); + console.log(data); +}; +``` + +These are exapmles of data responses from the server. + +- **orderbook**: Updates related to the user's private information are as follows: + + ```json + { + "topic": "orderbook", + "action": "partial", + "symbol": "xht-usdt", + "data": { + "bids": [ + [0.1, 0.1], + ... + ], + "asks": [ + [1, 1], + ... + ], + "timestamp": "2020-12-15T06:45:27.766Z" + }, + "time": 1608015328 + } + ``` + +- **trade**: Updates related to the user's private information are as follows: + + ```json + { + "topic": "trade", + "action": "partial", + "symbol": "xht-usdt", + "data": [ + { + "size": 0.012, + "price": 300, + "side": "buy", + "timestamp": "2020-12-15T07:25:28.887Z" + }, + ... + ], + "time": 1608015328 + } + ``` + +- **wallet**: Updates related to the user's private information are as follows: + + ```json + { + "topic": "wallet", + "action": "partial", + "user_id": 1, + "data": { + "usdt_balance": 1, + "usdt_available": 1, + "xht_balance": 1, + "xht_available": 1, + "xmr_balance": 1, + "xmr_available": 1, + "btc_balance": 1, + "btc_available": 1, + "eth_balance": 1, + "eth_available": 1, + ..., + "updated_at": "2020-12-15T08:41:24.048Z" + }, + "time": 1608021684 + } + ``` + +- **order**: Websocket messages relating the the user's orders. + - The `status` of the order can be `new`, `pfilled`, `filled`, and `canceled`. + - The `action` of the data determines what caused it to happen. All three are explained below: + + - `partial`: All previous and current orders. Is the first order data received when connecting. Max: 50. Descending order. + + ```json + { + "topic": "order", + "action": "partial", + "user_id": 1, + "data": [ + { + "id": "7d3d9545-b7e6-4e7f-84a0-a39efa4cb173", + "side": "buy", + "symbol": "xht-usdt", + "type": "limit", + "size": 0.1, + "filled": 0, + "price": 1, + "stop": null, + "status": "new", + "fee": 0, + "fee_coin": "xht", + "meta": {}, + "fee_structure": { + "maker": 0.1, + "taker": 0.1 + }, + "created_at": "2020-11-30T07:45:43.819Z", + "created_by": 1 + }, + ... + ], + "time": 1608022610 + } + ``` + + - `insert`: When user's order is added. The status of the order can be either `new`, `pfilled`, or `filled`. + + ```json + { + "topic": "order", + "action": "insert", + "user_id": 1, + "symbol": "xht-usdt", + "data": [ + { + "id": "7d3d9545-b7e6-4e7f-84a0-a39efa4cb173", + "side": "buy", + "symbol": "xht-usdt", + "type": "limit", + "size": 0.1, + "filled": 0, + "price": 1, + "stop": null, + "status": "new", + "fee": 0, + "fee_coin": "xht", + "meta": {}, + "fee_structure": { + "maker": 0.1, + "taker": 0.1 + }, + "created_at": "2020-11-30T07:45:43.819Z", + "updated_at": "2020-12-15T08:56:45.066Z", + "created_by": 1 + }, + ... + ], + "time": 1608022610 + } + ``` + + - `update`: When user's order status is updated. Status can be `pfilled`, `filled`, and `canceled`. + + ```json + { + "topic": "order", + "action": "insert", + "user_id": 1, + "symbol": "xht-usdt", + "data": [ + { + "id": "7d3d9545-b7e6-4e7f-84a0-a39efa4cb173", + "side": "buy", + "symbol": "xht-usdt", + "type": "limit", + "size": 0.1, + "filled": 0, + "price": 1, + "stop": null, + "status": "new", + "fee": 0, + "fee_coin": "xht", + "meta": {}, + "fee_structure": { + "maker": 0.1, + "taker": 0.1 + }, + "created_at": "2020-11-30T07:45:43.819Z", + "updated_at": "2020-12-15T08:56:45.066Z", + "created_by": 1 + }, + ... + ], + "time": 1608022610 + } + ``` + +## Plugins + +The Kit plugins are handled within one file, `plugins.js`. The main libraries being used are: +- [eval v0.1.4](https://github.com/pierrec/node-eval) - Used to execute plugin scripts +- [Express v4.16.2](https://expressjs.com/en/api.html) + +### How it works + +The plugins are designed to be contained within their own process. They can be installed, updated, and uninstalled on the fly. Manipulating any plugin will not affect the actual API server. Plugins are stored in the database in the `Plugin` table. + +#### Plugin structure + +```json +{ + "version": 1, // Plugin version + "name": "string", // Name of plugin, must be unique + "author": "string", // Author of plugin + "bio": "string", // Plugin bio + "enabled": true, // Plugin enabled status + "description": "string", // Plugin description + "documentation": "string", // Plugin documentation. Will be in markdown format + "logo": "string", // URL of plugin logo + "icon": "string", // URL of plugin icon + "url": "string", // URL of plugin (where it can be found) + "meta": {}, // Variables that will be unique for each instance of this plugin + "prescript": { // Scripts to run before installing plugin + "run": "string", + "install": [] + }, + "postscript": { // Scripts to run before uninstalling plugin + "run": "string" + }, + "script": "string", // Plugin script to run after installation + "admin_view": "string", // Client code for admin panel + "web_view": "string" // Client code for web view +} +``` + +#### Meta +The meta object is for any unique values your plugin requires. For example, if you are building a plugin using AWS S3, you will need a way to input your AWS credentials. You can use the meta object to store this values so they will be accessable in your plugin. + +```javascript +{ + "meta": { + "key": "key", + "secret": "secret" + } +} +``` + +Meta values are stored in the script as `meta`. Our `meta` values can be accessed as follows: +```javascript +const { key, secret } = meta; +``` + +#### Libraries + +- The HollaEx Plugins can be developed using the installed libraries below. They are accessable in the script as the value in the parentheses. + + - HollaEx Tools Library (`toolsLib`) + - Express (`app`) + - Lodash (`lodash`) + - Express Validator (`expressValidator`) + - Winston logger `loggerPlugin` + - Multer (`multer`) + +If your plugin requires other libraries, add the `npm` library name to the `install` array in `prescript`. +```javascript +{ + "prescript": { + "install": ['npm-library'] + } +} +``` + +Installed libraries are stored in the script as `installedLibraries`. +```javascript +const npmLibrary = installedLibraries['npm-library']; +``` + + +#### Script +Scripts must be written in ES6+ becuase they will be minified before installation. If this minification fails, the installation will fail as well. The script is what runs after you install and enable the plugin. All endpoints created must start with the path `/plugins`. +```javascript +app.get('/plugins/say-hi', (req, res) => { + res.send('hi'); +}); +``` + +### Endpoints + +#### `GET /plugins` + - Will return paginated data of plugins installed on Kit + - Query parameters: + - `limit` + - `page` + - `search` - Get plugins with names that match this value +#### `POST /plugins` + - Installs a new plugin into the kit + - Only admins can access this + - Returns the newly created plugin and restarts plugin server if plugin is enabled + - Body values: + ```jsx + { + name: 'string', + script: 'string', + version: 'int', + description: 'string', + author: 'string', + enabled: 'boolean', + bio: 'string', //optional + documentation: 'string', //optional + icon: 'string', //optional + url: 'string', //optional + logo: 'string', //optional + admin_view: 'string', //optional + web_view: 'string', //optional + prescript: { //optional + install: 'array', + run: 'string' + }, + postscript: { //optional + run: 'string' + }, + meta: { //optional + ...any values + } + } + ``` +#### `PUT /plugins` + - Updates an existing plugin to a new version + - Returns the updated plugin and restarts plugin server if plugin in enabled + - Only admin can access this endpoint + - Body values: + ```jsx + { + name: 'string', + version: 'int', //Version must be different from the one already installed + script: 'string', + description: 'string', //optional + author: 'string', //optional + bio: 'string', //optional + documentation: 'string', //optional + icon: 'string', //optional + url: 'string', //optional + logo: 'string', //optional + admin_view: 'string', //optional + web_view: 'string', //optional + prescript: { //optional + install: 'array', + run: 'string' + }, + postscript: { //optional + run: 'string' + }, + meta: { //optional + ...any values + } + } + ``` +#### `DELETE /plugins` + - Uninstalls a plugin from the Kit and restarts the plugin server + - Returns Success message + - Only admins can access this + - Query parameters: + - `name` - name of the plugin to uninstall +#### `GET /plugins/enable` + - Will enable a plugin if disabled + - Only admin can access this endpoint + - Returns a success message and restarts plugin server + - Query parameters: + - `name` - name of plugin to enable +#### `GET /plugins/disable` + - Will disable a plugin if enabled + - Only admin can access this endpoint + - Returns a success message and restarts plugin server + - Query parameters: + - `name` - name of plugin to disable +#### `GET /plugins/script` + - Will return `name`, `version`, `script`, `prescript`, `postscript`, and `admin_view` for plugin + - Only admin can access this endpoint + - Query parameters: + - `name` - name of plugin +#### `GET /plugins/meta` + - Will return the meta values for the plugin + - Only admin can access this endpoint + - Returns `name`, `version`, and `meta` for plugin + - Query parameters: + - `name` - name of plugin +#### `PUT /plugins/meta` + - Update the meta object for a plugin. This meta object stores values used within a plugin + - Only admin can access this endpoint + - Returns a success message and restarts the plugin server + - Body values: + ```jsx + { + name: 'string', + meta: { + ...any values + // will only update values that are both in the original plugin meta + // and that are passed within this object. The meta object passed + // through this endpoint doesn't completely override the existing meta + } + } + ``` -Plugins diff --git a/server/api/swagger/swagger.yaml b/server/api/swagger/swagger.yaml index 0e6177991e..6ce3468a62 100644 --- a/server/api/swagger/swagger.yaml +++ b/server/api/swagger/swagger.yaml @@ -1,6 +1,6 @@ swagger: "2.0" info: - version: "2.0.4" + version: "2.0.5" title: HollaEx Kit host: api.hollaex.com basePath: /v2 @@ -955,7 +955,7 @@ paths: description: This will send a confirmation email to the email address on record, if activate OTP, it will require OTP as well. tags: - User - - Withdraw + - Withdrawal parameters: - name: data description: withdrawal information @@ -985,7 +985,7 @@ paths: description: confirm a withdrawal request tags: - User - - Withdraw + - Withdrawal parameters: - name: data description: Tansfer information diff --git a/server/app.js b/server/app.js index c68670dfc1..3fcd52ce33 100644 --- a/server/app.js +++ b/server/app.js @@ -2,12 +2,16 @@ const { createServer } = require('http'); var SwaggerExpress = require('swagger-express-mw'); +const swaggerUi = require('swagger-ui-express'); const morgan = require('morgan'); +var YAML = require('yamljs'); +var swaggerDoc = YAML.load('./api/swagger/swagger.yaml'); const { logEntryRequest, stream, logger } = require('./config/logger'); const { domainMiddleware, helmetMiddleware } = require('./config/middleware'); var app = require('express')(); const toolsLib = require('hollaex-tools-lib'); const { checkStatus } = require('./init'); +const { API_HOST, CUSTOM_CSS } = require('./constants'); checkStatus(); // listen through pubsub for configuration/init @@ -36,6 +40,33 @@ var config = { } }; +swaggerDoc.host = API_HOST; +if (process.env.NODE_ENV === 'production') { + swaggerDoc.schemes = ['https']; + Object.entries(swaggerDoc.paths).forEach(([path, pathContent], index) => { + Object.keys(pathContent).forEach((method) => { + if (method.indexOf('swagger') === -1) { + if (pathContent[method].hasOwnProperty('tags')) { + const tags = pathContent[method].tags; + const index = tags.findIndex((value) => value === 'Admin' || value === 'Notification'); + if (index > -1) { + delete pathContent[method]; + } + } + } + }); + }); +} + +var options = { + customCss: CUSTOM_CSS, + customSiteTitle: 'HollaEx Kit API Explorer', + customfavIcon: + 'https://rm-content.s3.amazonaws.com/5aead825bb456c005e2322dd/upload-c116da40-ebd2-11e8-9c84-e32cc39c32d1_57.png' +}; + +app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDoc, options)); + SwaggerExpress.create(config, function(err, swaggerExpress) { if (err) { throw err; } diff --git a/server/constants.js b/server/constants.js index 233a566846..38dac31ec4 100644 --- a/server/constants.js +++ b/server/constants.js @@ -54,10 +54,10 @@ subscriber.on('message', (channel, message) => { if (data.secrets) updateSecrets(data.secrets); break; case 'freezeUser': - updateFrozenUser(data, 'add'); + updateFrozenUser('add', data); break; case 'unfreezeUser': - updateFrozenUser(data, 'remove'); + updateFrozenUser('remove', data); break; case 'stop': resetAllConfig(); @@ -438,4 +438,29 @@ exports.VERIFY_STATUS = { REJECTED: 2, COMPLETED: 3 }; -// PLUGIN CONSTANTS END ------------------------------ to be moved \ No newline at end of file +// PLUGIN CONSTANTS END ------------------------------ to be moved + +exports.CUSTOM_CSS = ` + .topbar-wrapper img { + content:url('https://s3.ap-northeast-2.amazonaws.com/public-holla-images/bitholla/bitholla-white--01.png'); + height: 2rem; + } + .swagger-ui .opblock.opblock-get .opblock-summary-method { + background: blue; + } + .swagger-ui .btn.execute { + background-color: blue; + color: #fff; + border-color: blue; + } + .swagger-ui .btn.authorize { + color: blue; + border-color: blue; + } + .swagger-ui .btn.authorize svg { + fill: blue; + } + .models { + display: none !important; + } +`; diff --git a/server/db/seeders/20190825120350-add-status.js b/server/db/seeders/20190825120350-add-status.js index b2f452ca9e..a3f0f29a53 100644 --- a/server/db/seeders/20190825120350-add-status.js +++ b/server/db/seeders/20190825120350-add-status.js @@ -9,7 +9,6 @@ const { EMAILS_TIMEZONE, VALID_LANGUAGES, NEW_USER_DEFAULT_LANGUAGE, - SENDER_EMAIL, DEFAULT_THEME, NEW_USER_IS_ACTIVATED, SMTP_SERVER, @@ -19,7 +18,6 @@ const { SEND_EMAIL_TO_SUPPORT, ALLOWED_DOMAINS, CAPTCHA_SECRET_KEY, - ADMIN_EMAIL, CAPTCHA_SITE_KEY, ADMIN_WHITELIST_IP, ACTIVATION_CODE, @@ -106,8 +104,8 @@ module.exports = { emails: { timezone: EMAILS_TIMEZONE || '', send_email_to_support: (SEND_EMAIL_TO_SUPPORT && SEND_EMAIL_TO_SUPPORT === 'true') || false, - sender: SENDER_EMAIL || '', - audit: ADMIN_EMAIL || '' + sender: '', + audit: '' }, captcha: { secret_key: CAPTCHA_SECRET_KEY diff --git a/server/init.js b/server/init.js index d8d63acd9a..6404b6fe45 100644 --- a/server/init.js +++ b/server/init.js @@ -126,6 +126,9 @@ const checkStatus = () => { created_at: exchange.created_at, expiry: exchange.expiry, collateral_level: exchange.collateral_level, + type: exchange.type, + plan: exchange.plan, + period: exchange.period, status: true, initialized: status.initialized }; diff --git a/server/mail/strings/en.js b/server/mail/strings/en.js index 8ac6c86d39..036808893d 100644 --- a/server/mail/strings/en.js +++ b/server/mail/strings/en.js @@ -54,7 +54,7 @@ const WELCOME = { BODY: { 1: () => `Thank you for signing up to ${API_NAME()}.`, 2: (account, deposit) => ` - To being trading, you must first deposit cryptocurrency or fund money to your account. + To begin trading, you must first deposit cryptocurrency or fund money to your account. Please go to your ${account} and visit the ${deposit} page.`, 3: 'account', 4: 'deposit', diff --git a/server/package.json b/server/package.json index 67b37ac3b5..a003eace50 100644 --- a/server/package.json +++ b/server/package.json @@ -1,5 +1,5 @@ { - "version": "2.0.4", + "version": "2.0.5", "private": false, "description": "HollaEx Kit", "keywords": [ @@ -57,6 +57,7 @@ "request-promise": "4.2.2", "sequelize": "4.37.7", "swagger-express-mw": "0.1.0", + "swagger-ui-express": "4.0.7", "uglify-es": "3.3.9", "uuid": "3.2.1", "validator": "9.4.1", diff --git a/server/tools/dbs/checkConfig.js b/server/tools/dbs/checkConfig.js index 4ae7171bef..32e0d679e6 100644 --- a/server/tools/dbs/checkConfig.js +++ b/server/tools/dbs/checkConfig.js @@ -60,8 +60,8 @@ Status.findOne() emails: { timezone: existingSecrets.emails ? (existingSecrets.emails.timzeone || process.env.EMAILS_TIMEZONE || '') : (process.env.EMAILS_TIMEZONE || ''), send_email_to_support: existingSecrets.emails ? (existingSecrets.emails.send_email_to_support || (process.env.SEND_EMAIL_TO_SUPPORT && process.env.SEND_EMAIL_TO_SUPPORT === 'true') || false) : ((process.env.SEND_EMAIL_TO_SUPPORT && process.env.SEND_EMAIL_TO_SUPPORT === 'true') || false), - sender: existingSecrets.emails ? (existingSecrets.emails.sender || process.env.SENDER_EMAIL || '') : (process.env.SENDER_EMAIL || ''), - audit: existingSecrets.audit ? (existingSecrets.emails.audit || process.env.ADMIN_EMAIL || '') : (process.env.ADMIN_EMAIL || '') + sender: existingSecrets.emails ? (existingSecrets.emails.sender || '') : '', + audit: existingSecrets.emails ? (existingSecrets.emails.audit || '') : '' }, captcha: { secret_key: existingSecrets.captcha ? (existingSecrets.captcha.secret_key || process.env.CAPTCHA_SECRET_KEY) : process.env.CAPTCHA_SECRET_KEY @@ -70,7 +70,7 @@ Status.findOne() server: existingSecrets.smtp ? (existingSecrets.smtp.server || process.env.SMTP_SERVER || '') : (process.env.SMTP_SERVER || ''), port: existingSecrets.smtp ? (existingSecrets.smtp.port || process.env.SMTP_PORT || 587) : (process.env.SMTP_PORT || 587), user: existingSecrets.smtp ? (existingSecrets.smtp.user || process.env.SMTP_USER) : process.env.SMTP_USER, - password: existingSecrets.smtp ? (existingSecrets.smtp.password || process.env.SMTP_PASSWORD) : (process.env.SMTP_PASSWORD) + password: existingSecrets.smtp ? (existingSecrets.smtp.password || process.env.SMTP_PASSWORD) : process.env.SMTP_PASSWORD } }; diff --git a/server/tools/dbs/setConfig.js b/server/tools/dbs/setConfig.js index 215a2f0968..06aee02ca1 100644 --- a/server/tools/dbs/setConfig.js +++ b/server/tools/dbs/setConfig.js @@ -11,7 +11,6 @@ const { EMAILS_TIMEZONE, VALID_LANGUAGES, NEW_USER_DEFAULT_LANGUAGE, - SENDER_EMAIL, DEFAULT_THEME, NEW_USER_IS_ACTIVATED, SMTP_SERVER, @@ -21,7 +20,6 @@ const { SEND_EMAIL_TO_SUPPORT, ALLOWED_DOMAINS, CAPTCHA_SECRET_KEY, - ADMIN_EMAIL, CAPTCHA_SITE_KEY, ADMIN_WHITELIST_IP, NATIVE_CURRENCY @@ -78,8 +76,8 @@ const secrets = { emails: { timezone: EMAILS_TIMEZONE || '', send_email_to_support: (SEND_EMAIL_TO_SUPPORT && SEND_EMAIL_TO_SUPPORT === 'true') || false, - sender: SENDER_EMAIL || '', - audit: ADMIN_EMAIL || '' + sender: '', + audit: '' }, captcha: { secret_key: CAPTCHA_SECRET_KEY diff --git a/settings/configmap b/settings/configmap index 789ce6a754..8c8d50fd53 100644 --- a/settings/configmap +++ b/settings/configmap @@ -27,11 +27,11 @@ HOLLAEX_CONFIGMAP_API_HOST=http://localhost HOLLAEX_CONFIGMAP_USER_LEVEL_NUMBER=4 -HOLLAEX_CONFIGMAP_ADMIN_EMAIL=admin@bitholla.com +HOLLAEX_CONFIGMAP_ADMIN_EMAIL= HOLLAEX_CONFIGMAP_KYC_EMAIL= HOLLAEX_CONFIGMAP_SUPPORT_EMAIL=support@bitholla.com HOLLAEX_CONFIGMAP_SUPERVISOR_EMAIL= -HOLLAEX_CONFIGMAP_SENDER_EMAIL=$HOLLAEX_CONFIGMAP_SUPPORT_EMAIL +HOLLAEX_CONFIGMAP_SENDER_EMAIL= HOLLAEX_CONFIGMAP_NEW_USER_IS_ACTIVATED=true @@ -118,24 +118,24 @@ ENVIRONMENT_USER_HOLLAEX_CORE_IMAGE_VERSION=$ENVIRONMENT_DOCKER_IMAGE_VERSION ENVIRONMENT_USER_HOLLAEX_WEB_IMAGE_REGISTRY=bitholla/my-hollaex-web ENVIRONMENT_USER_HOLLAEX_WEB_IMAGE_VERSION=latest -ENVIRONMENT_KUBERNETES_API_CPU_LIMITS=200m +ENVIRONMENT_KUBERNETES_API_CPU_LIMITS=100m ENVIRONMENT_KUBERNETES_API_MEMORY_LIMITS=512Mi -ENVIRONMENT_KUBERNETES_API_CPU_REQUESTS=10m +ENVIRONMENT_KUBERNETES_API_CPU_REQUESTS=50m ENVIRONMENT_KUBERNETES_API_MEMORY_REQUESTS=512Mi -ENVIRONMENT_KUBERNETES_STREAM_CPU_LIMITS=200m +ENVIRONMENT_KUBERNETES_STREAM_CPU_LIMITS=100m ENVIRONMENT_KUBERNETES_STREAM_MEMORY_LIMITS=256Mi -ENVIRONMENT_KUBERNETES_STREAM_CPU_REQUESTS=10m -ENVIRONMENT_KUBERNETES_STREAM_MEMORY_REQUESTS=128Mi +ENVIRONMENT_KUBERNETES_STREAM_CPU_REQUESTS=50m +ENVIRONMENT_KUBERNETES_STREAM_MEMORY_REQUESTS=256Mi ENVIRONMENT_KUBERNETES_POSTGRESQL_CPU_LIMITS=100m -ENVIRONMENT_KUBERNETES_POSTGRESQL_MEMORY_LIMITS=200Mi -ENVIRONMENT_KUBERNETES_POSTGRESQL_CPU_REQUESTS=10m +ENVIRONMENT_KUBERNETES_POSTGRESQL_MEMORY_LIMITS=100Mi +ENVIRONMENT_KUBERNETES_POSTGRESQL_CPU_REQUESTS=100m ENVIRONMENT_KUBERNETES_POSTGRESQL_MEMORY_REQUESTS=100Mi ENVIRONMENT_KUBERNETES_REDIS_CPU_LIMITS=100m -ENVIRONMENT_KUBERNETES_REDIS_MEMORY_LIMITS=200Mi -ENVIRONMENT_KUBERNETES_REDIS_CPU_REQUESTS=10m +ENVIRONMENT_KUBERNETES_REDIS_MEMORY_LIMITS=100Mi +ENVIRONMENT_KUBERNETES_REDIS_CPU_REQUESTS=100m ENVIRONMENT_KUBERNETES_REDIS_MEMORY_REQUESTS=100Mi ENVIRONMENT_KUBERNETES_S3_BACKUP_CRONJOB_RULE='0 1 * * *' diff --git a/version b/version index 26e33797ac..b9d2bdfd65 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.0.4 \ No newline at end of file +2.0.5 \ No newline at end of file diff --git a/web/package.json b/web/package.json index 08d4cc18ba..2900f4a9d7 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "hollaex-kit", - "version": "2.0.4", + "version": "2.0.5", "private": true, "dependencies": { "@ant-design/compatible": "1.0.5", diff --git a/web/public/assets/icons/xlm-icon.svg b/web/public/assets/icons/xlm-icon.svg index e48fd929ab..c43b57ebcf 100644 --- a/web/public/assets/icons/xlm-icon.svg +++ b/web/public/assets/icons/xlm-icon.svg @@ -2,14 +2,10 @@ diff --git a/web/public/assets/images/terms_of_service_and_privacy_policy-tooltip.png b/web/public/assets/images/terms_of_service_and_privacy_policy-tooltip.png new file mode 100644 index 0000000000..136cff08bc Binary files /dev/null and b/web/public/assets/images/terms_of_service_and_privacy_policy-tooltip.png differ diff --git a/web/public/assets/images/user-email-unverified.svg b/web/public/assets/images/user-email-unverified.svg new file mode 100644 index 0000000000..003c7416df --- /dev/null +++ b/web/public/assets/images/user-email-unverified.svg @@ -0,0 +1,17 @@ + + + diff --git a/web/public/assets/images/user-email-verified.svg b/web/public/assets/images/user-email-verified.svg new file mode 100644 index 0000000000..0ba007fe78 --- /dev/null +++ b/web/public/assets/images/user-email-verified.svg @@ -0,0 +1,17 @@ + + + diff --git a/web/public/assets/images/user-email.svg b/web/public/assets/images/user-email.svg new file mode 100644 index 0000000000..c2ca44d0e0 --- /dev/null +++ b/web/public/assets/images/user-email.svg @@ -0,0 +1,9 @@ + + + diff --git a/web/public/favicon.ico b/web/public/favicon.ico index 18e346d5ef..950555a3df 100644 Binary files a/web/public/favicon.ico and b/web/public/favicon.ico differ diff --git a/web/src/actions/walletActions.js b/web/src/actions/walletActions.js index f98bb89721..0ab984835b 100644 --- a/web/src/actions/walletActions.js +++ b/web/src/actions/walletActions.js @@ -30,6 +30,7 @@ export const ACTION_KEYS = { const ENDPOINTS = { TRADES: '/user/trades', + ORDERS: '/orders', DEPOSITS: '/user/deposits', WITHDRAWALS: '/user/withdrawals', DEPOSIT_BANK: '/user/deposit/bank', @@ -211,7 +212,7 @@ export const getOrdersHistory = ({ return (dispatch) => { dispatch({ type: ACTION_KEYS.ORDER_HISTORY_PENDING, payload: { page } }); axios - .get(`${ENDPOINTS.TRADES}?${query}`) + .get(`${ENDPOINTS.ORDERS}?${query}`) .then((body) => { dispatch({ type: ACTION_KEYS.ORDER_HISTORY_FULFILLED, @@ -239,6 +240,9 @@ export const downloadUserTrades = (key) => { format: 'csv', }); let path = ENDPOINTS.TRADES; + if (key === 'orders') { + path = ENDPOINTS.ORDERS; + } if (key === 'deposit') { path = ENDPOINTS.DEPOSITS; } else if (key === 'withdrawal') { diff --git a/web/src/components/AdminForm/hoc.js b/web/src/components/AdminForm/hoc.js index b66f3ef998..f8deb3ddcc 100644 --- a/web/src/components/AdminForm/hoc.js +++ b/web/src/components/AdminForm/hoc.js @@ -17,6 +17,7 @@ const Form = (name, className = '', allowPristine = false) => { small, buttonClass = '', submitOnKeyDown = false, + disableAllFields = false, }) => { return (