]> Untitled Git - lemmy.git/commitdiff
Make delete account require password.
authorDessalines <tyhou13@gmx.com>
Fri, 18 Oct 2019 04:25:23 +0000 (21:25 -0700)
committerDessalines <tyhou13@gmx.com>
Fri, 18 Oct 2019 04:25:23 +0000 (21:25 -0700)
- Fixes #301

server/src/api/user.rs
ui/src/components/user.tsx
ui/src/interfaces.ts
ui/src/services/WebSocketService.ts
ui/src/translations/en.ts

index b0ed5a4bb5dd3981008bc4971d88108fe7db0300..2de809055826ce33a68b0f31ad89f7450cecd6f3 100644 (file)
@@ -105,6 +105,7 @@ pub struct GetReplies {
 
 #[derive(Serialize, Deserialize)]
 pub struct DeleteAccount {
+  password: String,
   auth: String,
 }
 
@@ -601,6 +602,14 @@ impl Perform<LoginResponse> for Oper<DeleteAccount> {
 
     let user_id = claims.id;
 
+    let user: User_ = User_::read(&conn, user_id)?;
+
+    // Verify the password
+    let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
+    if !valid {
+      return Err(APIError::err(&self.op, "password_incorrect"))?;
+    }
+
     // Comments
     let comments = CommentView::list(
       &conn,
index c53a672a0d102e3e79812003c82d8b5365405304..88476bc82afa092a3a00d85cee9b4103dc31dd55 100644 (file)
@@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno';
 import { Link } from 'inferno-router';
 import { Subscription } from "rxjs";
 import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse } from '../interfaces';
+import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse, DeleteAccountForm } from '../interfaces';
 import { WebSocketService, UserService } from '../services';
 import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter, themes, setTheme } from '../utils';
 import { PostListing } from './post-listing';
@@ -33,6 +33,7 @@ interface UserState {
   userSettingsLoading: boolean;
   deleteAccountLoading: boolean;
   deleteAccountShowConfirm: boolean;
+  deleteAccountForm: DeleteAccountForm;
 }
 
 export class User extends Component<any, UserState> {
@@ -69,6 +70,9 @@ export class User extends Component<any, UserState> {
     userSettingsLoading: null,
     deleteAccountLoading: null,
     deleteAccountShowConfirm: false,
+    deleteAccountForm: {
+      password: null,
+    }
   }
 
   constructor(props: any, context: any) {
@@ -316,9 +320,10 @@ export class User extends Component<any, UserState> {
                   <button class="btn btn-danger" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="delete_account">#</T></button>
                   {this.state.deleteAccountShowConfirm && 
                     <>
-                      <div class="mt-2 alert alert-danger" role="alert"><T i18nKey="delete_account_confirm">#</T></div>
-                      <button class="btn btn-danger mr-4" onClick={linkEvent(this, this.handleDeleteAccount)}>{this.state.deleteAccountLoading ? 
-                      <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('yes'))}</button>
+                      <div class="my-2 alert alert-danger" role="alert"><T i18nKey="delete_account_confirm">#</T></div>
+                      <input type="password" value={this.state.deleteAccountForm.password}  onInput={linkEvent(this, this.handleDeleteAccountPasswordChange)} class="form-control my-2" />
+                      <button class="btn btn-danger mr-4" disabled={!this.state.deleteAccountForm.password} onClick={linkEvent(this, this.handleDeleteAccount)}>{this.state.deleteAccountLoading ? 
+                      <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('delete'))}</button>
                       <button class="btn btn-secondary" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="cancel">#</T></button>
                     </>
                   }
@@ -453,12 +458,17 @@ export class User extends Component<any, UserState> {
     i.setState(i.state);
   }
 
+  handleDeleteAccountPasswordChange(i: User, event: any) {
+    i.state.deleteAccountForm.password = event.target.value;
+    i.setState(i.state);
+  }
+
   handleDeleteAccount(i: User, event: any) {
     event.preventDefault();
     i.state.deleteAccountLoading = true;
     i.setState(i.state);
 
-    WebSocketService.Instance.deleteAccount();
+    WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
   }
 
   parseMessage(msg: any) {
@@ -466,6 +476,8 @@ export class User extends Component<any, UserState> {
     let op: UserOperation = msgOp(msg);
     if (msg.error) {
       alert(i18n.t(msg.error));
+      this.state.deleteAccountLoading = false;
+      this.setState(this.state);
       return;
     } else if (op == UserOperation.GetUserDetails) {
       let res: UserDetailsResponse = msg;
index 4bd013ce9ec93ce13c980dc1535ce4e2b5a00a4a..e11dee04a6bd5263a6b0246a2e1c5ca4fee41d3a 100644 (file)
@@ -600,3 +600,7 @@ export interface SearchResponse {
   communities: Array<Community>;  
   users: Array<UserView>;
 }
+
+export interface DeleteAccountForm {
+  password: string;
+}
index f8838d400ac7e93928a3aca4c745493c6fc4387a..987cbfdf15c12d530728bd3098e26f31fbe21b75 100644 (file)
@@ -1,5 +1,5 @@
 import { wsUri } from '../env';
-import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm } from '../interfaces';
+import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm, DeleteAccountForm } from '../interfaces';
 import { webSocket } from 'rxjs/webSocket';
 import { Subject } from 'rxjs';
 import { retryWhen, delay, take } from 'rxjs/operators';
@@ -199,8 +199,7 @@ export class WebSocketService {
     this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
   }
 
-  public deleteAccount() {
-    let form = {};
+  public deleteAccount(form: DeleteAccountForm) {
     this.setAuth(form);
     this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form));
   }
index 7df3d02362ae40103b810115c5143af590e54ec8..7a23e20992ff0ee6805b68373617e6f95b86ad2d 100644 (file)
@@ -56,7 +56,7 @@ export const en = {
     delete: 'delete',
     deleted: 'deleted',
     delete_account: 'Delete Account',
-    delete_account_confirm: 'Warning: this will permanently delete all your data. Are you sure?',
+    delete_account_confirm: 'Warning: this will permanently delete all your data. Enter your password to confirm.',
     restore: 'restore',
     ban: 'ban',
     ban_from_site: 'ban from site',