]> Untitled Git - lemmy.git/blobdiff - ui/src/components/login.tsx
routes.api: fix get_captcha endpoint (#1135)
[lemmy.git] / ui / src / components / login.tsx
index 94de499eee66bf051c271f46040dc2a51c90b70c..caf8c9cfb48c9463f04d149b7f0700c07231a94e 100644 (file)
@@ -9,9 +9,10 @@ import {
   UserOperation,
   PasswordResetForm,
   GetSiteResponse,
+  GetCaptchaResponse,
   WebSocketJsonResponse,
   Site,
-} from '../interfaces';
+} from 'lemmy-js-client';
 import { WebSocketService, UserService } from '../services';
 import { wsJsonToRes, validEmail, toast } from '../utils';
 import { i18n } from '../i18next';
@@ -21,11 +22,8 @@ interface State {
   registerForm: RegisterForm;
   loginLoading: boolean;
   registerLoading: boolean;
-  mathQuestion: {
-    a: number;
-    b: number;
-    answer: number;
-  };
+  captcha: GetCaptchaResponse;
+  captchaPlaying: boolean;
   site: Site;
 }
 
@@ -43,14 +41,13 @@ export class Login extends Component<any, State> {
       password_verify: undefined,
       admin: false,
       show_nsfw: false,
+      captcha_uuid: undefined,
+      captcha_answer: undefined,
     },
     loginLoading: false,
     registerLoading: false,
-    mathQuestion: {
-      a: Math.floor(Math.random() * 10) + 1,
-      b: Math.floor(Math.random() * 10) + 1,
-      answer: undefined,
-    },
+    captcha: undefined,
+    captchaPlaying: false,
     site: {
       id: undefined,
       name: undefined,
@@ -81,6 +78,7 @@ export class Login extends Component<any, State> {
       );
 
     WebSocketService.Instance.getSite();
+    WebSocketService.Instance.getCaptcha();
   }
 
   componentWillUnmount() {
@@ -172,6 +170,7 @@ export class Login extends Component<any, State> {
       </div>
     );
   }
