Initial commit

This commit is contained in:
Yaser
2026-08-13 19:50:53 +03:30
commit 38084458fe
879 changed files with 95198 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
module ActiveRecord
class Base
def self.inherited(child)
super
unless child == ActiveRecord::SchemaMigration
validates_lengths_from_database
end
end
end
end
Rails.configuration.database_support_json = \
ActiveRecord::Base.configurations[Rails.env]['support_json']
Rails.configuration.database_adapter = \
ActiveRecord::Base.configurations[Rails.env]['adapter']

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
require 'peatio/aml'
begin
if ENV['AML_BACKEND'].present?
require ENV['AML_BACKEND']
Peatio::AML.adapter = "#{ENV.fetch('AML_BACKEND').capitalize}".constantize.new
end
rescue StandardError, LoadError => e
Rails.logger.error { e.message }
end

View File

@@ -0,0 +1,8 @@
# Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do
# ApplicationController.renderer.defaults.merge!(
# http_host: 'example.org',
# https: false
# )
# end

View File

@@ -0,0 +1,10 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
# frozen_string_literal: true
class NilClass
def to_d
BigDecimal(0)
end
end

View File

@@ -0,0 +1,3 @@
Peatio::Blockchain.registry[:bitcoin] = Bitcoin::Blockchain
Peatio::Blockchain.registry[:geth] = Ethereum::Blockchain
Peatio::Blockchain.registry[:parity] = Ethereum::Blockchain

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
require 'peatio/app'
Peatio::App.define do |config|
config.set(:deposit_funds_locked, 'false', type: :bool)
config.set(:app_name, 'Dena')
config.set(:domain, 'Zagros.com')
end

View File

@@ -0,0 +1,25 @@
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.
# Valid options are :json, :marshal, and :hybrid.
Rails.application.config.action_dispatch.cookies_serializer = :json

View File

@@ -0,0 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
Date::DATE_FORMATS[:short] = '%m-%d'
Time::DATE_FORMATS[:default] = "%Y-%m-%d %H:%M:%S"

View File

@@ -0,0 +1,9 @@
# encoding: UTF-8
# frozen_string_literal: true
# Specifications are available in docs/specs/event_api.md.
require 'active_support/concern'
require 'active_support/lazy_load_hooks'
require 'amqp/event_api'
ActiveSupport.on_load(:active_record) { ActiveRecord::Base.include EventAPI::ActiveRecord::Extension }

View File

@@ -0,0 +1,39 @@
# encoding: UTF-8
# frozen_string_literal: true
def catch_and_report_exception(options = {})
begin
yield
nil
rescue options.fetch(:class) { StandardError } => e
report_exception(e)
e
end
end
# report_api_error sample output.
# With default Rails formatter:
# I, [2019-09-18T12:52:59.077389 #157366] INFO -- : {:message=>"Account balance is insufficient", :path=>"/api/v2/account/withdraws", :params=>{"uid"=>"ID20DA7496BB", "currency"=>"usd", "amount"=>0.1e3, "beneficiary_id"=>1, "otp"=>123456}}
#
# With JSONLogFormatter:
# {"message":"Account balance is insufficient","path":"/api/v2/account/withdraws","params":{"uid":"ID5DE7A981C4","currency":"usd","amount":"100.0","beneficiary_id":1,"otp":123456},"level":"INFO","time":"2019-09-18 12:54:36"}
def report_api_error(exception, request)
Rails.logger.info message: exception.message, path: request.path, params: request.params
end
def report_exception(exception, report_to_ets = true)
report_exception_to_screen(exception)
report_exception_to_ets(exception) if report_to_ets
end
def report_exception_to_screen(exception)
Rails.logger.error(exception.inspect)
Rails.logger.error(exception.backtrace.join("\n")) if exception.respond_to?(:backtrace)
end
def report_exception_to_ets(exception)
Raven.capture_exception(exception) if defined?(Raven)
rescue => ets_exception
report_exception(ets_exception, false)
end

View File

@@ -0,0 +1,7 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:otp]

View File

@@ -0,0 +1,22 @@
# encoding: UTF-8
# frozen_string_literal: true
# Make Grape support lambdas in «description» field.
require 'grape-swagger/doc_methods/parse_params'
require 'grape_entity/exposure/delegator_exposure'
class Grape::Entity::Exposure::Base
def documentation
@documentation.respond_to?(:call) ? @documentation.call : @documentation
end
end
class << GrapeSwagger::DocMethods::ParseParams
def document_description(settings)
description = settings[:desc].presence || settings[:description].presence
description = description.respond_to?(:call) ? description.call : description
description = '' unless description.kind_of?(String) && description.present?
@parsed_param[:description] = description
end
end

