Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/flask_wtf/recaptcha/validators.py: 29%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

45 statements  

1import json 

2from urllib import request as http 

3from urllib.parse import urlencode 

4 

5from flask import current_app 

6from flask import request 

7from wtforms import ValidationError 

8 

9RECAPTCHA_VERIFY_SERVER_DEFAULT = "https://www.google.com/recaptcha/api/siteverify" 

10RECAPTCHA_ERROR_CODES = { 

11 "missing-input-secret": "The secret parameter is missing.", 

12 "invalid-input-secret": "The secret parameter is invalid or malformed.", 

13 "missing-input-response": "The response parameter is missing.", 

14 "invalid-input-response": "The response parameter is invalid or malformed.", 

15} 

16 

17 

18__all__ = ["Recaptcha"] 

19 

20 

21class Recaptcha: 

22 """Validates a ReCaptcha. 

23 

24 Verification is skipped and the field is considered valid whenever 

25 ``current_app.testing`` is ``True`` or ``RECAPTCHA_ENABLED`` is 

26 ``False``, so tests and offline development don't need a real 

27 reCAPTCHA token. 

28 

29 .. versionchanged:: 1.3.0 

30 Verification is also skipped when ``RECAPTCHA_ENABLED`` is 

31 ``False``. 

32 """ 

33 

34 def __init__(self, message=None): 

35 if message is None: 

36 message = RECAPTCHA_ERROR_CODES["missing-input-response"] 

37 self.message = message 

38 

39 def __call__(self, form, field): 

40 if current_app.testing or not current_app.config.get("RECAPTCHA_ENABLED", True): 

41 return True 

42 

43 if request.is_json: 

44 response = request.json.get("g-recaptcha-response", "") 

45 else: 

46 response = request.form.get("g-recaptcha-response", "") 

47 remote_ip = request.remote_addr 

48 

49 if not response: 

50 raise ValidationError(field.gettext(self.message)) 

51 

52 if not self._validate_recaptcha(response, remote_ip): 

53 field.recaptcha_error = "incorrect-captcha-sol" 

54 raise ValidationError(field.gettext(self.message)) 

55 

56 def _validate_recaptcha(self, response, remote_addr): 

57 """Performs the actual validation.""" 

58 try: 

59 private_key = current_app.config["RECAPTCHA_PRIVATE_KEY"] 

60 except KeyError: 

61 raise RuntimeError("No RECAPTCHA_PRIVATE_KEY config set") from None 

62 

63 verify_server = current_app.config.get("RECAPTCHA_VERIFY_SERVER") 

64 if not verify_server: 

65 verify_server = RECAPTCHA_VERIFY_SERVER_DEFAULT 

66 

67 data = urlencode( 

68 {"secret": private_key, "remoteip": remote_addr, "response": response} 

69 ) 

70 

71 http_response = http.urlopen(verify_server, data.encode("utf-8")) 

72 

73 if http_response.code != 200: 

74 return False 

75 

76 json_resp = json.loads(http_response.read()) 

77 

78 if json_resp["success"]: 

79 return True 

80 

81 for error in json_resp.get("error-codes", []): 

82 if error in RECAPTCHA_ERROR_CODES: 

83 raise ValidationError(RECAPTCHA_ERROR_CODES[error]) 

84 

85 return False