Class: SpreeCmCommissioner::FraudCheck

Inherits:
Object
  • Object
show all
Includes:
Spree::ServiceModule::Base
Defined in:
app/services/spree_cm_commissioner/fraud_check.rb

Constant Summary collapse

DEFAULTS =
{
  'max_votes_per_minute_per_user' => 5,
  'max_votes_per_minute_per_ip' => 10,
  'max_accounts_per_device' => 3,
  'block_vpn' => false
}.freeze
RATE_WINDOW =

seconds

60
VPN_CACHE_TTL =

1 hour

3600

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(voting_session:, user:, params:, request:) ⇒ FraudCheck

Returns a new instance of FraudCheck.



29
30
31
32
33
34
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 29

def initialize(voting_session:, user:, params:, request:)
  @voting_session = voting_session
  @user = user
  @params = params
  @request = request
end

Instance Attribute Details

#paramsObject (readonly)

Returns the value of attribute params.



27
28
29
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 27

def params
  @params
end

#requestObject (readonly)

Returns the value of attribute request.



27
28
29
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 27

def request
  @request
end

#userObject (readonly)

Returns the value of attribute user.



27
28
29
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 27

def user
  @user
end

#voting_sessionObject (readonly)

Returns the value of attribute voting_session.



27
28
29
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 27

def voting_session
  @voting_session
end

Instance Method Details

#callObject



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/services/spree_cm_commissioner/fraud_check.rb', line 36

def call
  return success(nil) if fraud_config.blank?

  check_user_rate_limit!
  check_ip_rate_limit!
  
  check_vpn_block!

  success(nil)
rescue RuntimeError => e
  failure(nil, e.message)
rescue Redis::BaseError => e
  # Fail-open: a Redis outage should not take down voting entirely.
  # Log the error so it is visible in monitoring, but let the vote through.
  # If the policy should be fail-closed instead, replace the rescue body
  # with: failure(I18n.t('voting.errors.service_unavailable'))
  CmAppLogger.error(
    label: 'FraudCheck Redis error — failing open',
    data: {
      voting_session_id: voting_session.id,
      user_id: user&.id,
      error_class: e.class.name,
      error_message: e.message
    }
  )
  success(nil)
end