Commit 39eb02cbbb8cb5105639e5a30a5d6380a61e7115

Authored by Ábner Silva de Oliveira
2 parents 7ecbf4b9 dd84c4ad

Merge branch 'api' of gitlab.com:participa/noosfero into api

lib/noosfero/api/helpers.rb
  1 +require 'grape'
  2 +
1 3 module Noosfero;
2 4  
3 5 module API
... ... @@ -37,6 +39,10 @@
37 39 @environment
38 40 end
39 41  
  42 + def logger
  43 + Noosfero::API::API.logger
  44 + end
  45 +
40 46 def limit
41 47 limit = params[:limit].to_i
42 48 limit = default_limit if limit <= 0
... ... @@ -202,20 +208,6 @@
202 208 attrs
203 209 end
204 210  
205   - def verify_recaptcha_v2(remote_ip, g_recaptcha_response, private_key, api_recaptcha_verify_uri)
206   - verify_hash = {
207   - "secret" => private_key,
208   - "remoteip" => remote_ip,
209   - "response" => g_recaptcha_response
210   - }
211   - uri = URI(api_recaptcha_verify_uri)
212   - https = Net::HTTP.new(uri.host, uri.port)
213   - https.use_ssl = true
214   - request = Net::HTTP::Post.new(uri.path)
215   - request.set_form_data(verify_hash)
216   - JSON.parse(https.request(request).body)
217   - end
218   -
219 211 ##########################################
220 212 # error helpers #
221 213 ##########################################
... ... @@ -251,8 +243,19 @@
251 243 render_api_error!(_('Method Not Allowed'), 405)
252 244 end
253 245  
254   - def render_api_error!(message, status)
255   - error!({'message' => message, :code => status}, status)
  246 + # javascript_console_message is supposed to be executed as console.log()
  247 + def render_api_error!(user_message, status, log_message = nil, javascript_console_message = nil)
  248 + message_hash = {'message' => user_message, :code => status}
  249 + message_hash[:javascript_console_message] = javascript_console_message if javascript_console_message.present?
  250 + log_msg = "#{status}, User message: #{user_message}"
  251 + log_msg = "#{log_message}, #{log_msg}" if log_message.present?
  252 + log_msg = "#{log_msg}, Javascript Console Message: #{javascript_console_message}" if javascript_console_message.present?
  253 + logger.error log_msg
  254 + if javascript_console_message.present?
  255 + error!(message_hash, status)
  256 + else
  257 + error!(user_message, status)
  258 + end
256 259 end
257 260  
258 261 def render_api_errors!(messages)
... ... @@ -319,10 +322,13 @@
319 322 def test_captcha(remote_ip, params, environment)
320 323 d = environment.api_captcha_settings
321 324 return true unless d[:enabled] == true
  325 + msg_icve = _('Internal captcha validation error')
  326 + msg_eacs = 'Environment api_captcha_settings'
  327 + s = 500
322 328  
323 329 if d[:provider] == 'google'
324   - raise ArgumentError, "Environment api_captcha_settings private_key not defined" if d[:private_key].nil?
325   - raise ArgumentError, "Environment api_captcha_settings version not defined" unless d[:version] == 1 || d[:version] == 2
  330 + return render_api_error!(msg_icve, s, nil, "#{msg_eacs} private_key not defined") if d[:private_key].nil?
  331 + return render_api_error!(msg_icve, s, nil, "#{msg_eacs} version not defined") unless d[:version] == 1 || d[:version] == 2
326 332 if d[:version] == 1
327 333 d[:verify_uri] ||= 'https://www.google.com/recaptcha/api/verify'
328 334 return verify_recaptcha_v1(remote_ip, d[:private_key], d[:verify_uri], params[:recaptcha_challenge_field], params[:recaptcha_response_field])
... ... @@ -333,15 +339,15 @@
333 339 end
334 340 end
335 341 if d[:provider] == 'serpro'
336   - raise ArgumentError, "Environment api_captcha_settings verify_uri not defined" if d[:verify_uri].nil?
  342 + return render_api_error!(msg_icve, s, nil, "#{msg_eacs} verify_uri not defined") if d[:verify_uri].nil?