View File

@@ -0,0 +1,33 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym 'AML'
inflect.acronym 'API'
inflect.acronym 'AMQP'
inflect.acronym 'MQ'
inflect.acronym 'CORS'
inflect.acronym 'UI'
inflect.acronym 'UUID'
inflect.acronym 'CRUD'
inflect.acronym 'TID'
inflect.acronym 'OWHDWallet'
inflect.irregular 'cash', 'cash'
end

View File

@@ -0,0 +1,65 @@
# encoding: UTF-8
# frozen_string_literal: true
Rails.configuration.x.jwt_public_key =
if ENV['JWT_PUBLIC_KEY'].present?
key = OpenSSL::PKey.read(Base64.urlsafe_decode64(ENV['JWT_PUBLIC_KEY']))
raise ArgumentError, 'JWT_PUBLIC_KEY was set to private key, however it should be public.' if key.private?
key
end
::Rails.configuration.x.jwt_options = {
algorithm: ENV.fetch('JWT_ALGORITHM', 'RS256'),
verify_expiration: true,
verify_not_before: true,
iss: ENV['JWT_ISSUER'],
verify_iss: ENV['JWT_ISSUER'].present?,
verify_iat: true,
verify_jti: true,
aud: ENV['JWT_AUDIENCE'].to_s.split(',').reject(&:blank?),
verify_aud: ENV['JWT_AUDIENCE'].present?,
sub: 'session',
verify_sub: true,
}.compact.tap do |jwt_options|
leeway_options = {
leeway: ENV['JWT_DEFAULT_LEEWAY'],
iat_leeway: ENV['JWT_ISSUED_AT_LEEWAY'],
exp_leeway: ENV['JWT_EXPIRATION_LEEWAY'],
nbf_leeway: ENV['JWT_NOT_BEFORE_LEEWAY'],
}.compact.transform_values!(&:to_i)
jwt_options.merge!(leeway_options)
# Set algorithm to 'none' if public key was not provided.
# Since rack-jwt requires public_key for all algorithms except 'none'
# Also using empty public key doesn't make sense unless you use 'none' algorithm.
jwt_options[:algorithm] = 'none' if ::Rails.configuration.x.jwt_public_key.blank?
end
require 'yaml'
require 'openssl'
(YAML.load_file('config/management_api_v1.yml') || {}).deep_symbolize_keys.tap do |x|
x.fetch(:keychain).each do |id, key|
key = OpenSSL::PKey.read(Base64.urlsafe_decode64(key.fetch(:value)))
if key.private?
raise ArgumentError, 'keychain.' + id.to_s + ' was set to private key, ' \
'however it should be public (in config/management_api_v1.yml).'
end
x[:keychain][id][:value] = key
end
x.fetch(:scopes).values.each do |scope|
%i[permitted_signers mandatory_signers].each do |list|
scope[list] = scope.fetch(list, []).map(&:to_sym)
scope[list] = scope.fetch(list, []).map(&:to_sym)
if list == :mandatory_signers && scope[list].empty?
raise ArgumentError, 'scopes.' + scope.to_s + '.' + list.to_s + ' is empty, ' \
'however it should contain at least one value (in config/management_api_v1.yml).'
end
end
end
Rails.configuration.x.security_configuration = x
end

View File

