Skip to content

Commit 35bd3de

Browse files
committed
require new users to commit to follow the groundrules
1 parent f0db0e5 commit 35bd3de

File tree

2 files changed

+164
-10
lines changed

2 files changed

+164
-10
lines changed

dojo_theme/templates/register.html

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{% extends "base.html" %}
22

3+
{% set commitment_text = "I have read the ground rules and commit to not publish pwn.college writeups on the internet." %}
4+
35
{% block content %}
46
<div class="jumbotron">
57
<div class="container">
@@ -22,10 +24,22 @@ <h3>Bug Bounties</h3>
2224
If you find a vulnerability in this platform, please <a href="mailto:pwn-college@asu.edu">email</a> us rather than pwn us.
2325
We'll appreciate it, and you'll get extra credit (if you're an ASU student) or an awesome scoreboard award!</p>
2426

27+
<div class="form-group" id="commitment-section">
28+
<div class="alert alert-warning">
29+
To register, please type the following commitment exactly as shown:
30+
<br><br>
31+
<strong id="commitment-text">{{ commitment_text }}</strong>
32+
</div>
33+
<input type="text" id="commitment-input" class="form-control" placeholder="Type the commitment above" autocomplete="off">
34+
<small class="form-text text-muted" id="commitment-feedback">
35+
Please type the commitment exactly as shown above to enable registration
36+
</small>
37+
</div>
38+
2539
<h2>Sign Up!</h2>
2640
{% with form = Forms.auth.RegistrationForm() %}
2741
{% from "macros/forms.html" import render_extra_fields %}
28-
<form method="post" accept-charset="utf-8" autocomplete="off" role="form">
42+
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" id="registration-form">
2943
<div class="form-group">
3044
<b>{{ form.name.label }}</b>
3145
{{ form.name(class="form-control", value=name) }}
@@ -47,13 +61,16 @@ <h2>Sign Up!</h2>
4761
Password used to log into your account
4862
</small>
4963
</div>
64+
5065
{{ form.nonce() }}
66+
67+
<input type="hidden" id="commitment-verified" name="commitment_verified" value="">
5168

5269
{{ render_extra_fields(form.extra) }}
5370

5471
<div class="row pt-3">
5572
<div class="col-md-12">
56-
{{ form.submit(class="btn btn-md btn-primary btn-outlined float-right") }}
73+
{{ form.submit(class="btn btn-md btn-primary btn-outlined float-right btn-disabled", id="register-submit", style="opacity: 0.5; cursor: not-allowed;") }}
5774
</div>
5875
</div>
5976

@@ -76,4 +93,108 @@ <h2>Sign Up!</h2>
7693
{% endblock %}
7794

7895
{% block scripts %}
96+
<style>
97+
@keyframes shake {
98+
0%, 100% { transform: translateX(0); }
99+
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
100+
20%, 40%, 60%, 80% { transform: translateX(5px); }
101+
}
102+
</style>
103+
<script>
104+
document.addEventListener('DOMContentLoaded', function() {
105+
const commitmentText = {{ commitment_text | tojson }};
106+
const commitmentInput = document.getElementById('commitment-input');
107+
const commitmentFeedback = document.getElementById('commitment-feedback');
108+
const registerButton = document.getElementById('register-submit');
109+
const registerForm = document.getElementById('registration-form');
110+
const commitmentVerifiedField = document.getElementById('commitment-verified');
111+
let commitmentValid = false;
112+
113+
function normalizeText(text) {
114+
return text.toLowerCase().replace(/[^a-z]/g, '').split('').sort().join('');
115+
}
116+
117+
function validateCommitment() {
118+
const userInput = commitmentInput.value.trim();
119+
120+
if (userInput === '') {
121+
commitmentValid = false;
122+
commitmentVerifiedField.value = '';
123+
commitmentInput.classList.remove('is-valid', 'is-invalid');
124+
commitmentFeedback.textContent = 'Please type the commitment exactly as shown above to enable registration';
125+
commitmentFeedback.classList.remove('text-success', 'text-danger');
126+
commitmentFeedback.classList.add('text-muted');
127+
128+
registerButton.style.opacity = '0.5';
129+
registerButton.style.cursor = 'not-allowed';
130+
registerButton.classList.add('btn-disabled');
131+
} else {
132+
const normalizedUser = normalizeText(userInput);
133+
const normalizedCommitment = normalizeText(commitmentText);
134+
135+
if (normalizedUser === normalizedCommitment) {
136+
commitmentValid = true;
137+
commitmentVerifiedField.value = 'verified';
138+
commitmentInput.classList.remove('is-invalid');
139+
commitmentInput.classList.add('is-valid');
140+
commitmentFeedback.textContent = 'Thank you for helping keep pwn.college viable!';
141+
commitmentFeedback.classList.remove('text-muted', 'text-danger');
142+
commitmentFeedback.classList.add('text-success');
143+
144+
registerButton.style.opacity = '1';
145+
registerButton.style.cursor = 'pointer';
146+
registerButton.classList.remove('btn-disabled');
147+
} else {
148+
commitmentValid = false;
149+
commitmentVerifiedField.value = '';
150+
commitmentInput.classList.remove('is-valid');
151+
commitmentInput.classList.add('is-invalid');
152+
commitmentFeedback.textContent = 'Please type the commitment as shown above';
153+
commitmentFeedback.classList.remove('text-muted', 'text-success');
154+
commitmentFeedback.classList.add('text-danger');
155+
156+
registerButton.style.opacity = '0.5';
157+
registerButton.style.cursor = 'not-allowed';
158+
registerButton.classList.add('btn-disabled');
159+
}
160+
}
161+
}
162+
163+
function showCommitmentReminder() {
164+
alert('Please type the commitment exactly as shown to enable registration.');
165+
document.getElementById('commitment-section').scrollIntoView({ behavior: 'smooth', block: 'center' });
166+
commitmentInput.focus();
167+
commitmentInput.style.animation = 'shake 0.5s';
168+
setTimeout(() => {
169+
commitmentInput.style.animation = '';
170+
}, 500);
171+
}
172+
173+
commitmentInput.addEventListener('input', validateCommitment);
174+
commitmentInput.addEventListener('paste', function() {
175+
setTimeout(validateCommitment, 10);
176+
});
177+
178+
registerForm.addEventListener('submit', function(e) {
179+
if (!commitmentValid) {
180+
e.preventDefault();
181+
e.stopPropagation();
182+
showCommitmentReminder();
183+
return false;
184+
}
185+
return true;
186+
});
187+
188+
registerButton.addEventListener('click', function(e) {
189+
if (!commitmentValid) {
190+
e.preventDefault();
191+
e.stopPropagation();
192+
showCommitmentReminder();
193+
return false;
194+
}
195+
});
196+
197+
validateCommitment();
198+
});
199+
</script>
79200
{% endblock %}

test/test_welcome.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import contextlib
22
import time
3+
import string
4+
import random
35

46
import pytest
57
from selenium.webdriver import Firefox, FirefoxOptions
@@ -10,18 +12,19 @@
1012

1113
from utils import DOJO_URL, workspace_run
1214

13-
1415
@pytest.fixture
15-
def random_user_browser(random_user_name):
16+
def browser_fixture():
1617
options = FirefoxOptions()
1718
options.add_argument("--headless")
18-
browser = Firefox(options=options)
19+
return Firefox(options=options)
1920

20-
browser.get(f"{DOJO_URL}/login")
21-
browser.find_element("id", "name").send_keys(random_user_name)
22-
browser.find_element("id", "password").send_keys(random_user_name)
23-
browser.find_element("id", "_submit").click()
24-
return browser
21+
@pytest.fixture
22+
def random_user_browser(browser_fixture, random_user_name):
23+
browser_fixture.get(f"{DOJO_URL}/login")
24+
browser_fixture.find_element("id", "name").send_keys(random_user_name)
25+
browser_fixture.find_element("id", "password").send_keys(random_user_name)
26+
browser_fixture.find_element("id", "_submit").click()
27+
return browser_fixture
2528

2629

2730
@contextlib.contextmanager
@@ -207,3 +210,33 @@ def skip_test_welcome_practice(random_user_browser, random_user_name, welcome_do
207210
flag = workspace_run("tail -n1 /tmp/out 2>&1", user=random_user_name).stdout.split()[-1]
208211
challenge_submit(random_user_browser, idx, flag)
209212
random_user_browser.close()
213+
214+
215+
def test_registration_commitment(browser_fixture):
216+
browser_fixture.get(f"{DOJO_URL}/register")
217+
wait = WebDriverWait(browser_fixture, 10)
218+
219+
test_username = "test" + "".join(random.choices(string.ascii_lowercase, k=8))
220+
221+
browser_fixture.find_element(By.ID, "name").send_keys(test_username)
222+
browser_fixture.find_element(By.ID, "email").send_keys(f"{test_username}@example.com")
223+
browser_fixture.find_element(By.ID, "password").send_keys("TestPassword123!")
224+
225+
submit_button = browser_fixture.find_element(By.ID, "register-submit")
226+
submit_button.click()
227+
228+
alert = browser_fixture.switch_to.alert
229+
assert "Please type the commitment" in alert.text
230+
alert.accept()
231+
232+
commitment_input = browser_fixture.find_element(By.ID, "commitment-input")
233+
commitment_input.send_keys("i have read the ground rules and commit to not publish pwn.college writeups on the internet")
234+
235+
time.sleep(0.5)
236+
237+
submit_button.click()
238+
239+
wait.until(lambda driver: "register" not in driver.current_url.lower())
240+
assert "register" not in browser_fixture.current_url.lower()
241+
242+
browser_fixture.close()

0 commit comments

Comments
 (0)