Skip to content

Commit 960ad2a

Browse files
guguclaude
andcommitted
Add Cloudflare Turnstile captcha to registration form
- Add TurnstileComponent for rendering captcha widget - Integrate captcha into registration form (SaaS builds only) - Add turnstileToken to NewAuthUser interface - Disable submit button until captcha is completed - Reset captcha widget on failed registration attempts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cca5edb commit 960ad2a

13 files changed

Lines changed: 644 additions & 301 deletions
Lines changed: 110 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,204 @@
11
.wrapper {
2-
display: grid;
3-
grid-template-columns: auto 62.5%;
4-
grid-column-gap: 24px;
5-
height: 100%;
6-
padding: 40px 24px;
2+
display: grid;
3+
grid-template-columns: auto 62.5%;
4+
grid-column-gap: 24px;
5+
height: 100%;
6+
padding: 40px 24px;
77
}
88

99
@media (width <= 600px) {
10-
.wrapper {
11-
display: flex;
12-
flex-direction: column;
13-
padding: 0;
14-
}
10+
.wrapper {
11+
display: flex;
12+
flex-direction: column;
13+
padding: 0;
14+
}
1515
}
1616

1717
.registrationTitle {
18-
font-weight: 700 !important;
19-
margin-top: -4px !important;
20-
margin-bottom: 32px !important;
18+
font-weight: 700 !important;
19+
margin-top: -4px !important;
20+
margin-bottom: 32px !important;
2121
}
2222

2323
.registrationTitle_mobile {
24-
display: none;
24+
display: none;
2525
}
2626

2727
@media (width <= 600px) {
28-
.registrationTitle_desktop {
29-
display: none;
30-
}
28+
.registrationTitle_desktop {
29+
display: none;
30+
}
3131

32-
.registrationTitle_mobile {
33-
display: initial;
34-
}
32+
.registrationTitle_mobile {
33+
display: initial;
34+
}
3535
}
3636

37-
38-
39-
4037
.registrationTitle__emphasis {
41-
color: var(--color-accentedPalette-500)
38+
color: var(--color-accentedPalette-500);
4239
}
4340

4441
.register-form-box {
45-
display: flex;
46-
flex-direction: column;
47-
/* justify-content: space-between; */
48-
padding-bottom: 20px;
42+
display: flex;
43+
flex-direction: column;
44+
/* justify-content: space-between; */
45+
padding-bottom: 20px;
4946
}
5047

5148
@media (width <= 600px) {
52-
.register-form-box {
53-
height: 100%;
54-
}
49+
.register-form-box {
50+
height: 100%;
51+
}
5552
}
5653

5754
.register-form {
58-
display: flex;
59-
flex-direction: column;
60-
height: 100%;
61-
margin: auto;
62-
padding: 0 48px;
63-
width: 496px;
55+
display: flex;
56+
flex-direction: column;
57+
height: 100%;
58+
margin: auto;
59+
padding: 0 48px;
60+
width: 496px;
6461
}
6562

6663
@media (width <= 600px) {
67-
.register-form {
68-
padding: 40px 9vw 0;
69-
width: 100%;
70-
}
64+
.register-form {
65+
padding: 40px 9vw 0;
66+
width: 100%;
67+
}
7168
}
7269

7370
.mat-h1 {
74-
align-self: center;
75-
margin-top: 20px;
76-
font-weight: 500;
77-
text-align: center;
78-
width: 75%;
71+
align-self: center;
72+
margin-top: 20px;
73+
font-weight: 500;
74+
text-align: center;
75+
width: 75%;
7976
}
8077

8178
@media screen and (max-width: 600px) {
82-
.mat-h1 {
83-
margin-top: 32px;
84-
margin-bottom: 32px;
85-
width: 100%;
86-
}
79+
.mat-h1 {
80+
margin-top: 32px;
81+
margin-bottom: 32px;
82+
width: 100%;
83+
}
8784
}
8885

8986
.divider {
90-
position: relative;
91-
background-color: #E8E8E8;
92-
height: 1px;
93-
margin: 24px 0;
94-
width: 100%
87+
position: relative;
88+
background-color: #e8e8e8;
89+
height: 1px;
90+
margin: 24px 0;
91+
width: 100%;
9592
}
9693

9794
.divider__label {
98-
position: absolute;
99-
top: 50%; left: 50%;
100-
transform: translate(-50%, -50%);
101-
background-color: var(--mat-sidenav-content-background-color);
102-
font-size: 14px;
103-
padding: 0 16px;
95+
position: absolute;
96+
top: 50%;
97+
left: 50%;
98+
transform: translate(-50%, -50%);
99+
background-color: var(--mat-sidenav-content-background-color);
100+
font-size: 14px;
101+
padding: 0 16px;
104102
}
105103

106104
@media screen and (max-width: 600px) {
107-
#google_registration_button ::ng-deep iframe {
108-
width: 100% !important;
109-
}
105+
#google_registration_button ::ng-deep iframe {
106+
width: 100% !important;
107+
}
110108
}
111109

