Module: ActiveHashcash

Extended by:
ActiveSupport::Concern
Defined in:
lib/active_hashcash.rb,
lib/active_hashcash/engine.rb,
lib/active_hashcash/version.rb,
app/models/active_hashcash/stamp.rb,
app/jobs/active_hashcash/application_job.rb,
app/helpers/active_hashcash/stamps_helper.rb,
app/helpers/active_hashcash/addresses_helper.rb,
app/models/active_hashcash/application_record.rb,
app/helpers/active_hashcash/application_helper.rb,
app/mailers/active_hashcash/application_mailer.rb,
app/controllers/active_hashcash/assets_controller.rb,
app/controllers/active_hashcash/stamps_controller.rb,
app/controllers/active_hashcash/addresses_controller.rb,
app/controllers/active_hashcash/application_controller.rb

Overview

ActiveHashcash protects Rails applications against bots and brute force attacks without annoying humans. See the rdoc-ref:README.md for more explanations about Hashcash.

Include this module into your Rails controller.

class SessionController < ApplicationController
include ActiveHashcash

before_action :check_hashcash, only: :create
end

Your are welcome to override most of the methods to customize to your needs. For example, if your app runs behind a loab balancer you should probably override #hashcash_ip_address.

Defined Under Namespace

Modules: AddressesHelper, ApplicationHelper, StampsHelper Classes: AddressesController, ApplicationController, ApplicationJob, ApplicationMailer, ApplicationRecord, AssetsController, Engine, Stamp, StampsController

Constant Summary collapse

VERSION =
"0.5.0"

Instance Method Summary collapse

Instance Method Details

#check_hashcashObject

Call that method via a before_action when the form is submitted:

before_action :check_hashcash, only: :create

In case of invalid hashcash it calls hashcash_after_failure that you can override. Otherwise, hashcash stamp is stored in database to prevent from double spending.



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/active_hashcash.rb', line 43

def check_hashcash
  attrs = {
    ip_address: hashcash_ip_address,
    request_path: hashcash_request_path,
    context: hashcash_stamp_context
  }
  if hashcash_param && Stamp.spend(hashcash_param, hashcash_resource, hashcash_bits, Date.yesterday, attrs)
    hashcash_after_success
  else
    hashcash_after_failure
  end
end

#hashcash_after_failureObject

That method is called when #check_hashcash fails. It raises ActionController::InvalidAuthenticityToken so HTTP response will be 422 by default. Override this method to provide a different behaviour.

Raises:

  • (ActionController::InvalidAuthenticityToken)


105
106
107
# File 'lib/active_hashcash.rb', line 105

def hashcash_after_failure
  raise ActionController::InvalidAuthenticityToken.new("Invalid hashcash #{hashcash_param}")
end

#hashcash_after_successObject

Maybe you want something special when the hashcash is valid. By default nothing happens.



110
111
112
# File 'lib/active_hashcash.rb', line 110

def hashcash_after_success
  # Override me for your own needs.
end

#hashcash_bitsObject

Returns the complexity, the higher the slower it is. Complexity is increased logarithmicly for each IP during the last 24H to slowdown brute force attacks. The minimun value returned is ActiveHashcash.bits.



84
85
86
87
88
89
90
# File 'lib/active_hashcash.rb', line 84

def hashcash_bits
  if (previous_stamp_count = ActiveHashcash::Stamp.where(ip_address: hashcash_ip_address).where(created_at: 1.day.ago..).count) > 0
    (ActiveHashcash.bits + Math.log2(previous_stamp_count)).floor
  else
    ActiveHashcash.bits
  end
end

#hashcash_hidden_field_tag(name = :hashcash) ⇒ Object

Call it inside the form that have to be protected and don't forget to initialize the JavaScript Hascash.setup(). Unless you need something really special, you should not need to override this method.

<% form_for model do |form| %>
<%= hashcash_hidden_field_tag %>

<% end %>


122
123
124
125
126
127
128
129
130
# File 'lib/active_hashcash.rb', line 122

def hashcash_hidden_field_tag(name = :hashcash)
  options = {
    resource: hashcash_resource,
    bits: hashcash_bits,
    waiting_message: hashcash_waiting_message,
    date: Date.today.strftime("%y%m%d")
  }
  view_context.hidden_field_tag(name, "", "data-hashcash" => options.to_json)
end

#hashcash_ip_addressObject

Returns remote IP address. They are used to automatically increase complexity when the same IP sends many valid hashcash. If you're app is behind a load balancer, you should probably override it to read the right HTTP header.



59
60
61
# File 'lib/active_hashcash.rb', line 59

def hashcash_ip_address
  request.remote_ip
end

#hashcash_paramObject

Override if you want to rename the hashcash param.



93
94
95
# File 'lib/active_hashcash.rb', line 93

def hashcash_param
  params[:hashcash]
end

#hashcash_request_pathObject

Return current request path to be saved to the sucessful ActiveHash::Stamp. If multiple forms are protected via hashcash this is an interesting info.



65
66
67
# File 'lib/active_hashcash.rb', line 65

def hashcash_request_path
  request.path
end

#hashcash_resourceObject

This is the resource used to build the hashcash stamp. By default the host name is returned. It' should be good for most cases and prevent from reusing the same stamp between sites.



77
78
79
# File 'lib/active_hashcash.rb', line 77

def hashcash_resource
  ActiveHashcash.resource || request.host
end

#hashcash_stamp_contextObject

Override this method to store custom data for each stamp. It must returns a hash or nil.



71
72
# File 'lib/active_hashcash.rb', line 71

def hashcash_stamp_context
end

#hashcash_waiting_messageObject

Override to customize message displayed on submit button while computing hashcash.



98
99
100
# File 'lib/active_hashcash.rb', line 98

def hashcash_waiting_message
  t("active_hashcash.waiting_label")
end