decidim-cdtb 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -65,17 +65,35 @@ To migrate from S3 to local storage, the identified steps will be:
65
65
  `bin/rake cache:clear`
66
66
  5. Restart the Rails server
67
67
 
68
- ### Detect spam
68
+ ### Spam & bots
69
69
 
70
- To detect spam in Decidim.
70
+ Spam and bots are daily menaces in the current Internet. Decidim is not an exception, and is affected by both security concerns and performance.
71
+
72
+ #### Bad bots and crawlers
73
+
74
+ Decidim is already bundled with Rack::Attack but it lacks some features like IP banning or throttling by forwarded IP (useful when Decidim is behind a proxy). CDTB by default enables Rack::Attack with these features.
75
+
76
+ Four ENV variables exist to configure its behaviour:
77
+
78
+ - CDTB_RACK_ATTACK_DISABLED: Set to 1 to disable CDTB's Rack:Attack.
79
+ - RACK_ATTACK_THROTTLE_LIMIT: The max. allowed number of requests during the period. Defaults to 30.
80
+ - RACK_ATTACK_THROTTLE_PERIOD: The period in seconds. Defaults to 60.
81
+ - RACK_ATTACK_BLOCKED_IPS: A comma separated list of blocked IPs or subnets (in the form 1.2.3.0/32).
82
+
83
+
84
+ Available rake tasks to help analize crawlers:
85
+
86
+ - `bin/rake cdtb:logs:num_rq_per_ip` Counts the number of requests for each IP in the logs. Accepts a logfile param, it must be in log/.
71
87
 
72
88
  #### Detect spam users
89
+
73
90
  Detects users susceptible of being spammers. It can run on all organizations or be scoped to a single organization by passing the organization ID as the rake task parameter.
74
91
 
75
92
  This rake task export a .csv with a list of all the searched users. A column indicates if each user is suspicious of being a spammer or not.
76
93
  The columns in the CSV are: "ID, "Is suspicious?", "Name", "Email", "Nickname", "Personal URL", "About"
77
94
 
78
95
  Examples:
96
+
79
97
  `bin/rake cdtb:spam:users[org_id]` --> find users in organization with an id.
80
98
  `bin/rake cdtb:spam:users` --> find all users in all organizations.
81
99
 
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless ENV["CDTB_RACK_ATTACK_DISABLED"].to_i.positive? || %w[development test].include?(Rails.env)
4
+ require "rack/attack"
5
+
6
+ limit= ENV.fetch("RACK_ATTACK_THROTTLE_LIMIT", 30)
7
+ period= ENV.fetch("RACK_ATTACK_THROTTLE_PERIOD", 60)
8
+ Rails.logger.info("Configuring Rack::Attack.throttle with limit: #{limit}, period: #{period}")
9
+ Rack::Attack.throttle("requests by (forwarded) ip", limit: limit.to_i, period: period.to_i) do |request|
10
+ # ignore requests to assets
11
+ next if request.path.start_with?("/rails/active_storage")
12
+
13
+ x_forwarded_for= request.get_header("HTTP_X_FORWARDED_FOR")
14
+ Rails.logger.info { ">>>>>>>>>>>>>>>>>>>> X-Forwarded-For: #{x_forwarded_for}" }
15
+ if x_forwarded_for.present?
16
+ ip= x_forwarded_for.split(":").first
17
+ ip
18
+ else
19
+ request.ip
20
+ end
21
+ end
22
+
23
+ if ENV["RACK_ATTACK_BLOCKED_IPS"].present?
24
+ ENV["RACK_ATTACK_BLOCKED_IPS"].split(",").each do |ip_or_subnet|
25
+ Rack::Attack.blocklist_ip(ip_or_subnet)
26
+ end
27
+ end
28
+ end
data/decidim-cdtb.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "A gem to help managing Decidim applications."
13
13
  spec.homepage = "https://github.com/CodiTramuntana/decidim-module-cdtb"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.7.5"
15
+ spec.required_ruby_version = ">= 3.0.7"
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = spec.homepage
@@ -35,4 +35,5 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  spec.add_development_dependency "decidim-dev", Decidim::Cdtb::DECIDIM_MIN_VERSION
37
37
  spec.add_development_dependency "faker"
