initial commit
This commit is contained in:
commit
caa37a5021
BIN
__pycache__/app.cpython-39.pyc
Normal file
BIN
__pycache__/app.cpython-39.pyc
Normal file
Binary file not shown.
44
app.py
Normal file
44
app.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from flask import Flask, render_template, request, make_response, redirect
|
||||||
|
from numpy import real
|
||||||
|
from freecaptcha import captcha
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
app = Flask(__name__, static_url_path='', static_folder='static',)
|
||||||
|
|
||||||
|
captcha_solutions = {}
|
||||||
|
captcha_solved = []
|
||||||
|
|
||||||
|
@app.route("/captcha", methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
# This means they just submitted a CAPTCHA
|
||||||
|
# We need to see if they got it right
|
||||||
|
incorrect_captcha = False
|
||||||
|
if request.method == 'POST':
|
||||||
|
captcha_quess = request.form.get('captcha', None)
|
||||||
|
captcha_cookie = request.cookies.get('freecaptcha_cookie')
|
||||||
|
real_answer = captcha_solutions.get(captcha_cookie, None)
|
||||||
|
if real_answer is not None:
|
||||||
|
if int(captcha_quess) == int(real_answer):
|
||||||
|
captcha_solved.append(captcha_cookie)
|
||||||
|
return redirect("/", code=302)
|
||||||
|
else:
|
||||||
|
incorrect_captcha = True
|
||||||
|
|
||||||
|
# Select an image
|
||||||
|
image_path = captcha.random_image()
|
||||||
|
|
||||||
|
# Generate list of rotated versions of image
|
||||||
|
# and save which one is correct
|
||||||
|
answer, options = captcha.captchafy(image_path)
|
||||||
|
|
||||||
|
# Provide the CAPTCHA options to the web page using the CAPTCHA
|
||||||
|
resp = make_response(render_template("index.html", captcha_options=options, incorrect_captcha=incorrect_captcha))
|
||||||
|
|
||||||
|
# Track this user with a cookie and store the correct answer
|
||||||
|
# by linking the cookie with the answer, we can check their answer
|
||||||
|
# later
|
||||||
|
freecaptcha_cookie = str(uuid.uuid4())
|
||||||
|
resp.set_cookie('freecaptcha_cookie', freecaptcha_cookie)
|
||||||
|
captcha_solutions[freecaptcha_cookie] = answer
|
||||||
|
|
||||||
|
return resp
|
0
freecaptcha/__init__.py
Normal file
0
freecaptcha/__init__.py
Normal file
BIN
freecaptcha/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
freecaptcha/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
freecaptcha/__pycache__/captcha.cpython-39.pyc
Normal file
BIN
freecaptcha/__pycache__/captcha.cpython-39.pyc
Normal file
Binary file not shown.
54
freecaptcha/captcha.py
Normal file
54
freecaptcha/captcha.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import random
|
||||||
|
import os
|
||||||
|
from PIL import Image
|
||||||
|
import base64
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
# Angles we'll rotate the original by
|
||||||
|
# when we create n rotations
|
||||||
|
def calculate_angles(n):
|
||||||
|
return list(range(0, 360, 360 // n))
|
||||||
|
|
||||||
|
def rotate_img(img_path, angle):
|
||||||
|
original_img = Image.open(img_path)
|
||||||
|
rotated = original_img.rotate(angle)
|
||||||
|
buffered = BytesIO()
|
||||||
|
rotated.save(buffered, format="PNG")
|
||||||
|
b64_rot = base64.b64encode(buffered.getvalue())
|
||||||
|
return b64_rot.decode("utf-8")
|
||||||
|
|
||||||
|
def captchafy(img_path, n=6):
|
||||||
|
angles = calculate_angles(n)
|
||||||
|
|
||||||
|
rotated_imgs = [
|
||||||
|
{
|
||||||
|
'original': False,
|
||||||
|
'image': rotate_img(img_path, angle)
|
||||||
|
} for angle in angles]
|
||||||
|
|
||||||
|
rotated_imgs[0]['original'] = True
|
||||||
|
|
||||||
|
random.shuffle(rotated_imgs)
|
||||||
|
|
||||||
|
correct_img = None
|
||||||
|
for index, img in enumerate(rotated_imgs):
|
||||||
|
if img['original']:
|
||||||
|
correct_img = index
|
||||||
|
|
||||||
|
return correct_img, [img['image'] for img in rotated_imgs]
|
||||||
|
|
||||||
|
def random_image(dir='images/'):
|
||||||
|
dir_contents = os.listdir(dir)
|
||||||
|
random_image = random.choice(dir_contents)
|
||||||
|
return dir + random_image
|
||||||
|
|
||||||
|
def resize_dir(size=150, dir='images/'):
|
||||||
|
for img_file in os.listdir(dir):
|
||||||
|
img = Image.open(dir + img_file)
|
||||||
|
width, height = img.size
|
||||||
|
print(width, height)
|
||||||
|
if not (width > size or height > size):
|
||||||
|
continue
|
||||||
|
|
||||||
|
img.thumbnail((size, size),Image.ANTIALIAS)
|
||||||
|
img.save(dir + img_file)
|
BIN
images/gnome.png
Normal file
BIN
images/gnome.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
72
static/freecaptcha.css
Normal file
72
static/freecaptcha.css
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 0fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
div > div {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HIDE RADIO */
|
||||||
|
[type=radio] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IMAGE STYLES */
|
||||||
|
[type=radio] + img {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CHECKED STYLES */
|
||||||
|
[type=radio]:checked + img {
|
||||||
|
outline: 2px solid black;
|
||||||
|
filter: brightness(120%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.isa_info, .isa_success, .isa_warning, .isa_error {
|
||||||
|
margin: 10px 0px;
|
||||||
|
padding:12px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.isa_info {
|
||||||
|
color: #00529B;
|
||||||
|
background-color: #BDE5F8;
|
||||||
|
}
|
||||||
|
.isa_success {
|
||||||
|
color: #4F8A10;
|
||||||
|
background-color: #DFF2BF;
|
||||||
|
}
|
||||||
|
.isa_warning {
|
||||||
|
color: #9F6000;
|
||||||
|
background-color: #FEEFB3;
|
||||||
|
}
|
||||||
|
.isa_error {
|
||||||
|
color: #D8000C;
|
||||||
|
background-color: #FFD2D2;
|
||||||
|
}
|
||||||
|
.isa_info i, .isa_success i, .isa_warning i, .isa_error i {
|
||||||
|
margin:10px 22px;
|
||||||
|
font-size:2em;
|
||||||
|
vertical-align:middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
width: fit-content;
|
||||||
|
/* To adjust the height as well */
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit] {
|
||||||
|
background-color: #4CAF50; /* Green */
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 15px 32px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
31
templates/index.html
Normal file
31
templates/index.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="freecaptcha.css">
|
||||||
|
<title>Tor Dev</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root">
|
||||||
|
{% if incorrect_captcha %}
|
||||||
|
<div class="isa_error">
|
||||||
|
<i class="fa fa-error"></i>
|
||||||
|
Wrong CAPTCHA, try again!
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<form method="POST">
|
||||||
|
<div class='grid'>
|
||||||
|
{% for captcha_image in captcha_options %}
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="captcha" value="{{ loop.index0 }}" checked>
|
||||||
|
<img src="data:image/png;base64,{{ captcha_image }}"></img>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<center><input type="submit" value="Submit"></input></center>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user