337 343 return verify_serpro_captcha(d[:serpro_client_id], params[:txtToken_captcha_serpro_gov_br], params[:captcha_text], d[:verify_uri])
338 344 end
339   - raise ArgumentError, "Environment api_captcha_settings provider not defined"
  345 + return render_api_error!(msg_icve, s, nil, "#{msg_eacs} provider not defined")
340 346 end
341 347  
342 348 def verify_recaptcha_v1(remote_ip, private_key, api_recaptcha_verify_uri, recaptcha_challenge_field, recaptcha_response_field)
343 349 if recaptcha_challenge_field == nil || recaptcha_response_field == nil
344   - return _('Missing captcha data')
  350 + return render_api_error!(_('Captcha validation error'), 500, nil, _('Missing captcha data'))
345 351 end
346 352  
347 353 verify_hash = {
... ... @@ -358,19 +364,14 @@
358 364 begin
359 365 body = https.request(request).body
360 366 rescue Exception => e
361   - logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))
362   - logger.error e
363   - return _("Google recaptcha error: #{e.message}")
  367 + return render_api_error!(_('Internal captcha validation error'), 500, nil, "recaptcha error: #{e.message}")
364 368 end
365 369 body = JSON.parse(body)
366 370 body == "true\nsuccess" ? true : body
367 371 end
368 372  
369 373 def verify_recaptcha_v2(remote_ip, private_key, api_recaptcha_verify_uri, g_recaptcha_response)
370   - if g_recaptcha_response == nil
371   - return _('Missing captcha data')
372   - end
373   -
  374 + return render_api_error!(_('Captcha validation error'), 500, nil, _('Missing captcha data')) if g_recaptcha_response == nil
374 375 verify_hash = {
375 376 "secret" => private_key,
376 377 "remoteip" => remote_ip,
... ... @@ -384,17 +385,15 @@
384 385 begin
385 386 body = https.request(request).body
386 387 rescue Exception => e
387   - logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))
388   - logger.error e
389   - return _("Google recaptcha error: #{e.message}")
  388 + return render_api_error!(_('Internal captcha validation error'), 500, nil, "recaptcha error: #{e.message}")
390 389 end
391 390 captcha_result = JSON.parse(body)
392 391 captcha_result["success"] ? true : captcha_result
393 392 end
394 393  
395 394 def verify_serpro_captcha(client_id, token, captcha_text, verify_uri)
396   - return _('Missing Serpro Captcha token') if token == nil
397   - return _('Captcha text has not been filled') if captcha_text == nil
  395 + return render_api_error!(_("Error processing token validation"), 500, nil, "Missing Serpro's Captcha token") unless token
  396 + return render_api_error!(_('Captcha text has not been filled'), 403) unless captcha_text
398 397 uri = URI(verify_uri)
399 398 http = Net::HTTP.new(uri.host, uri.port)
400 399 request = Net::HTTP::Post.new(uri.path)
... ... @@ -403,13 +402,15 @@
403 402 begin
404 403 body = http.request(request).body
405 404 rescue Exception => e
406   - logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log"))
407   - logger.error e
408   - return _("Serpro captcha error: #{e.message}")
  405 + return render_api_error!(_('Internal captcha validation error'), 500, nil, "Serpro captcha error: #{e.message}")
409 406 end
410   - return _("Wrong captcha text, please try again") if body == 0
411   - return _("Token not found") if body == 2
412   - body == '1' ? true : body
  407 + return true if body == '1'
  408 + return render_api_error!(_("Internal captcha validation error"), 500, body, "Unable to reach Serpro's Captcha validation service") if body == "Activity timed out"
  409 + return render_api_error!(_("Wrong captcha text, please try again"), 403) if body == 0
  410 + return render_api_error!(_("Serpro's captcha token not found"), 500) if body == 2
  411 + return render_api_error!(_("No data sent to validation server or other serious problem"), 500) if body == -1
  412 + #Catches all errors at the end
  413 + return render_api_error!(_("Internal captcha validation error"), 500, nil, "Error validating Serpro's captcha #{body}")
