Commit c4d1dd86e0e1ef06d8a085bc4cf87ac7423f27fd
Exists in
staging
and in
7 other branches
Merge branch 'api' into production
Conflicts: test/fixtures/article_followers.yml
Showing
7 changed files
with
107 additions
and
69 deletions
Show diff stats
app/models/environment.rb
@@ -326,6 +326,9 @@ class Environment < ActiveRecord::Base | @@ -326,6 +326,9 @@ class Environment < ActiveRecord::Base | ||
326 | 326 | ||
327 | settings_items :signup_welcome_screen_body, :type => String | 327 | settings_items :signup_welcome_screen_body, :type => String |
328 | 328 | ||
329 | + #Captcha setings | ||
330 | + settings_items :api_captcha_settings, :type => ActiveSupport::HashWithIndifferentAccess, :default => {} | ||
331 | + | ||
329 | def has_custom_welcome_screen? | 332 | def has_custom_welcome_screen? |
330 | settings[:signup_welcome_screen_body].present? | 333 | settings[:signup_welcome_screen_body].present? |
331 | end | 334 | end |
app/models/user.rb
@@ -129,7 +129,8 @@ class User < ActiveRecord::Base | @@ -129,7 +129,8 @@ class User < ActiveRecord::Base | ||
129 | end | 129 | end |
130 | 130 | ||
131 | #FIXME make this test | 131 | #FIXME make this test |
132 | - def private_token_expired? | 132 | + def private_token_expired? |
133 | + return true if self.private_token_generated_at.nil? | ||
133 | self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now) | 134 | self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now) |
134 | end | 135 | end |
135 | 136 | ||
@@ -357,19 +358,6 @@ class User < ActiveRecord::Base | @@ -357,19 +358,6 @@ class User < ActiveRecord::Base | ||
357 | @is_password_required = false | 358 | @is_password_required = false |
358 | end | 359 | end |
359 | 360 | ||
360 | - #FIXME make this test | ||
361 | - def generate_private_token! | ||
362 | - self.private_token = SecureRandom.hex | ||
363 | - self.private_token_generated_at = DateTime.now | ||
364 | - save(:validate => false) | ||
365 | - end | ||
366 | - | ||
367 | - #FIXME make this test | ||
368 | - def private_token_expired? | ||
369 | - self.generate_private_token! if self.private_token.nil? || (self.private_token_generated_at + 2.weeks < DateTime.now) | ||
370 | - end | ||
371 | - | ||
372 | - | ||
373 | protected | 361 | protected |
374 | 362 | ||
375 | def normalize_email | 363 | def normalize_email |
lib/noosfero/api/api.rb
1 | require 'grape' | 1 | require 'grape' |
2 | #require 'rack/contrib' | 2 | #require 'rack/contrib' |
3 | +Dir["#{Rails.root}/lib/noosfero/api/*.rb"].each {|file| require_dependency file unless file =~ /api\.rb/} | ||
3 | 4 | ||
4 | -Dir["#{Rails.root}/lib/noosfero/api/*.rb"].each {|file| require file unless file =~ /api\.rb/} | ||
5 | module Noosfero | 5 | module Noosfero |
6 | module API | 6 | module API |
7 | class API < Grape::API | 7 | class API < Grape::API |
@@ -12,6 +12,13 @@ module Noosfero | @@ -12,6 +12,13 @@ module Noosfero | ||
12 | use GrapeLogging::Middleware::RequestLogger, { logger: logger } | 12 | use GrapeLogging::Middleware::RequestLogger, { logger: logger } |
13 | 13 | ||
14 | rescue_from :all do |e| | 14 | rescue_from :all do |e| |
15 | + # Many brave warriors have fallen in the battle for fixing the API log | ||
16 | + # Please, don't remove these 2 lines until the API log problem has | ||
17 | + # been PROPERLY fixed by our savior!!! | ||
18 | + # Otherwise we will have no clue of what went wrong in the API | ||
19 | + puts "API error during processing: #{$!}" | ||
20 | + puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}" | ||
21 | + # Thanks! | ||
15 | logger.error e | 22 | logger.error e |
16 | end | 23 | end |
17 | 24 | ||
@@ -61,4 +68,4 @@ module Noosfero | @@ -61,4 +68,4 @@ module Noosfero | ||
61 | end | 68 | end |
62 | end | 69 | end |
63 | end | 70 | end |
64 | -end | 71 | -end |
72 | +end | ||
65 | \ No newline at end of file | 73 | \ No newline at end of file |
lib/noosfero/api/helpers.rb
@@ -4,6 +4,8 @@ | @@ -4,6 +4,8 @@ | ||
4 | PRIVATE_TOKEN_PARAM = :private_token | 4 | PRIVATE_TOKEN_PARAM = :private_token |
5 | ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type] | 5 | ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type] |
6 | 6 | ||
7 | + include SanitizeParams | ||
8 | + | ||
7 | def current_user | 9 | def current_user |
8 | private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s | 10 | private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s |
9 | @current_user ||= User.find_by_private_token(private_token) | 11 | @current_user ||= User.find_by_private_token(private_token) |
@@ -91,6 +93,7 @@ | @@ -91,6 +93,7 @@ | ||
91 | end | 93 | end |
92 | 94 | ||
93 | def authenticate! | 95 | def authenticate! |
96 | + | ||
94 | unauthorized! unless current_user | 97 | unauthorized! unless current_user |
95 | end | 98 | end |
96 | 99 | ||
@@ -207,39 +210,29 @@ | @@ -207,39 +210,29 @@ | ||
207 | # captcha_helpers # | 210 | # captcha_helpers # |
208 | ########################################## | 211 | ########################################## |
209 | 212 | ||
210 | - def test_captcha(remote_ip, params) | ||
211 | - return true unless API.NOOSFERO_CONF['api_captcha_enabled'] === true | ||
212 | - | ||
213 | - private_key = API.NOOSFERO_CONF['api_recaptcha_private_key'] | ||
214 | - if private_key == nil | ||
215 | - raise ArgumentError, "API.NOOSFERO_CONF['api_recaptcha_private_key'] not defined" | ||
216 | - end | ||
217 | - | ||
218 | - api_captcha_version = API.NOOSFERO_CONF['api_captcha_version'] | ||
219 | - unless api_captcha_version == 1 || api_captcha_version == 2 | ||
220 | - raise ArgumentError, "API.NOOSFERO_CONF['api_captcha_version'] not defined" | ||
221 | - end | ||
222 | - | ||
223 | - if api_captcha_version == 1 | ||
224 | - api_recaptcha_verify_uri = API.NOOSFERO_CONF['api_recaptcha_v1_verify_uri'] | ||
225 | - if api_recaptcha_verify_uri == nil | ||
226 | - raise ArgumentError, "API.NOOSFERO_CONF['api_recaptcha_v1_verify_uri'] not defined" | 213 | + def test_captcha(remote_ip, params, _environment = nil) |
214 | + environment ||= _environment | ||
215 | + d = environment.api_captcha_settings | ||
216 | + return true unless d[:enabled] == true | ||
217 | + | ||
218 | + if d[:provider] == 'google' | ||
219 | + raise ArgumentError, "Environment api_captcha_settings private_key not defined" if d[:private_key].nil? | ||
220 | + raise ArgumentError, "Environment api_captcha_settings version not defined" unless d[:version] == 1 || d[:version] == 2 | ||
221 | + raise ArgumentError, "Environment api_captcha_settings verify_uri not defined" if d[:verify_uri].nil? | ||
222 | + if d[:version] == 1 | ||
223 | + return verify_recaptcha_v1(remote_ip, d[:private_key], d[:verify_uri], params[:recaptcha_challenge_field], params[:recaptcha_response_field]) | ||
227 | end | 224 | end |
228 | - return verify_recaptcha_v1(remote_ip, private_key, api_recaptcha_verify_uri, params[:recaptcha_challenge_field], params[:recaptcha_response_field]) | ||
229 | - end | ||
230 | - | ||
231 | - if api_captcha_version == 2 | ||
232 | - api_recaptcha_verify_uri = API.NOOSFERO_CONF['api_recaptcha_v2_verify_uri'] | ||
233 | - if api_recaptcha_verify_uri == nil | ||
234 | - raise ArgumentError, "API.NOOSFERO_CONF['api_recaptcha_v2_verify_uri'] not defined" | 225 | + if d[:version] == 2 |
226 | + return verify_recaptcha_v2(remote_ip, d[:private_key], d[:verify_uri], params[:g_recaptcha_response]) | ||
235 | end | 227 | end |
236 | - return verify_recaptcha_v2(remote_ip, private_key, api_recaptcha_verify_uri, params[:g_recaptcha_response]) | ||
237 | end | 228 | end |
238 | 229 | ||
230 | + if d[:provider] == 'serpro' | ||
231 | + #TODO ADD SERPRO's CAPTCHA | ||
232 | + end | ||
239 | end | 233 | end |
240 | 234 | ||
241 | def verify_recaptcha_v1(remote_ip, private_key, api_recaptcha_verify_uri, recaptcha_challenge_field, recaptcha_response_field) | 235 | def verify_recaptcha_v1(remote_ip, private_key, api_recaptcha_verify_uri, recaptcha_challenge_field, recaptcha_response_field) |
242 | - | ||
243 | if recaptcha_challenge_field == nil || recaptcha_response_field == nil | 236 | if recaptcha_challenge_field == nil || recaptcha_response_field == nil |
244 | return _('Missing captcha data') | 237 | return _('Missing captcha data') |
245 | end | 238 | end |
lib/noosfero/api/session.rb
@@ -29,7 +29,7 @@ module Noosfero | @@ -29,7 +29,7 @@ module Noosfero | ||
29 | # password (required) - Password | 29 | # password (required) - Password |
30 | # login - login | 30 | # login - login |
31 | # Example Request: | 31 | # Example Request: |
32 | - # POST /register?email=some@mail.com&password=pas&login=some | 32 | + # POST /register?email=some@mail.com&password=pas&password_confirmation=pas&login=some |
33 | params do | 33 | params do |
34 | requires :email, type: String, desc: _("Email") | 34 | requires :email, type: String, desc: _("Email") |
35 | requires :login, type: String, desc: _("Login") | 35 | requires :login, type: String, desc: _("Login") |
lib/sanitize_params.rb
@@ -2,33 +2,40 @@ module SanitizeParams | @@ -2,33 +2,40 @@ module SanitizeParams | ||
2 | 2 | ||
3 | protected | 3 | protected |
4 | 4 | ||
5 | - # Check each request parameter for | ||
6 | - # improper HTML or Script tags | ||
7 | - def sanitize_params | ||
8 | - request.params.each { |k, v| | ||
9 | - if v.is_a?(String) | ||
10 | - params[k] = sanitize_param v | ||
11 | - elsif v.is_a?(Array) | ||
12 | - params[k] = sanitize_array v | ||
13 | - end | ||
14 | - } | ||
15 | - end | 5 | + # Check each request parameter for |
6 | + # improper HTML or Script tags | ||
7 | + def sanitize_params | ||
8 | + sanitize_params_hash(request.params) | ||
9 | + end | ||
16 | 10 | ||
17 | - # If the parameter was an array, | ||
18 | - # try to sanitize each element in the array | ||
19 | - def sanitize_array(array) | ||
20 | - array.map! { |e| | ||
21 | - if e.is_a?(String) | ||
22 | - sanitize_param e | ||
23 | - end | ||
24 | - } | ||
25 | - return array | ||
26 | - end | 11 | + # Given a params list sanitize all |
12 | + def sanitize_params_hash(params) | ||
13 | + params.each { |k, v| | ||
14 | + if v.is_a?(String) | ||
15 | + params[k] = sanitize_param v | ||
16 | + elsif v.is_a?(Array) | ||
17 | + params[k] = sanitize_array v | ||
18 | + elsif v.kind_of?(Hash) | ||
19 | + params[k] = sanitize_params_hash(v) | ||
20 | + end | ||
21 | + } | ||
22 | + end | ||
27 | 23 | ||
28 | - # Santitize a single value | ||
29 | - def sanitize_param(value) | ||
30 | - allowed_tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) | ||
31 | - ActionController::Base.helpers.sanitize(value, tags: allowed_tags, attributes: %w(href title)) | ||
32 | - end | 24 | + # If the parameter was an array, |
25 | + # try to sanitize each element in the array | ||
26 | + def sanitize_array(array) | ||
27 | + array.map! { |e| | ||
28 | + if e.is_a?(String) | ||
29 | + sanitize_param e | ||
30 | + end | ||
31 | + } | ||
32 | + return array | ||
33 | + end | ||
34 | + | ||
35 | + # Santitize a single value | ||
36 | + def sanitize_param(value) | ||
37 | + allowed_tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) | ||
38 | + ActionController::Base.helpers.sanitize(value, tags: allowed_tags, attributes: %w(href title)) | ||
39 | + end | ||
33 | 40 | ||
34 | end | 41 | end |
test/unit/api/helpers_test.rb
@@ -161,6 +161,46 @@ class APIHelpersTest < ActiveSupport::TestCase | @@ -161,6 +161,46 @@ class APIHelpersTest < ActiveSupport::TestCase | ||
161 | assert_nil make_conditions_with_parameter[:type] | 161 | assert_nil make_conditions_with_parameter[:type] |
162 | end | 162 | end |
163 | 163 | ||
164 | + should 'do not test captcha when there are no settings' do | ||
165 | + environment = Environment.new | ||
166 | + assert test_captcha("127.0.0.1", {}, environment) | ||
167 | + end | ||
168 | + | ||
169 | + should 'do not test captcha when captcha is disabled on settings' do | ||
170 | + environment = Environment.new | ||
171 | + environment.api_captcha_settings = { | ||
172 | + enabled: false, | ||
173 | + } | ||
174 | + assert test_captcha("127.0.0.1", {}, environment) | ||
175 | + end | ||
176 | + | ||
177 | + | ||
178 | + should 'fail display recaptcha v1' do | ||
179 | + environment = Environment.new | ||
180 | + environment.api_captcha_settings = { | ||
181 | + enabled: true, | ||
182 | + provider: 'google', | ||
183 | + version: 1, | ||
184 | + private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY', | ||
185 | + public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-', | ||
186 | + verify_uri: 'https://www.google.com/recaptcha/api/verify', | ||
187 | + } | ||
188 | + assert_equal test_captcha("127.0.0.1", {}, environment), "Missing captcha data" | ||
189 | + end | ||
190 | + | ||
191 | + should 'fail display recaptcha v2' do | ||
192 | + environment = Environment.new | ||
193 | + environment.api_captcha_settings = { | ||
194 | + enabled: true, | ||
195 | + provider: 'google', | ||
196 | + version: 2, | ||
197 | + private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY', | ||
198 | + public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-', | ||
199 | + verify_uri: 'https://www.google.com/recaptcha/api/siteverify', | ||
200 | + } | ||
201 | + assert_equal test_captcha("127.0.0.1", {}, environment), "Missing captcha data" | ||
202 | + end | ||
203 | + | ||
164 | protected | 204 | protected |
165 | 205 | ||
166 | def error!(info, status) | 206 | def error!(info, status) |