prune_captcha 1.2.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- captcha_prune/__init__.py +1 -0
- captcha_prune/apps.py +13 -0
- captcha_prune/context_processors.py +12 -0
- captcha_prune/models.py +3 -1
- captcha_prune/utils.py +68 -0
- prune_captcha-1.4.0.dist-info/METADATA +144 -0
- {prune_captcha-1.2.0.dist-info → prune_captcha-1.4.0.dist-info}/RECORD +9 -8
- {prune_captcha-1.2.0.dist-info → prune_captcha-1.4.0.dist-info}/WHEEL +1 -1
- captcha_prune/start_server.py +0 -5
- prune_captcha-1.2.0.dist-info/METADATA +0 -91
- prune_captcha-1.2.0.dist-info/entry_points.txt +0 -2
- {prune_captcha-1.2.0.dist-info → prune_captcha-1.4.0.dist-info}/top_level.txt +0 -0
captcha_prune/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
default_app_config = "django_puzzle.apps.DjangoPuzzleConfig"
|
captcha_prune/apps.py
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
from django.apps import AppConfig
|
2
|
+
from django.conf import settings
|
3
|
+
from django.core.exceptions import ImproperlyConfigured
|
4
|
+
|
5
|
+
|
6
|
+
class DjangoPuzzleConfig(AppConfig):
|
7
|
+
name = "django_puzzle"
|
8
|
+
|
9
|
+
def ready(self):
|
10
|
+
if not hasattr(settings, "PUZZLE_IMAGE_STATIC_PATH"):
|
11
|
+
raise ImproperlyConfigured(
|
12
|
+
"django-puzzle: vous devez définir PUZZLE_IMAGE_STATIC_PATH dans settings.py"
|
13
|
+
)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from django.conf import settings
|
2
|
+
from django.core.exceptions import ImproperlyConfigured
|
3
|
+
|
4
|
+
|
5
|
+
def puzzle_static_path(request):
|
6
|
+
try:
|
7
|
+
path = settings.PUZZLE_IMAGE_STATIC_PATH
|
8
|
+
except AttributeError:
|
9
|
+
raise ImproperlyConfigured(
|
10
|
+
"Vous devez définir PUZZLE_IMAGE_STATIC_PATH dans votre settings.py"
|
11
|
+
)
|
12
|
+
return {"PUZZLE_IMAGE_STATIC_PATH": path}
|
captcha_prune/models.py
CHANGED
@@ -3,8 +3,10 @@ import uuid
|
|
3
3
|
|
4
4
|
from django.db import models
|
5
5
|
|
6
|
+
from commons.base_model import BaseModel
|
6
7
|
|
7
|
-
|
8
|
+
|
9
|
+
class Captcha(BaseModel):
|
8
10
|
uuid = models.UUIDField(default=uuid.uuid4, unique=True)
|
9
11
|
width = models.IntegerField(default=350)
|
10
12
|
height = models.IntegerField(default=200)
|
captcha_prune/utils.py
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
import os
|
2
|
+
import random
|
3
|
+
from urllib.parse import urlencode
|
4
|
+
|
5
|
+
import requests
|
6
|
+
from django.conf import settings
|
7
|
+
from django.contrib import messages
|
8
|
+
from django.http import HttpRequest, HttpResponse
|
9
|
+
from django.urls import reverse
|
10
|
+
|
11
|
+
|
12
|
+
def create_and_get_puzzle(request: HttpRequest) -> HttpResponse | dict:
|
13
|
+
puzzle_path = getattr(settings, "PUZZLE_IMAGE_STATIC_PATH", None)
|
14
|
+
try:
|
15
|
+
response = requests.post(
|
16
|
+
request.build_absolute_uri(reverse("captcha:create-captcha"))
|
17
|
+
).json()
|
18
|
+
except requests.RequestException:
|
19
|
+
return HttpResponse(status=502)
|
20
|
+
request.session["puzzle_uuid"] = response["uuid"]
|
21
|
+
puzzle_images = [
|
22
|
+
f
|
23
|
+
for f in os.listdir(puzzle_path)
|
24
|
+
if f.lower().endswith((".jpg", ".jpeg", ".png", ".gif"))
|
25
|
+
]
|
26
|
+
selected_image = random.choice(puzzle_images)
|
27
|
+
return {
|
28
|
+
"uuid": response["uuid"],
|
29
|
+
"width": response["width"],
|
30
|
+
"height": response["height"],
|
31
|
+
"piece_width": response["piece_width"],
|
32
|
+
"piece_height": response["piece_height"],
|
33
|
+
"pos_x_solution": response["pos_x_solution"],
|
34
|
+
"pos_y_solution": response["pos_y_solution"],
|
35
|
+
"piece_pos_x": response["piece_pos_x"],
|
36
|
+
"piece_pos_y": response["piece_pos_y"],
|
37
|
+
"image": selected_image,
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
def verify_captcha(
|
42
|
+
request: HttpRequest,
|
43
|
+
session_expired: HttpResponse,
|
44
|
+
incorrect_captcha: HttpResponse,
|
45
|
+
form,
|
46
|
+
) -> HttpResponse | None:
|
47
|
+
puzzle_uuid = request.session.get("puzzle_uuid")
|
48
|
+
if not puzzle_uuid:
|
49
|
+
messages.error(request, "La session a expiré.")
|
50
|
+
return session_expired
|
51
|
+
try:
|
52
|
+
base_url = request.build_absolute_uri(
|
53
|
+
reverse("captcha:verify-captcha", kwargs={"uuid": puzzle_uuid}),
|
54
|
+
)
|
55
|
+
data = {
|
56
|
+
"pos_x_answer": request.POST.get("pos_x_answer"),
|
57
|
+
"pos_y_answer": request.POST.get("pos_y_answer"),
|
58
|
+
}
|
59
|
+
query_string = urlencode(data)
|
60
|
+
full_url = f"{base_url}?{query_string}"
|
61
|
+
response = requests.get(full_url)
|
62
|
+
if response.status_code == 401:
|
63
|
+
messages.error(request, "Captcha incorrect. Veuillez réessayer.")
|
64
|
+
return incorrect_captcha
|
65
|
+
del form.fields["pos_x_answer"]
|
66
|
+
del form.fields["pos_y_answer"]
|
67
|
+
except requests.RequestException:
|
68
|
+
return HttpResponse(status=502)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: prune_captcha
|
3
|
+
Version: 1.4.0
|
4
|
+
Summary: A tool to protect formulaire from spam.
|
5
|
+
Author-email: Arnout <bastien@prune.sh>
|
6
|
+
Project-URL: Made_by, https://prune.sh/
|
7
|
+
Keywords: captcha,django,code-quality
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: <4.0,>=3.12
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: django>=5.2
|
14
|
+
Requires-Dist: psycopg2-binary>=2.9.10
|
15
|
+
Requires-Dist: pydantic>=2.11.4
|
16
|
+
Requires-Dist: pydantic-settings>=2.9.1
|
17
|
+
Requires-Dist: requests>=2.32.3
|
18
|
+
|
19
|
+
# Prune's Captcha
|
20
|
+
|
21
|
+
## What is it for?
|
22
|
+
|
23
|
+
Captcha helps prevent robots from spamming using your forms.
|
24
|
+
|
25
|
+
## Prerequisites
|
26
|
+
|
27
|
+
- To be installed on a Prune Django project that uses poetry or UV
|
28
|
+
|
29
|
+
## UV project
|
30
|
+
|
31
|
+
### Installation
|
32
|
+
|
33
|
+
Run the following command in the console:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
uv add captcha_prune
|
37
|
+
```
|
38
|
+
|
39
|
+
### Updating the captcha
|
40
|
+
|
41
|
+
Don't hesitate to regularly run `uv sync --upgrade`, as the captcha evolves with time and our practices!
|
42
|
+
|
43
|
+
## Poetry project
|
44
|
+
|
45
|
+
### Installation
|
46
|
+
|
47
|
+
Run the following command:
|
48
|
+
|
49
|
+
```bash
|
50
|
+
poetry add prune_captcha
|
51
|
+
```
|
52
|
+
|
53
|
+
### Updating the captcha
|
54
|
+
|
55
|
+
Don't hesitate to regularly run `poetry update`, as the captcha evolves with time and our practices!
|
56
|
+
|
57
|
+
## Captcha Integration
|
58
|
+
|
59
|
+
### Configuration
|
60
|
+
|
61
|
+
In `settings.py`, set the path to the images used for the puzzle:
|
62
|
+
|
63
|
+
```python
|
64
|
+
PUZZLE_IMAGE_STATIC_PATH = "website/images/"
|
65
|
+
```
|
66
|
+
|
67
|
+
### Utilisation
|
68
|
+
|
69
|
+
- GET request (form display)
|
70
|
+
|
71
|
+
- Use create_and_get_puzzle to generate the captcha data.
|
72
|
+
|
73
|
+
- Passes the data into the context under the puzzle variable.
|
74
|
+
|
75
|
+
- Include the component in your template:
|
76
|
+
|
77
|
+
```python
|
78
|
+
from captcha_prune.utils import create_and_get_puzzle
|
79
|
+
```
|
80
|
+
|
81
|
+
```
|
82
|
+
{% include "captcha_prune/components/captcha.html" %}
|
83
|
+
```
|
84
|
+
|
85
|
+
- POST request (form submission)
|
86
|
+
|
87
|
+
- Use verify_captcha to validate the captcha.
|
88
|
+
|
89
|
+
```python
|
90
|
+
from captcha_prune.utils import verify_captcha
|
91
|
+
```
|
92
|
+
|
93
|
+
```python
|
94
|
+
verify_captcha(request, redirect("/"), redirect("website:contact-page"), form)
|
95
|
+
```
|
96
|
+
|
97
|
+
- No feedback if the captcha is correct.
|
98
|
+
|
99
|
+
- Redirects in case of expired session or incorrect captcha.
|
100
|
+
|
101
|
+
### Example
|
102
|
+
|
103
|
+
```python
|
104
|
+
from django.shortcuts import render, redirect
|
105
|
+
|
106
|
+
from django.contrib import messages
|
107
|
+
from captcha_prune.utils import create_and_get_puzzle, verify_captcha
|
108
|
+
from .forms import ContactForm
|
109
|
+
|
110
|
+
def contact_view(request):
|
111
|
+
if request.method == "POST":
|
112
|
+
form = ContactForm(request.POST)
|
113
|
+
if form.is_valid():
|
114
|
+
verify_captcha(
|
115
|
+
request,
|
116
|
+
redirect("/"),
|
117
|
+
redirect("website:contact-page"),
|
118
|
+
form
|
119
|
+
)
|
120
|
+
messages.success(request, "Formulaire soumis avec succès.")
|
121
|
+
return redirect("/")
|
122
|
+
else:
|
123
|
+
puzzle = create_and_get_puzzle(request)
|
124
|
+
else:
|
125
|
+
form = ContactForm()
|
126
|
+
puzzle = create_and_get_puzzle(request)
|
127
|
+
return render(
|
128
|
+
request,
|
129
|
+
"website/pages/contact/page.html",
|
130
|
+
{"form": form, "puzzle": puzzle},
|
131
|
+
)
|
132
|
+
|
133
|
+
```
|
134
|
+
|
135
|
+
# Available Versions
|
136
|
+
|
137
|
+
| Version | Date | Notes |
|
138
|
+
| ------- | ---------- | ---------------------------------- |
|
139
|
+
| 1.4.0 | 2025-05-20 | added BaseModel in Captcha, ... |
|
140
|
+
| 1.3.0 | 2025-04-30 | deleted start_server, deleted ... |
|
141
|
+
| 1.2.0 | 2025-04-30 | fixed prune_captcha command, ... |
|
142
|
+
| 1.1.0 | 2025-04-30 | start_server was not a module, ... |
|
143
|
+
| 1.0.0 | 2025-04-29 | First version of the `captcha` ... |
|
144
|
+
```
|
@@ -1,10 +1,12 @@
|
|
1
|
-
captcha_prune/__init__.py,sha256=
|
1
|
+
captcha_prune/__init__.py,sha256=chKlxXsXZCpq_Ae-w6o8J0xR-oUimw8ECGuCLu7Ntu0,61
|
2
|
+
captcha_prune/apps.py,sha256=aBtviQsU3gIRCPeeJyVMAvjoza6oh34-NEWtB9klnvg,422
|
2
3
|
captcha_prune/asgi.py,sha256=wi2rRLFltXOZyve8mAB_E8udaFyONOf5N42WrWIQX8M,403
|
3
|
-
captcha_prune/
|
4
|
+
captcha_prune/context_processors.py,sha256=RTHgIxoje5n2wr1YvefbgUlvwNfiCe7Eyz9VKVoN4ZA,383
|
5
|
+
captcha_prune/models.py,sha256=O8nxhVfPat3oaDGZzd88kQHkGayQIWZ_dOO9uu1R6P4,1240
|
4
6
|
captcha_prune/payloads.py,sha256=PwR48xKg9YEgGgoJmGe7ywwFPCqM4gumomyFunn-Ems,115
|
5
7
|
captcha_prune/settings.py,sha256=YEZHEjYYYK-cH3gSLIR3a7g4Bypnuf_5eMTTcm719CE,3395
|
6
|
-
captcha_prune/start_server.py,sha256=-HBZ7IVfVM10yOT9cKY-_QSe_1k5wFFy_xCb9ouVJY8,89
|
7
8
|
captcha_prune/urls.py,sha256=DeCJTjJA0krW27KoHafvh3GBRr7fJ80E2lVHEWYSsW4,271
|
9
|
+
captcha_prune/utils.py,sha256=fInmwfuDWyR3oRfVYpeHUj2JfjvATZHMUcKQkTXKPD0,2351
|
8
10
|
captcha_prune/views.py,sha256=BzjQfXLwYx2YSWODrnGpokqU8XeC-9QORivzWKxYofY,1539
|
9
11
|
captcha_prune/wsgi.py,sha256=fukA_iiCT4FFzcJ0QX2Zr_HNddqdq-ln3ien2UWcCTA,403
|
10
12
|
captcha_prune/migrations/0001_initial.py,sha256=QMTaeSIxPociSrV4r89zfsbxMwMu4qpL16LT3yPgcaw,831
|
@@ -15,8 +17,7 @@ commons/decorators.py,sha256=nU_3SyxENcWDdxo03VyNYEvoevplC6ig7BFogY8apNs,1306
|
|
15
17
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
18
|
tests/captcha_prune/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
19
|
tests/captcha_prune/test_views.py,sha256=h-Mrdiprh71s7kIJPYAt6xv4G_S7vp51WCpAzy4CZ6U,2364
|
18
|
-
prune_captcha-1.
|
19
|
-
prune_captcha-1.
|
20
|
-
prune_captcha-1.
|
21
|
-
prune_captcha-1.
|
22
|
-
prune_captcha-1.2.0.dist-info/RECORD,,
|
20
|
+
prune_captcha-1.4.0.dist-info/METADATA,sha256=u2jmNK0J8rDB7fNs3a1LOHH_vT35hd6PnQEk5cyijx4,3745
|
21
|
+
prune_captcha-1.4.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
22
|
+
prune_captcha-1.4.0.dist-info/top_level.txt,sha256=EB4h0WF_YGF7kAWB0XtqmuloOhkL5pC71CzgEVYam7w,28
|
23
|
+
prune_captcha-1.4.0.dist-info/RECORD,,
|
captcha_prune/start_server.py
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: prune_captcha
|
3
|
-
Version: 1.2.0
|
4
|
-
Summary: A tool to protect formulaire from spam.
|
5
|
-
Author-email: Arnout <bastien@prune.sh>
|
6
|
-
Project-URL: Made_by, https://prune.sh/
|
7
|
-
Keywords: captcha,django,code-quality
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
10
|
-
Classifier: Operating System :: OS Independent
|
11
|
-
Requires-Python: <4.0,>=3.12
|
12
|
-
Description-Content-Type: text/markdown
|
13
|
-
Requires-Dist: django>=5.2
|
14
|
-
Requires-Dist: psycopg2-binary>=2.9.10
|
15
|
-
Requires-Dist: pydantic>=2.11.4
|
16
|
-
Requires-Dist: pydantic-settings>=2.9.1
|
17
|
-
|
18
|
-
# Prune's Captcha
|
19
|
-
|
20
|
-
## What is it for?
|
21
|
-
|
22
|
-
Captcha helps prevent robots from spamming using your forms.
|
23
|
-
|
24
|
-
## Prerequisites
|
25
|
-
|
26
|
-
- To be installed on a Prune Django project that uses poetry or UV
|
27
|
-
|
28
|
-
## UV project
|
29
|
-
|
30
|
-
### Installation
|
31
|
-
|
32
|
-
Run the following command in the console:
|
33
|
-
|
34
|
-
```bash
|
35
|
-
uv add captcha_prune
|
36
|
-
```
|
37
|
-
|
38
|
-
### Running the captcha
|
39
|
-
|
40
|
-
To run the package, simply enter in the console:
|
41
|
-
|
42
|
-
```bash
|
43
|
-
captcha_prune
|
44
|
-
```
|
45
|
-
|
46
|
-
### Updating the captcha
|
47
|
-
|
48
|
-
Don't hesitate to regularly run `uv sync --upgrade`, as the captcha evolves with time and our practices!
|
49
|
-
|
50
|
-
## Poetry project
|
51
|
-
|
52
|
-
### Installation
|
53
|
-
|
54
|
-
Run the following command:
|
55
|
-
|
56
|
-
```bash
|
57
|
-
poetry add prune_captcha
|
58
|
-
```
|
59
|
-
|
60
|
-
### Running the captcha
|
61
|
-
|
62
|
-
```bash
|
63
|
-
poetry run prune_captcha
|
64
|
-
```
|
65
|
-
|
66
|
-
### Updating the captcha
|
67
|
-
|
68
|
-
Don't hesitate to regularly run `poetry update`, as the captcha evolves with time and our practices!
|
69
|
-
|
70
|
-
## Captcha Integration
|
71
|
-
|
72
|
-
Once the project is launched, the application's URLs need to be linked to the form.
|
73
|
-
|
74
|
-
- When making a **GET** request to the form page, the API must be called via the **creation endpoint**. The response will contain the necessary information to display the captcha.
|
75
|
-
- When submitting the form via **POST**, the API must be called via the **verification endpoint**. The response will indicate whether the captcha is valid or not.
|
76
|
-
|
77
|
-
## Captcha Display
|
78
|
-
|
79
|
-
To display the captcha correctly, use the data received in the response from the creation request. This data includes:
|
80
|
-
|
81
|
-
- the captcha's width and height,
|
82
|
-
- the piece's width and height,
|
83
|
-
- the current position of the piece,
|
84
|
-
- the target position (where the piece should be placed),
|
85
|
-
- the expected precision (captcha difficulty level).
|
86
|
-
|
87
|
-
# Available Versions
|
88
|
-
|
89
|
-
| Version | Date | Notes |
|
90
|
-
| ------- | ---------- | -------------------------------------- |
|
91
|
-
| 1.0.0 | 2025-03-14 | First version of the `captcha` package |
|
File without changes
|