1
- import React , { Component } from 'react' ;
1
+ import React , { Component , RefObject } from 'react' ;
2
2
import { Classes , Navbar , Alignment , EditableText , Button , Popover , Spinner , H5 , Intent } from '@blueprintjs/core' ;
3
+ import ReCAPTCHA from 'react-google-recaptcha' ;
4
+ import waitFor from 'wait-for-cond' ;
3
5
4
6
import socketClient from '../../socketClient' ;
5
7
import Toast from '../../toast' ;
@@ -9,6 +11,8 @@ import './style.scss';
9
11
import logoPath from '../../assets/images/pawnlogo.png' ;
10
12
11
13
interface IState extends IExecutionState {
14
+ recaptcha : RefObject < ReCAPTCHA > ,
15
+ captchaToken : string | null ,
12
16
locked : boolean ,
13
17
title : string ,
14
18
isSharing : boolean ,
@@ -23,6 +27,8 @@ interface IExecutionState {
23
27
24
28
class NavBar extends Component {
25
29
state : IState = {
30
+ recaptcha : React . createRef ( ) ,
31
+ captchaToken : null ,
26
32
locked : false ,
27
33
title : '' ,
28
34
isProcessing : false ,
@@ -93,10 +99,20 @@ class NavBar extends Component {
93
99
Toast . show ( { intent : Intent . SUCCESS , icon : 'tick' , message : `Forked ${ previousTitle } successfully.` } ) ;
94
100
}
95
101
96
- private runScript ( ) : void {
97
- if ( ! this . state . isProcessing || ! this . state . isRunning ) {
98
- socketClient . socket . emit ( 'runScript' ) ;
102
+ private async runScript ( ) : Promise < any > {
103
+ if ( this . state . isProcessing || this . state . isRunning )
104
+ return ;
105
+
106
+ if ( ! await this . checkCaptcha ( ) ) {
107
+ return Toast . show ( {
108
+ intent : Intent . DANGER ,
109
+ icon : 'error' ,
110
+ message : 'You are solving that damn captcha for over an hour now... Hit the button again to retry solving the captcha.'
111
+ } ) ;
99
112
}
113
+
114
+ socketClient . socket . emit ( 'runScript' , this . state . captchaToken ) ;
115
+ this . invalidateCaptcha ( ) ;
100
116
}
101
117
102
118
private stopScript ( ) : void {
@@ -144,12 +160,43 @@ class NavBar extends Component {
144
160
}
145
161
}
146
162
147
- private shareFiddle ( ) : void {
163
+ private async checkCaptcha ( ) : Promise < boolean > {
164
+ if ( ! this . state . recaptcha . current )
165
+ return false ;
166
+
167
+ this . state . recaptcha . current . execute ( ) ;
168
+
169
+ try {
170
+ await waitFor ( ( ) => this . state . captchaToken , 1 * 60 * 60 * 1000 ) ; // Shouldn't take longer than an hour to solve some captchas...
171
+ return true ;
172
+ } catch ( ex ) {
173
+ return false ; // he actually took longer than 1 hour to solve captchas... smh my head
174
+ }
175
+ }
176
+
177
+ private invalidateCaptcha ( ) : void {
178
+ if ( ! this . state . recaptcha . current )
179
+ return ;
180
+
181
+ this . state . recaptcha . current . reset ( ) ;
182
+ this . setState ( { captchaToken : null } ) ;
183
+ }
184
+
185
+ private async shareFiddle ( ) : Promise < any > {
148
186
if ( this . state . isSharing || this . state . locked )
149
187
return ;
150
188
189
+ if ( ! await this . checkCaptcha ( ) ) {
190
+ return Toast . show ( {
191
+ intent : Intent . DANGER ,
192
+ icon : 'error' ,
193
+ message : 'You are solving that damn captcha for over an hour now... Hit the button again to retry solving the captcha.'
194
+ } ) ;
195
+ }
196
+
151
197
this . setState ( { isSharing : true } ) ;
152
- socketClient . socket . emit ( 'share' ) ;
198
+ socketClient . socket . emit ( 'share' , this . state . captchaToken ) ;
199
+ this . invalidateCaptcha ( ) ;
153
200
}
154
201
155
202
private forkFiddle ( ) : void {
@@ -180,6 +227,13 @@ class NavBar extends Component {
180
227
</ Navbar . Heading >
181
228
</ Navbar . Group >
182
229
< Navbar . Group align = { Alignment . RIGHT } >
230
+ < ReCAPTCHA
231
+ ref = { this . state . recaptcha }
232
+ size = { 'invisible' }
233
+ theme = { 'dark' }
234
+ onChange = { captchaToken => this . setState ( { captchaToken } ) }
235
+ sitekey = { process . env . REACT_APP_RECAPTCHA_KEY || '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' }
236
+ />
183
237
< Popover >
184
238
< Button className = { 'bp3-minimal' } disabled = { this . state . locked } icon = { 'share' } text = { 'Share' } large />
185
239
< div className = { 'sharePopover' } >
0 commit comments