38
+ spec.metadata["rubygems_mfa_required"] = "true"
38
39
  end
@@ -11,7 +11,7 @@ module Decidim
11
11
  # rubocop:disable Style/RedundantRegexpEscape
12
12
  URL_REGEX = %r{(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|
13
13
  www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|
14
- (?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})}.freeze
14
+ (?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})}
15
15
  # rubocop:enable Style/RedundantRegexpEscape
16
16
 
17
17
  def initialize(organization = nil)
@@ -40,7 +40,9 @@ module Decidim
40
40
  # rubocop:disable Metrics/AbcSize
41
41
  def do_execution(context)
42
42
  progress_bar = context[:progress_bar]
43
- CSV.open("spam_users.csv", "w") do |csv|
43
+ filename= "spam_users.csv"
44
+ filepath= Rails.env.test? ? "tmp/#{filename}" : filename
45
+ CSV.open(filepath, "w") do |csv|
44
46
  csv_headers = ["ID", "Is suspicious?", "Name", "Email", "Nickname", "Personal URL", "About",
45
47
  "Organization ID", "Organization Name"]
46
48
  csv << csv_headers
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Cdtb
5
- VERSION = "0.1.8"
6
- DECIDIM_MIN_VERSION = ">= 0.26.2"
5
+ VERSION = "0.2.0"
6
+ DECIDIM_MIN_VERSION = ">= 0.27.0"
7
7
  end
8
8
  end
@@ -97,8 +97,8 @@ namespace :cdtb do
97
97
  unconfirmed_email: nil,
98
98
  avatar: nil,
99
99
  extended_data: user_group.extended_data.merge({
100
- "phone": "123456789",
101
- "document_number":
100
+ phone: "123456789",
101
+ document_number:
102
102
  "document-#{user_group.id}"
103
103
  })
104
104
  )
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/cdtb/tasks"
4
+
5
+ namespace :cdtb do
6
+ namespace :verifications do
7
+ desc <<~EODESC
8
+ Lists the verifications handlers in the current Decidim application.
9
+ EODESC
10
+ task handlers: :environment do |_task, _args|
11
+ puts "Verification Handlers in this Decidim application:"
12
+ Decidim.authorization_handlers.each do |manifest|
13
+ attrs= if manifest.form.present?
14
+ manifest.form.constantize.attribute_set.to_a.map(&:name).excluding(:id, :user, :handler_name).join(", ")
15
+ else
16
+ "No form."
17
+ end
18
+ puts "- #{manifest.name}: (#{attrs})"
19
+ end
20
+ end
21
+
22
+ desc <<~EODESC
23
+ Returns the unique_id version of the given arguments for the given authorization handler.
24
+ Params:
25
+ - handler_name
26
+ - (optional) organization_id
27
+ - credential_1, credential_2, ...: in the form "id_document:00000000T", "birthdate:24/03/1977".
28
+ For example:
29
+ `bin/rake cdtb:verifications:to_unique_id[file_authorization_handler,id_document:00000000T,birthdate:01/01/2000]
30
+ `
31
+ EODESC
32
+ task :to_unique_id, [:handler_name] => :environment do |_task, args|
33
+ puts "Resolving #{args.handler_name} form class"
34
+ handler= find_handler_by_name(args.handler_name)
35
+ puts "Found handler with form class: #{handler.class}"
36
+
37
+ fill_handler_args(handler, args)
38
+
39
+ puts "unique_id: #{handler.unique_id}"
40
+ end
41
+
42
+ def find_handler_by_name(handler_name)
43
+ handler_class= Decidim::Verifications.find_workflow_manifest(handler_name).form
44
+ handler_class.constantize.new
45
+ end
46
+
47
+ def fill_handler_args(handler, args)
48
+ arguments= args.to_a[1..]
49
+ current_organization= if arguments.first.include?(":")
50
+ Decidim::Organization.first
51
+ else
52
+ Decidim::Organization.find(arguments.first)
53
+ end
54
+ handler.with_context(current_organization: current_organization)
55
+
56
+ credentials= arguments.map { |arg| arg.split(":") }
57
+ puts "Setting credentials: #{credentials}"
58
+ credentials.each do |attr, val|
59
+ handler.send("#{attr}=".to_sym, val)
60
+ end
61
+ end
62
+
63
+ desc <<~EODESC
64
+ Checks the given credentials against the specified verification handler. Params [handler_name,credential1,credential2,...]"
65
+ EODESC
66
+ task :census_check, [:handler_name] => :environment do |_task, args|
67
+ handler= find_handler_by_name(args.handler_name)
68
+ fill_handler_args(handler, args)
69
+ raise "This handler does not support Cdtb's verification_service" unless handler.respond_to?(:verification_service)
70
+
71
+ service= handler.verification_service
72
+ puts "Invoking #{service.class.name}..."
73
+ rs= service.send_request
74
+ puts "Response Ok?: #{service.rs_ok?}"
75
+ puts "RS: #{rs.body}"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :cdtb do
4
+ namespace :logs do
5
+ desc "Analize logs in Rails format. Counts the number of requests for each IP in the logs. Accepts a logfile param, it must be in log/."
6
+ task :num_rq_per_ip, [:logfile] do |_task, args|
7
+ logfile= args.logfile || "development.log"
8
+
9
+ file_path= "log/#{logfile}"
10
+ first_cmd= "grep Started"
11
+ piped_cmds= [%(grep " for "), "cut -d ' ' -f13", "sort", "uniq -c", "sort"].join(" | ")
12
+ puts "Running: `#{first_cmd} #{file_path} | #{piped_cmds}`"
13
+ puts `#{first_cmd} #{file_path} | #{piped_cmds}`
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-cdtb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Valls
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-24 00:00:00.000000000 Z
11
+ date: 2024-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: decidim
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.26.2
19
+ version: 0.27.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.26.2
26
+ version: 0.27.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.26.2
61
+ version: 0.27.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 0.26.2
68
+ version: 0.27.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: faker
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +100,7 @@ files:
100
100
  - Rakefile