+
   registerForm() {
     return (
       <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
@@ -258,23 +257,37 @@ export class Login extends Component<any, State> {
             />
           </div>
         </div>
-        <div class="form-group row">
-          <label class="col-sm-10 col-form-label" htmlFor="register-math">
-            {i18n.t('what_is')}{' '}
-            {`${this.state.mathQuestion.a} + ${this.state.mathQuestion.b}?`}
-          </label>
 
-          <div class="col-sm-2">
-            <input
-              type="number"
-              id="register-math"
-              class="form-control"
-              value={this.state.mathQuestion.answer}
-              onInput={linkEvent(this, this.handleMathAnswerChange)}
-              required
-            />
+        {this.state.captcha && (
+          <div class="form-group row">
+            <label class="col-sm-2" htmlFor="register-captcha">
+              <span class="mr-2">{i18n.t('enter_code')}</span>
+              <button
+                type="button"
+                class="btn btn-secondary"
+                onClick={linkEvent(this, this.handleRegenCaptcha)}
+              >
+                <svg class="icon icon-refresh-cw">
+                  <use xlinkHref="#icon-refresh-cw"></use>
+                </svg>
+              </button>
+            </label>
+            {this.showCaptcha()}
+            <div class="col-sm-6">
+              <input
+                type="text"
+                class="form-control"
+                id="register-captcha"
+                value={this.state.registerForm.captcha_answer}
+                onInput={linkEvent(
+                  this,
+                  this.handleRegisterCaptchaAnswerChange
+                )}
+                required
+              />
+            </div>
           </div>
-        </div>
+        )}
         {this.state.site.enable_nsfw && (
           <div class="form-group row">
             <div class="col-sm-10">
@@ -295,11 +308,7 @@ export class Login extends Component<any, State> {
         )}
         <div class="form-group row">
           <div class="col-sm-10">
-            <button
-              type="submit"
-              class="btn btn-secondary"
-              disabled={this.mathCheck}
-            >
+            <button type="submit" class="btn btn-secondary">
               {this.state.registerLoading ? (
                 <svg class="icon icon-spinner spin">
                   <use xlinkHref="#icon-spinner"></use>
@@ -314,6 +323,36 @@ export class Login extends Component<any, State> {
     );
   }
 
+  showCaptcha() {
+    return (
+      <div class="col-sm-4">
+        {this.state.captcha.ok && (
+          <>
+            <img
+              class="rounded-top img-fluid"
+              src={this.captchaPngSrc()}
+              style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
+            />
+            {this.state.captcha.ok.wav && (
+              <button
+                class="rounded-bottom btn btn-sm btn-secondary btn-block"
+                style="border-top-right-radius: 0; border-top-left-radius: 0;"
+                title={i18n.t('play_captcha_audio')}
+                onClick={linkEvent(this, this.handleCaptchaPlay)}
+                type="button"
+                disabled={this.state.captchaPlaying}
+              >
+                <svg class="icon icon-play">
+                  <use xlinkHref="#icon-play"></use>
+                </svg>
+              </button>
+            )}
+          </>
+        )}
+      </div>
+    );
+  }
+
   handleLoginSubmit(i: Login, event: any) {
     event.preventDefault();
     i.state.loginLoading = true;
@@ -335,10 +374,7 @@ export class Login extends Component<any, State> {
     event.preventDefault();
     i.state.registerLoading = true;
     i.setState(i.state);
-
-    if (!i.mathCheck) {
-      WebSocketService.Instance.register(i.state.registerForm);
-    }
+    WebSocketService.Instance.register(i.state.registerForm);
   }
 
   handleRegisterUsernameChange(i: Login, event: any) {
@@ -369,11 +405,16 @@ export class Login extends Component<any, State> {
     i.setState(i.state);
   }
 
-  handleMathAnswerChange(i: Login, event: any) {
-    i.state.mathQuestion.answer = event.target.value;
+  handleRegisterCaptchaAnswerChange(i: Login, event: any) {
+    i.state.registerForm.captcha_answer = event.target.value;
     i.setState(i.state);
   }
 
+  handleRegenCaptcha(_i: Login, _event: any) {
+    event.preventDefault();
+    WebSocketService.Instance.getCaptcha();
+  }
+
   handlePasswordReset(i: Login) {
     event.preventDefault();
     let resetForm: PasswordResetForm = {
@@ -382,11 +423,21 @@ export class Login extends Component<any, State> {
     WebSocketService.Instance.passwordReset(resetForm);
   }
 
-  get mathCheck(): boolean {
-    return (
-      this.state.mathQuestion.answer !=
-      this.state.mathQuestion.a + this.state.mathQuestion.b
-    );
+  handleCaptchaPlay(i: Login) {
+    event.preventDefault();
+    let snd = new Audio('data:audio/wav;base64,' + i.state.captcha.ok.wav);
+    snd.play();
+    i.state.captchaPlaying = true;
+    i.setState(i.state);
+    snd.addEventListener('ended', () => {
+      snd.currentTime = 0;
+      i.state.captchaPlaying = false;
+      i.setState(this.state);
+    });
+  }
+
+  captchaPngSrc() {
+    return `data:image/png;base64,${this.state.captcha.ok.png}`;
   }
 
   parseMessage(msg: WebSocketJsonResponse) {
@@ -394,6 +445,9 @@ export class Login extends Component<any, State> {
     if (msg.error) {
       toast(i18n.t(msg.error), 'danger');
       this.state = this.emptyState;
+      this.state.registerForm.captcha_answer = undefined;
+      // Refetch another captcha
+      WebSocketService.Instance.getCaptcha();
       this.setState(this.state);
       return;
     } else {
@@ -412,6 +466,13 @@ export class Login extends Component<any, State> {
         UserService.Instance.login(data);
         WebSocketService.Instance.userJoin();
         this.props.history.push('/communities');
+      } else if (res.op == UserOperation.GetCaptcha) {
+        let data = res.data as GetCaptchaResponse;
+        if (data.ok) {
+          this.state.captcha = data;
+          this.state.registerForm.captcha_uuid = data.ok.uuid;
+          this.setState(this.state);
+        }
       } else if (res.op == UserOperation.PasswordReset) {
         toast(i18n.t('reset_password_mail_sent'));
       } else if (res.op == UserOperation.GetSite) {