@@ -0,0 +1,27 @@
# encoding: UTF-8
# frozen_string_literal: true
# Require JWT initializer to configure JWT key & options.
require_relative 'jwt'
require 'jwt/rack'
on_error = lambda do |_error|
message = 'jwt.decode_and_verify'
body = { errors: [message] }.to_json
headers = { 'Content-Type' => 'application/json', 'Content-Length' => body.bytesize.to_s }
[401, headers, [body]]
end
# TODO: Fixme in jwt-rack handle api/v2// as api/v2.
auth_args = {
secret: Rails.configuration.x.jwt_public_key,
options: Rails.configuration.x.jwt_options,
verify: Rails.configuration.x.jwt_public_key.present?,
exclude: %w(/api/v2/public /api/v2//public /api/v2/management /api/v2//management
/api/v2/swagger /api/v2//swagger /api/v2/admin/swagger /api/v2//admin/swagger
/api/v2/coinmarketcap /api/v2//coinmarketcap /api/v2/coingecko /api/v2//coingecko),
on_error: on_error
}
Rails.application.config.middleware.use JWT::Rack::Auth, auth_args

View File

@@ -0,0 +1,28 @@
# encoding: UTF-8
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 10
config.max_per_page = 1000
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
end
module KaminariCustomRoute
def page_url_for(page)
params = params_for(page).symbolize_keys
route = params.delete(:route)
if route
@template.send("#{route}_url", params)
else
@template.url_for(params)
end
end
end
Kaminari::Helpers::Tag.prepend KaminariCustomRoute

View File

@@ -0,0 +1,12 @@
# encoding: UTF-8
# frozen_string_literal: true
case ENV.fetch('MATCHING_ENGINE', 'peatio')
when 'finex'
Rails.logger.info { 'Use finex as third-party matching engine' }
Order::TYPES << 'post_only'
when 'peatio'
Rails.logger.info { 'Use default matching engine' }
end
Order::TYPES.freeze
Order.enumerize :ord_type, in: Order::TYPES, scope: true

View File

@@ -0,0 +1,21 @@
# encoding: UTF-8
# frozen_string_literal: true
%w[ deposit withdraw trading ].each do |ability|
var = "MINIMUM_MEMBER_LEVEL_FOR_#{ability.upcase}"
n = ENV[var]
if n.blank?
raise ArgumentError, "The variable #{var} is not set."
end
begin
Integer(n)
rescue ArgumentError
raise ArgumentError, "The value of #{var} (#{n.inspect}) is not a valid number."
end
if n.to_i < 0 || n.to_i > 99
raise ArgumentError, "The value of #{var} (#{n.inspect}) must be in range of [0, 99]."
end
end

View File

@@ -0,0 +1,7 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf

View File

@@ -0,0 +1,4 @@
# encoding: UTF-8
# frozen_string_literal: true
Mysql2::Client.default_query_options[:connect_flags] |= Mysql2::Client::MULTI_STATEMENTS

View File

@@ -0,0 +1,61 @@
# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 5.0, 5.1, 5.2 upgrade.
#
# Once upgraded flip defaults one by one to migrate to the new default.
#
# Read the Rails 5.0, 5.1, 5.2 release notes for more info on each option.
# Enable per-form CSRF tokens. Previous versions had false.
Rails.application.config.action_controller.per_form_csrf_tokens = false
# Enable origin-checking CSRF mitigation. Previous versions had false.
Rails.application.config.action_controller.forgery_protection_origin_check = false
# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
# Previous versions had false.
ActiveSupport.to_time_preserves_timezone = false
# Require `belongs_to` associations by default. Previous versions had false.
Rails.application.config.active_record.belongs_to_required_by_default = false
# Do not halt callback chains when a callback returns false. Previous versions had true.
# ActiveSupport.halt_callback_chains_on_return_false = true
# Make `form_with` generate non-remote forms.
Rails.application.config.action_view.form_with_generates_remote_forms = false
# Unknown asset fallback will return the path passed in when the given
# asset is not present in the asset pipeline.
# Rails.application.config.assets.unknown_asset_fallback = false
# Make Active Record use stable #cache_key alongside new #cache_version method.
# This is needed for recyclable cache keys.
# Rails.application.config.active_record.cache_versioning = true
# Use AES-256-GCM authenticated encryption for encrypted cookies.
# Also, embed cookie expiry in signed or encrypted cookies for increased security.
#
# This option is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 5.2.
#
# Existing cookies will be converted on read then written with the new scheme.
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true
# Use AES-256-GCM authenticated encryption as default cipher for encrypting messages
# instead of AES-256-CBC, when use_authenticated_message_encryption is set to true.
# Rails.application.config.active_support.use_authenticated_message_encryption = true
# Add default protection from forgery to ActionController::Base instead of in
# ApplicationController.
# Rails.application.config.action_controller.default_protect_from_forgery = true
# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
# 'f' after migrating old data.
# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
# Rails.application.config.active_support.use_sha1_digests = true
# Make `form_with` generate id attributes for any generated HTML tags.
# Rails.application.config.action_view.form_with_generates_ids = true

View File

@@ -0,0 +1,9 @@
# encoding: UTF-8
# frozen_string_literal: true
class Hash
def fetch!(key)
raise RuntimeError, "Required key #{key.inspect} is missing or is blank!" unless self[key].present?
self[key]
end
end

View File

@@ -0,0 +1,23 @@
# encoding: UTF-8
# frozen_string_literal: true
class Rack::Session::Redis
def set_session(env, session_id, new_session, options)
with_lock env, false do
with do |c|
new_options = if env['api_v2.session_lifetime']
x = ActionDispatch::Request::Session::Options.new \
options.instance_variable_get(:@by),
options.instance_variable_get(:@env),
options.instance_variable_get(:@delegate)
x[:expire_after] = env['api_v2.session_lifetime']
x
else
options
end
c.set(session_id, new_session, new_options)
end
session_id
end
end
end

View File

@@ -0,0 +1,3 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :disabled

View File

@@ -0,0 +1,12 @@
# encoding: UTF-8
# frozen_string_literal: true
class String
# Similar to how ActiveRecord does. See lib/active_record/type/decimal.rb
def to_d
str_decimal = delete_suffix('.')
return BigDecimal(0) if str_decimal.blank?
BigDecimal(str_decimal)
end
end

View File

@@ -0,0 +1,26 @@
# encoding: UTF-8
# frozen_string_literal: true
module Enumerize
class Attribute
def value_options(options = {})
values = if options.empty?
@values
else
raise ArgumentError, 'Options cannot have both :only and :except' if options[:only] && options[:except]
only = Array(options[:only]).map(&:to_s)
except = Array(options[:except]).map(&:to_s)
@values.reject do |value|
if options[:only]
!only.include?(value)
elsif options[:except]
except.include?(value)
end
end
end
values.map { |v| [v.text, v.value] }
end
end
end

View File

@@ -0,0 +1,12 @@
# frozen_string_literal: true
begin
types = YAML.load_file("#{Rails.root}/config/transfer_types.yml").symbolize_keys
deposit_types = Deposit::TRANSFER_TYPES.merge(types[:deposit])
withdraw_types = Withdraw::TRANSFER_TYPES.merge(types[:withdraw])
Deposit.enumerize :transfer_type, in: deposit_types
Withdraw.enumerize :transfer_type, in: withdraw_types
rescue StandardError => e
Deposit.enumerize :transfer_type, in: Deposit::TRANSFER_TYPES
Withdraw.enumerize :transfer_type, in: Withdraw::TRANSFER_TYPES
Rails.logger.error { e.message }
end

View File

@@ -0,0 +1 @@
ActiveRecord::Type.register(:uuid, UUID::Type)

View File

@@ -0,0 +1,3 @@
require 'peatio/upstream/opendax'
Peatio::Upstream.registry[:opendax] = Peatio::Upstream::Opendax

View File

@@ -0,0 +1,44 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'vault/totp'
require 'vault/rails'
Vault::Rails.configure do |config|
config.enabled = Rails.env.production?
config.address = ENV.fetch('VAULT_ADDR', 'http://127.0.0.1:8200')
config.token = ENV['VAULT_TOKEN']
config.ssl_verify = false
config.timeout = 60
config.application = ENV.fetch('VAULT_APP_NAME', 'peatio')
config.in_memory_warnings_enabled = false
end
if ENV['VAULT_TOKEN'].to_s != ''
def renew_process
token = Vault.auth_token.lookup(Vault.token)
time = token.data[:ttl] * (1 + rand) * 0.1
Rails.logger.debug '[VAULT] Token will renew in %.0f sec' % time
sleep(time)
Vault.auth_token.renew(token.data[:id])
Rails.logger.info '[VAULT] Token renewed'
end
token = Vault.auth_token.lookup(Vault.token)
if token.data[:renewable]
Rails.logger.info '[VAULT] Starting token renew thread'
Thread.new do
loop do
renew_process
rescue StandardError => e
report_exception(e)
sleep 60
end
end
else
Rails.logger.info '[VAULT] Token is not renewable'
end
else
Rails.logger.warn 'Environment variable VAULT_TOKEN is missing'
end

View File

@@ -0,0 +1,13 @@
# encoding: UTF-8
# frozen_string_literal: true
# This file is auto-generated from the current state of VCS.
# Instead of editing this file, please use bin/gendocs.
module Peatio
class Application
GIT_TAG = '2.6.0'
GIT_SHA = '66aceba'
BUILD_DATE = '2019-11-07 11:43:58+00:00'
VERSION = GIT_TAG
end
end

View File

@@ -0,0 +1,7 @@
Peatio::Wallet.registry[:bitcoind] = Bitcoin::Wallet
Peatio::Wallet.registry[:geth] = Ethereum::Wallet
Peatio::Wallet.registry[:parity] = Ethereum::Wallet
Peatio::Wallet.registry[:gnosis] = Gnosis::Wallet
Peatio::Wallet.registry[:ow_hdwallet] = OWHDWallet::Wallet
Peatio::Wallet.registry[:opendax] = OWHDWallet::Wallet
Peatio::Wallet.registry[:opendax_cloud] = OpendaxCloud::Wallet

View File

@@ -0,0 +1,17 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end