Browse Source

Add a form for submitting Signal CAPTCHA solutions

pull/721/head
Pēteris Caune 2 years ago
parent
commit
8d75f1adc3
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
  1. 1
      CHANGELOG.md
  2. 7
      hc/api/models.py
  3. 1
      hc/front/urls.py
  4. 34
      hc/front/views.py
  5. 44
      templates/front/signal_captcha.html

1
CHANGELOG.md

@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
### Improvements
- Upgrade to fido2 1.1.0 and simplify hc.lib.webauthn
- Add handling for ipv4address:port values in the X-Forwarded-For header (#714)
- Add a form for submitting Signal CAPTCHA solutions
## v2.4.1 - 2022-10-18

7
hc/api/models.py

@ -10,6 +10,7 @@ from datetime import datetime
from datetime import timedelta as td
from datetime import timezone
from typing import TypedDict
from urllib.parse import urlencode
from cronsim import CronSim
from django.conf import settings
@ -599,9 +600,15 @@ class Channel(models.Model):
subject = "Signal CAPTCHA proof required"
message = f"Challenge token: {challenge}"
hostname = socket.gethostname()
submit_url = settings.SITE_ROOT + reverse("hc-signal-captcha")
submit_url += urlencode({"host": hostname, "challenge": challenge})
html_message = f"""
On host <b>{hostname}</b>, run:<br>
<pre>manage.py submitchallenge {challenge} CAPTCHA-SOLUTION-HERE</pre><br>
<br>
Alternatively, submit CAPTCHA solution here: <br>
{submit_url}<br>
<br>
Message from Signal:<br>
<pre>{raw}</pre>
"""

1
hc/front/urls.py

@ -111,4 +111,5 @@ urlpatterns = [
path("docs/cron/", views.docs_cron, name="hc-docs-cron"),
path("docs/search/", views.docs_search, name="hc-docs-search"),
path("docs/<slug:doc>/", views.serve_doc, name="hc-serve-doc"),
path("signal_captcha/", views.signal_captcha, name="hc-signal-captcha"),
]

34
hc/front/views.py

@ -6,6 +6,7 @@ import os
import re
import sqlite3
import sys
import uuid
from collections import defaultdict
from datetime import timedelta as td
from secrets import token_urlsafe
@ -45,7 +46,7 @@ from hc.api.models import (
Notification,
Ping,
)
from hc.api.transports import Telegram, TransportError
from hc.api.transports import Signal, Telegram, TransportError
from hc.front import forms
from hc.front.decorators import require_setting
from hc.front.schemas import telegram_callback
@ -2277,4 +2278,35 @@ def add_gotify(request, code):
return render(request, "integrations/add_gotify.html", ctx)
@login_required
def signal_captcha(request: HttpRequest) -> HttpResponse:
if not request.user.is_superuser:
return HttpResponseForbidden()
ctx = {"challenge": request.GET.get("challenge", "")}
if request.method == "POST":
challenge = request.POST.get("challenge")
captcha = request.POST.get("captcha")
payload = {
"jsonrpc": "2.0",
"method": "submitRateLimitChallenge",
"params": {"challenge": str(challenge), "captcha": captcha},
"id": str(uuid.uuid4()),
}
payload_bytes = (json.dumps(payload) + "\n").encode()
for reply_bytes in Signal(None)._read_replies(payload_bytes):
try:
reply = json.loads(reply_bytes.decode())
except ValueError:
ctx["result"] = "submitRateLimitChallenge failed"
break
if reply.get("id") == payload["id"]:
ctx["result"] = reply_bytes.decode()
break
return render(request, "front/signal_captcha.html", ctx)
# Forks: add custom views after this line

44
templates/front/signal_captcha.html

@ -0,0 +1,44 @@
{% extends "base.html" %}
{% load compress static hc_extras %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1>Signal CAPTCHA</h1>
{% if result %}
<p>Result:</p>
<pre>{{ result }}</pre>
<hr />
{% endif %}
<p>
First, solve a CAPTCHA
<a href="https://signalcaptchas.org/challenge/generate.html" target="_blank">here</a>,
then paste it below:
</p>
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="captcha">Challenge</label>
<input
name="challenge"
required
class="form-control"
value="{{ challenge }}" />
</div>
<div class="form-group">
<label for="captcha">CAPTCHA</label>
<textarea
id="captcha"
name="captcha"
required
class="form-control"
rows="10"></textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
{% endblock %}
Loading…
Cancel
Save