112110
.password-field {
113-
margin-top: 8px;
111+
margin-top: 8px;
112+
}
113+
114+
.turnstile-widget {
115+
margin-top: 24px;
114116
}
115117

116118
.submit-button {
117-
margin-top: 64px;
119+
margin-top: 40px;
118120
}
119121

120122
.register-image-box {
121-
display: flex;
122-
justify-content: flex-end;
123-
align-items: flex-end;
124-
background-color: var(--image-box-bg);
125-
border-radius: 12px;
126-
height: calc(100vh - 120px);
127-
overflow: hidden;
128-
padding-top: 3vw;
123+
display: flex;
124+
justify-content: flex-end;
125+
align-items: flex-end;
126+
background-color: var(--image-box-bg);
127+
border-radius: 12px;
128+
height: calc(100vh - 120px);
129+
overflow: hidden;
130+
padding-top: 3vw;
129131
}
130132

131133
@media (prefers-color-scheme: light) {
132-
.register-image-box {
133-
--image-box-bg: #E8F1EA;
134-
}
134+
.register-image-box {
135+
--image-box-bg: #e8f1ea;
136+
}
135137
}
136138

137139
@media (prefers-color-scheme: dark) {
138-
.register-image-box {
139-
--image-box-bg: #636363;
140-
}
140+
.register-image-box {
141+
--image-box-bg: #636363;
142+
}
141143
}
142144

143145
@media screen and (max-width: 600px) {
144-
.register-image-box {
145-
display: none;
146-
}
146+
.register-image-box {
147+
display: none;
148+
}
147149
}
148150

149151
.password-visibility-button {
150-
cursor: pointer;
152+
cursor: pointer;
151153
}
152154

153155
.register-image {
154-
height: 85vh;
155-
margin-bottom: -5px;
156+
height: 85vh;
157+
margin-bottom: -5px;
156158
}
157159

158160
.register-form .agreement {
159-
margin-top: auto !important;
161+
margin-top: auto !important;
160162
}
161163

162164
.link {
163-
color: var(--color-accentedPalette-500);
165+
color: var(--color-accentedPalette-500);
164166
}
165167

166168
.register-form__github-button {
167-
background-color: #24292f;
168-
margin-top: 20px;
169-
padding: 6px;
170-
width: 400px;
169+
background-color: #24292f;
170+
margin-top: 20px;
171+
padding: 6px;
172+
width: 400px;
171173
}
172174

173175
@media (width <= 600px) {
174-
.register-form__github-button {
175-
width: auto;
176-
}
176+
.register-form__github-button {
177+
width: auto;
178+
}
177179
}
178180

179181
.register-form__github-button ::ng-deep .mdc-button__label {
180-
display: flex;
181-
justify-content: space-between;
182-
width: 100%;
182+
display: flex;
183+
justify-content: space-between;
184+
width: 100%;
183185
}
184186

185187
.register-form__github-caption {
186-
flex: 1 0 auto;
187-
color: #fff;
188-
margin-top: 2px;
189-
text-align: center;
188+
flex: 1 0 auto;
189+
color: #fff;
190+
margin-top: 2px;
191+
text-align: center;
190192
}
191193

192194
.register-form__github-icon {
193-
--mat-outlined-button-icon-spacing: 0;
194-
--mat-outlined-button-icon-offset: 0;
195+
--mat-outlined-button-icon-spacing: 0;
196+
--mat-outlined-button-icon-offset: 0;
195197

196-
height: 24px !important;
197-
width: 24px !important;
198+
height: 24px !important;
199+
width: 24px !important;
198200
}
199201

200202
.register-form__github-icon ::ng-deep svg path {
201-
fill: #fff;
203+
fill: #fff;
202204
}

frontend/src/app/components/registration/registration.component.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,17 @@ <h1 class="mat-headline-4 registrationTitle registrationTitle_mobile">
4444
(onFieldChange)="updatePasswordField($event)">
4545
</app-user-password>
4646

47+
<app-turnstile *ngIf="isSaas"
48+
class="turnstile-widget"
49+
(tokenReceived)="onTurnstileToken($event)"
50+
(tokenError)="onTurnstileError()"
51+
(tokenExpired)="onTurnstileExpired()">
52+
</app-turnstile>
53+
4754
<button type="submit" mat-flat-button color="accent" class="submit-button"
4855
angulartics2On="click"
4956
angularticsAction="Reg: sign up is clicked"
50-
[disabled]="submitting || registrationForm.form.invalid || registrationForm.form.pristine">
57+
[disabled]="submitting || registrationForm.form.invalid || registrationForm.form.pristine || (isSaas && !turnstileToken)">
5158
{{ submitting ? 'Submitting' : 'Create account'}}
5259
</button>
5360
<p class="mat-caption agreement">

0 commit comments

Comments
 (0)