413 414 end
414 415  
415 416 end
... ...
lib/noosfero/api/session.rb
... ... @@ -2,7 +2,6 @@ require &quot;uri&quot;
2 2  
3 3 module Noosfero
4 4 module API
5   -
6 5 class Session < Grape::API
7 6  
8 7 # Login to get token
... ... @@ -40,13 +39,9 @@ module Noosfero
40 39 unique_attributes! User, [:email, :login]
41 40 attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields
42 41 remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
43   -
44   - result = test_captcha(remote_ip, params, environment)
45   - unless result == true
46   - render_api_error!(result, 401)
47   - return
48   - end
49   -
  42 + # test_captcha will render_api_error! and exit in case of some problem
  43 + # this return is only improve the clarity of the execution path
  44 + return unless test_captcha(remote_ip, params, environment)
50 45 user = User.new(attrs)
51 46 if user.save
52 47 user.generate_private_token! if user.activated?
... ...
test/unit/api/helpers_test.rb
... ... @@ -113,7 +113,6 @@ class APIHelpersTest &lt; ActiveSupport::TestCase
113 113 p = fast_create(Profile)
114 114 a = fast_create(Article, :published => false, :profile_id => p.id)
115 115 fast_create(Article, :profile_id => p.id)
116   -
117 116 user.generate_private_token!
118 117 User.expects(:find_by_private_token).returns(user)
119 118 assert_equal 403, find_article(p.articles, a.id).last
... ... @@ -162,57 +161,6 @@ class APIHelpersTest &lt; ActiveSupport::TestCase
162 161 assert_nil make_conditions_with_parameter[:type]
163 162 end
164 163  
165   - should 'do not test captcha when there are no settings' do
166   - environment = Environment.new
167   - assert test_captcha("127.0.0.1", {}, environment)
168   - end
169   -
170   - should 'do not test captcha when captcha is disabled on settings' do
171   - environment = Environment.new
172   - environment.api_captcha_settings = {
173   - enabled: false,
174   - }
175   - assert test_captcha("127.0.0.1", {}, environment)
176   - end
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   -
204   - should 'fail display Serpro captcha' do
205   - environment = Environment.new
206   - environment.api_captcha_settings = {
207   - enabled: true,
208   - provider: 'serpro',
209   - serpro_client_id: '0000000000000000',
210   - verify_uri: 'http://localhost/api/verify',
211   - }
212   - params = {}
213   - params[:txtToken_captcha_serpro_gov_br] = '4324343'
214   - assert_equal test_captcha("127.0.0.1", params, environment), _('Captcha text has not been filled')
215   - end
216 164  
217 165 should 'render not_found if endpoint is unavailable' do
218 166 Noosfero::API::API.stubs(:endpoint_unavailable?).returns(true)
... ... @@ -232,11 +180,79 @@ class APIHelpersTest &lt; ActiveSupport::TestCase
232 180 #assert_equal 403, find_article(p.articles, a.id).last
233 181  
234 182 #assert_equals [article1, article2], present_articles
  183 + end
235 184  
  185 +###### Captcha tests ######
236 186  
237   - end
  187 +should 'do not test captcha when there are no settings' do
  188 + environment = Environment.new
  189 + assert test_captcha("127.0.0.1", {}, environment)
  190 +end
  191 +
  192 +should 'do not test captcha when captcha is disabled on settings' do
  193 + environment = Environment.new
  194 + environment.api_captcha_settings = {
  195 + enabled: false,
  196 + }
  197 + assert test_captcha("127.0.0.1", {}, environment)
  198 +end
  199 +
  200 +should 'fail display recaptcha v1' do
  201 + environment = Environment.new
  202 + environment.api_captcha_settings = {
  203 + enabled: true,
  204 + provider: 'google',
  205 + version: 1,
  206 + private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY',
  207 + public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-',
  208 + verify_uri: 'https://www.google.com/recaptcha/api/verify',
  209 + }
  210 + r = test_captcha('127.0.0.1', params, environment)
  211 + assert_equal(_("Missing captcha data"), r[0][:javascript_console_message])
  212 +end
