Coverage for /home/marco/Code/django-simple-captcha/captcha/helpers.py: 68.67%

71 statements  

« prev     ^ index     » next       coverage.py v7.6.5, created at 2024-11-15 09:22 +0100

1import random 

2 

3from django.urls import reverse 

4 

5from captcha.conf import settings 

6 

7 

8def math_challenge(): 

9 operators = ("+", "*", "-") 

10 operands = (random.randint(1, 10), random.randint(1, 10)) 

11 operator = random.choice(operators) 

12 if operands[0] < operands[1] and "-" == operator: 

13 operands = (operands[1], operands[0]) 

14 challenge = "%d%s%d" % (operands[0], operator, operands[1]) 

15 return ( 

16 "{}=".format(challenge.replace("*", settings.CAPTCHA_MATH_CHALLENGE_OPERATOR)), 

17 str(eval(challenge)), 

18 ) 

19 

20 

21def random_char_challenge(): 

22 chars, ret = "abcdefghijklmnopqrstuvwxyz", "" 

23 for i in range(settings.CAPTCHA_LENGTH): 

24 ret += random.choice(chars) 

25 return ret.upper(), ret 

26 

27 

28def unicode_challenge(): 

29 chars, ret = "äàáëéèïíîöóòüúù", "" 

30 for i in range(settings.CAPTCHA_LENGTH): 

31 ret += random.choice(chars) 

32 return ret.upper(), ret 

33 

34 

35def word_challenge(): 

36 fd = open(settings.CAPTCHA_WORDS_DICTIONARY, "r") 

37 lines = fd.readlines() 

38 fd.close() 

39 while True: 

40 word = random.choice(lines).strip() 

41 if ( 

42 len(word) >= settings.CAPTCHA_DICTIONARY_MIN_LENGTH 

43 and len(word) <= settings.CAPTCHA_DICTIONARY_MAX_LENGTH 

44 ): 

45 break 

46 return word.upper(), word.lower() 

47 

48 

49def huge_words_and_punctuation_challenge(): 

50 "Yay, undocumneted. Mostly used to test Issue 39 - http://code.google.com/p/django-simple-captcha/issues/detail?id=39" 

51 fd = open(settings.CAPTCHA_WORDS_DICTIONARY, "rb") 

52 lines = fd.readlines() 

53 fd.close() 

54 word = "" 

55 while True: 

56 word1 = random.choice(lines).strip() 

57 word2 = random.choice(lines).strip() 

58 punct = random.choice(settings.CAPTCHA_PUNCTUATION) 

59 word = "%s%s%s" % (word1, punct, word2) 

60 if ( 

61 len(word) >= settings.CAPTCHA_DICTIONARY_MIN_LENGTH 

62 and len(word) <= settings.CAPTCHA_DICTIONARY_MAX_LENGTH 

63 ): 

64 break 

65 return word.upper(), word.lower() 

66 

67 

68def noise_arcs(draw, image): 

69 size = image.size 

70 draw.arc([-20, -20, size[0], 20], 0, 295, fill=settings.CAPTCHA_FOREGROUND_COLOR) 

71 draw.line( 

72 [-20, 20, size[0] + 20, size[1] - 20], fill=settings.CAPTCHA_FOREGROUND_COLOR 

73 ) 

74 draw.line([-20, 0, size[0] + 20, size[1]], fill=settings.CAPTCHA_FOREGROUND_COLOR) 

75 return draw 

76 

77 

78def noise_dots(draw, image): 

79 size = image.size 

80 for p in range(int(size[0] * size[1] * 0.1)): 

81 draw.point( 

82 (random.randint(0, size[0]), random.randint(0, size[1])), 

83 fill=settings.CAPTCHA_FOREGROUND_COLOR, 

84 ) 

85 return draw 

86 

87 

88def noise_null(draw, image): 

89 return draw 

90 

91 

92def random_letter_color_challenge(idx, plaintext_captcha): 

93 # Generate colorful but balanced RGB values 

94 red = random.randint(64, 200) 

95 green = random.randint(64, 200) 

96 blue = random.randint(64, 200) 

97 

98 # Ensure at least one channel is higher to make it colorful 

99 channels = [red, green, blue] 

100 random.shuffle(channels) 

101 channels[0] = random.randint(150, 255) 

102 

103 # Format the color as a hex string 

104 return f"#{channels[0]:02X}{channels[1]:02X}{channels[2]:02X}" 

105 

106 

107def post_smooth(image): 

108 from PIL import ImageFilter 

109 

110 return image.filter(ImageFilter.SMOOTH) 

111 

112 

113def captcha_image_url(key): 

114 """Return url to image. Need for ajax refresh and, etc""" 

115 return reverse("captcha-image", args=[key]) 

116 

117 

118def captcha_audio_url(key): 

119 """Return url to image. Need for ajax refresh and, etc""" 

120 return reverse("captcha-audio", args=[key])