fix: replace secrets.randint with secure alternatives

This commit is contained in:
Mahdi Bahreini
2025-02-25 14:07:41 +00:00
parent d72573f349
commit 6e26be4f0b
2 changed files with 37 additions and 37 deletions

View File

@@ -13,7 +13,7 @@ import os
import copy
import wave
import struct
import random
import secrets
import operator
from functools import reduce
@@ -84,7 +84,7 @@ def create_noise(length: int, level: int = 4) -> bytearray:
adjust = 128 - int(level / 2)
i = 0
while i < length:
v = random.randint(0, 256)
v = secrets.randbelow(257)
noise[i] = v % level + adjust
i += 1
return noise
@@ -186,7 +186,7 @@ class AudioCaptcha:
:param length: the return string length.
"""
return random.sample(self.choices, length)
return [secrets.choice(self.choices) for _ in range(length)]
def load(self) -> None:
"""Load voice data into memory."""
@@ -203,27 +203,27 @@ class AudioCaptcha:
self._cache[name] = data
def _twist_pick(self, key: str) -> bytearray:
voice = random.choice(self._cache[key])
voice = secrets.choice(self._cache[key])
# random change speed
speed = random.randrange(90, 120) / 100.0
speed = (secrets.randbelow(31) + 90) / 100.0
voice = change_speed(voice, speed)
# random change sound
level = random.randrange(80, 120) / 100.0
level = (secrets.randbelow(41) + 80) / 100.0
voice = change_sound(voice, level)
return voice
def _noise_pick(self) -> bytearray:
key = random.choice(self.choices)
voice = random.choice(self._cache[key])
key = secrets.choice(self.choices)
voice = secrets.choice(self._cache[key])
voice = copy.copy(voice)
voice.reverse()
speed = random.randrange(8, 16) / 10.0
speed = (secrets.randbelow(9) + 8) / 10.0
voice = change_speed(voice, speed)
level = random.randrange(2, 6) / 10.0
level = (secrets.randbelow(5) + 2) / 10.0
voice = change_sound(voice, level)
return voice
@@ -234,7 +234,7 @@ class AudioCaptcha:
sound = self._noise_pick()
end = pos + len(sound) + 1
noise[pos:end] = mix_wave(sound, noise[pos:end])
pos = end + random.randint(0, int(WAVE_SAMPLE_RATE / 10))
pos = end + secrets.randbelow(int(WAVE_SAMPLE_RATE / 10) + 1)
return noise
def create_wave_body(self, chars: str) -> bytearray:
@@ -242,7 +242,7 @@ class AudioCaptcha:
inters: t.List[int] = []
for c in chars:
voices.append(self._twist_pick(c))
i = random.randint(WAVE_SAMPLE_RATE, WAVE_SAMPLE_RATE * 3)
i = secrets.randbelow(WAVE_SAMPLE_RATE * 3 - WAVE_SAMPLE_RATE + 1) + WAVE_SAMPLE_RATE
inters.append(i)
durations = map(lambda a: len(a), voices)

View File

@@ -8,7 +8,7 @@
from __future__ import annotations
import os
import random
import secrets
import typing as t
from PIL.Image import new as createImage, Image, Transform, Resampling
from PIL.ImageDraw import Draw, ImageDraw
@@ -80,13 +80,13 @@ class ImageCaptcha:
@staticmethod
def create_noise_curve(image: Image, color: ColorTuple) -> Image:
w, h = image.size
x1 = random.randint(0, int(w / 5))
x2 = random.randint(w - int(w / 5), w)
y1 = random.randint(int(h / 5), h - int(h / 5))
y2 = random.randint(y1, h - int(h / 5))
x1 = secrets.randbelow(int(w / 5) + 1)
x2 = secrets.randbelow(w - int(w / 5) + 1) + int(w / 5)
y1 = secrets.randbelow(h - 2 * int(h / 5) + 1) + int(h / 5)
y2 = secrets.randbelow(h - y1 - int(h / 5) + 1) + y1
points = [x1, y1, x2, y2]
end = random.randint(160, 200)
start = random.randint(0, 20)
end = secrets.randbelow(41) + 160
start = secrets.randbelow(21)
Draw(image).arc(points, start, end, fill=color)
return image
@@ -99,8 +99,8 @@ class ImageCaptcha:
draw = Draw(image)
w, h = image.size
while number:
x1 = random.randint(0, w)
y1 = random.randint(0, h)
x1 = secrets.randbelow(w + 1)
y1 = secrets.randbelow(h + 1)
draw.line(((x1, y1), (x1 - 1, y1 - 1)), fill=color, width=width)
number -= 1
return image
@@ -110,29 +110,29 @@ class ImageCaptcha:
c: str,
draw: ImageDraw,
color: ColorTuple) -> Image:
font = random.choice(self.truefonts)
font = secrets.choice(self.truefonts)
_, _, w, h = draw.multiline_textbbox((1, 1), c, font=font)
dx1 = random.randint(*self.character_offset_dx)
dy1 = random.randint(*self.character_offset_dy)
dx1 = secrets.randbelow(self.character_offset_dx[1] - self.character_offset_dx[0] + 1) + self.character_offset_dx[0]
dy1 = secrets.randbelow(self.character_offset_dy[1] - self.character_offset_dy[0] + 1) + self.character_offset_dy[0]
im = createImage('RGBA', (int(w) + dx1, int(h) + dy1))
Draw(im).text((dx1, dy1), c, font=font, fill=color)
# rotate
im = im.crop(im.getbbox())
im = im.rotate(
random.uniform(*self.character_rotate),
self.character_rotate[0] + (secrets.randbits(32) / (2**32)) * (self.character_rotate[1] - self.character_rotate[0]),
Resampling.BILINEAR,
expand=True,
)
# warp
dx2 = w * random.uniform(*self.character_warp_dx)
dy2 = h * random.uniform(*self.character_warp_dy)
x1 = int(random.uniform(-dx2, dx2))
y1 = int(random.uniform(-dy2, dy2))
x2 = int(random.uniform(-dx2, dx2))
y2 = int(random.uniform(-dy2, dy2))
dx2 = w * (secrets.randbits(32) / (2**32)) * (self.character_warp_dx[1] - self.character_warp_dx[0]) + self.character_warp_dx[0]
dy2 = h * (secrets.randbits(32) / (2**32)) * (self.character_warp_dy[1] - self.character_warp_dy[0]) + self.character_warp_dy[0]
x1 = int(secrets.randbits(32) / (2**32) * (dx2 - (-dx2)) + (-dx2))
y1 = int(secrets.randbits(32) / (2**32) * (dy2 - (-dy2)) + (-dy2))
x2 = int(secrets.randbits(32) / (2**32) * (dx2 - (-dx2)) + (-dx2))
y2 = int(secrets.randbits(32) / (2**32) * (dy2 - (-dy2)) + (-dy2))
w2 = w + abs(x1) + abs(x2)
h2 = h + abs(y1) + abs(y2)
data = (
@@ -163,7 +163,7 @@ class ImageCaptcha:
images: list[Image] = []
for c in chars:
if random.random() > self.word_space_probability:
if secrets.randbits(32) / (2**32) > self.word_space_probability:
images.append(self._draw_character(" ", draw, color))
images.append(self._draw_character(c, draw, color))
@@ -180,7 +180,7 @@ class ImageCaptcha:
w, h = im.size
mask = im.convert('L').point(self.lookup_table)
image.paste(im, (offset, int((self._height - h) / 2)), mask)
offset = offset + w + random.randint(-rand, 0)
offset = offset + w + (-secrets.randbelow(rand + 1))
if width > self._width:
image = image.resize((self._width, self._height))
@@ -197,7 +197,7 @@ class ImageCaptcha:
:param fg_color: foreground color of the text in rgba format (r,g,b,a).
"""
background = bg_color if bg_color else random_color(238, 255)
random_fg_color = random_color(10, 200, random.randint(220, 255))
random_fg_color = random_color(10, 200, secrets.randbelow(36) + 220)
color: ColorTuple = fg_color if fg_color else random_fg_color
im = self.create_captcha_image(chars, color, background)
@@ -241,9 +241,9 @@ def random_color(
start: int,
end: int,
opacity: int | None = None) -> ColorTuple:
red = random.randint(start, end)
green = random.randint(start, end)
blue = random.randint(start, end)
red = secrets.randbelow(end - start + 1) + start
green = secrets.randbelow(end - start + 1) + start
blue = secrets.randbelow(end - start + 1) + start
if opacity is None:
return red, green, blue
return red, green, blue, opacity