238 213  
239   - should 'captcha serpro say name or service not known' do
  214 +should 'fail display recaptcha v2' do
  215 + environment = Environment.new
  216 + environment.api_captcha_settings = {
  217 + enabled: true,
  218 + provider: 'google',
  219 + version: 2,
  220 + private_key: '6LdsWAcTAAAAAB6maB_HalVyCc4asDAxPxloIMvY',
  221 + public_key: '6LdsWAcTAAAAAChTUUD6yu9fCDhdIZzNd7F53zf-',
  222 + verify_uri: 'https://www.google.com/recaptcha/api/siteverify',
  223 + }
  224 + r = test_captcha('127.0.0.1', params, environment)
  225 + assert_equal(_("Missing captcha data"), r[0][:javascript_console_message])
  226 +end
  227 +
  228 +should 'verify if user filled Serpro\' captcha text' do
  229 + environment = Environment.new
  230 + environment.api_captcha_settings = {
  231 + enabled: true,
  232 + provider: 'serpro',
  233 + serpro_client_id: '0000000000000000',
  234 + verify_uri: 'http://localhost/api/verify',
  235 + }
  236 + params = {}
  237 + params[:txtToken_captcha_serpro_gov_br] = '4324343'
  238 + assert_equal(_('Captcha text has not been filled'), test_captcha('127.0.0.1', params, environment)[0])
  239 +end
  240 +
  241 +should 'verify if Serpro\' captcha token has been sent' do
  242 + environment = Environment.new
  243 + environment.api_captcha_settings = {
  244 + enabled: true,
  245 + provider: 'serpro',
  246 + serpro_client_id: '0000000000000000',
  247 + verify_uri: 'http://localhost/api/verify',
  248 + }
  249 + params = {}
  250 + params[:captcha_text] = '4324343'
  251 + r = test_captcha('127.0.0.1', params, environment)
  252 + assert_equal(_("Missing Serpro's Captcha token"), r[0][:javascript_console_message])
  253 +end
  254 +
  255 +should 'captcha serpro say name or service not known' do
240 256 environment = Environment.new
241 257 environment.api_captcha_settings = {
242 258 enabled: true,
... ... @@ -247,11 +263,11 @@ class APIHelpersTest &lt; ActiveSupport::TestCase
247 263 params = {}
248 264 params[:txtToken_captcha_serpro_gov_br] = '4324343'
249 265 params[:captcha_text] = '4324343'
250   - logger = Logger.new(File.join(Rails.root, 'log', 'test_api.log'))
251   - stubs(:logger).returns(logger)
252   - assert_equal test_captcha('127.0.0.1', params, environment), 'Serpro captcha error: getaddrinfo: Name or service not known'
253   - end
  266 + r = test_captcha('127.0.0.1', params, environment)
  267 + assert_equal(_("Serpro captcha error: getaddrinfo: Name or service not known"), r[0][:javascript_console_message])
  268 +end
254 269  
  270 +###### END Captcha tests ######
255 271  
256 272 protected
257 273  
... ...
test/unit/api/session_test.rb
... ... @@ -52,7 +52,7 @@ class SessionTest &lt; ActiveSupport::TestCase
52 52 assert_equal 400, last_response.status
53 53 end
54 54  
55   - should 'detected error, Name or service not known, for Serpro Captcha communication' do
  55 + should 'detected error, Name or service not known, for Serpro captcha communication' do
56 56 environment = Environment.default
57 57 environment.api_captcha_settings = {
58 58 enabled: true,
... ... @@ -64,7 +64,8 @@ class SessionTest &lt; ActiveSupport::TestCase
64 64 params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com",
65 65 :txtToken_captcha_serpro_gov_br => '4324343', :captcha_text => '4030320'}
66 66 post "/api/v1/register?#{params.to_query}"
67   - assert_equal "Serpro captcha error: getaddrinfo: Name or service not known", JSON.parse(last_response.body)["message"]
  67 + message = JSON.parse(last_response.body)['javascript_console_message']
  68 + assert_equal "Serpro captcha error: getaddrinfo: Name or service not known", message
68 69 end
69 70  
70 71 # TODO: Add another test cases to check register situations
... ...