101
101
  - app/jobs/application_job.rb
102
102
  - app/jobs/cdtb/fix_nickname_job.rb
103
+ - config/initializers/rack_attack.rb
103
104
  - decidim-cdtb.gemspec
104
105
  - lib/decidim/cdtb.rb
105
106
  - lib/decidim/cdtb/engine.rb
@@ -120,6 +121,8 @@ files:
120
121
  - lib/generators/cdtb/templates/validate_migrations.yml
121
122
  - lib/generators/cdtb/validate_migrations_ci_generator.rb
122
123
  - lib/tasks/anonymize.rake
124
+ - lib/tasks/census.rake
125
+ - lib/tasks/logs.rake
123
126
  - lib/tasks/multitenants.rake
124
127
  - lib/tasks/spam.rake
125
128
  - lib/tasks/storage.rake
@@ -133,6 +136,7 @@ metadata:
133
136
  homepage_uri: https://github.com/CodiTramuntana/decidim-module-cdtb
134
137
  source_code_uri: https://github.com/CodiTramuntana/decidim-module-cdtb
135
138
  changelog_uri: https://github.com/CodiTramuntana/decidim-module-cdtb/CHANGELOG.md
139
+ rubygems_mfa_required: 'true'
136
140
  post_install_message:
137
141
  rdoc_options: []
138
142
  require_paths:
@@ -141,14 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
141
145
  requirements:
142
146
  - - ">="
143
147
  - !ruby/object:Gem::Version
144
- version: 2.7.5
148
+ version: 3.0.7
145
149
  required_rubygems_version: !ruby/object:Gem::Requirement
146
150
  requirements:
147
151
  - - ">="
148
152
  - !ruby/object:Gem::Version
149
153
  version: '0'
150
154
  requirements: []
151
- rubygems_version: 3.1.6
155
+ rubygems_version: 3.2.33
152
156
  signing_key:
153
157
  specification_version: 4
154
158
  summary: CodiTramuntana's Decidim Toolbelt (cdtb).