Newer
Older
Website / src / app / account.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { sha256 } from 'sha.js';
import { Router } from '@angular/router';
import Swal from 'sweetalert2';

class Answer {
  success: Boolean = false
}

class PresaltAnswer extends Answer {
  presalt: string = ''
}

class AuthenticateAnswer extends Answer {
  token: string = ''
}

class CheckTokenAnswer extends Answer {
  valid: Boolean = false
}

class TokenData {
  iss: string = ''
  dat: string = ''
  typ: string = ''
  usr: string = ''
}

@Injectable({
  providedIn: 'root'
})
export class AccountService {
  public username = '?';
  private callbacks: Function[] = []

  subscribe(f: Function) {
    this.callbacks.push(f)
  }

  constructor(private http: HttpClient, private router: Router) {
    this.updateUserInfo()
  }

  getPresalt(then: Function, onFail: Function = () => {}, onConnectionError: Function = () => {}, username: string = this.username) {
    this.http.post(`${environment.apiURL}/users/presalt`, {username})
    .subscribe((answer: Object) => {
      var presaltAnswer = Object.assign(new PresaltAnswer(), answer)
      if (!presaltAnswer.success) {
        onFail()
        return
      }
      then(presaltAnswer.presalt)
    }, () => {
      onConnectionError()
    })
  }

  public login(username: string, password: string, onFail: Function, onConnectionError: Function) {
    this.setUser('')
    localStorage.removeItem('userToken')
    this.getPresalt((presalt: string) => {
      var passwordHash = new sha256().update(password + presalt).digest('hex')
      this.http.post(`${environment.apiURL}/users/authenticate`, {username, passwordHash})
      .subscribe((answer) => {
        var authenticateAnswer = Object.assign(new AuthenticateAnswer(), answer)
        var loginSuccess = authenticateAnswer.success == true && authenticateAnswer.token.length > 0
        if (loginSuccess) {
          localStorage.setItem('userToken', authenticateAnswer.token)
          this.setUser(username)
          this.updateUserInfo()
          this.router.navigate(['admin'])
        } else {
          onFail()
        }
      }, () => {onConnectionError()})
    }, onFail, onConnectionError, username)
  }

  updateUserInfo(then: Function = () => {}) {
    var token = localStorage.getItem('userToken')
    if (token == null) {
      this.logout()
      return
    }
    var data = JSON.parse(atob(token?.split('.')[1] as string))
    var tokenData = Object.assign(new TokenData(), data)
    this.setUser(tokenData.usr)
    this.http.post(`${environment.apiURL}/users/checkToken`, {token, username: this.username})
    .subscribe((answer: Object) => {
      var checkTokenAnswer = Object.assign(new CheckTokenAnswer(), answer)
      if (checkTokenAnswer.valid) {
      } else {
        this.logout()
      }
      then()
    }, () => {
      this.logout()
    })
  }

  logout() {
    this.setUser('')
    localStorage.removeItem('userToken')
  }

  changePassword(newPassword: string, then: Function, onConnectionError: Function) {
    this.getPresalt((presalt: string) => {
      var passwordHash = new sha256().update(newPassword + presalt).digest('hex')
      this.http.post(`${environment.apiURL}/users/changePassword`, 
        {username: this.username, passwordHash, token: localStorage.getItem('userToken')}).subscribe((answer) => {
        var status = Object.assign(new Answer(), answer)
        if (status.success) {
          Swal.fire('Password changed!', 'Watch out, \nyour old password won\'t work anymore', 'success')
        } else {
          this.logout()
          Swal.fire('Error!', 'Something went wrong, bad user token?', 'error')
        }
        then()
      })
    }, onConnectionError = onConnectionError)
    // if you get a on Error, you have done something wrong
  }

  setUser(username: string) {
    if (username == this.username) {
      return
    }
    this.username = username
    this.callbacks.forEach(f => {
      f(this.username)
    });
  }

  postStatus(status: string, time: number) {
    this.http.post(`${environment.apiURL}/users/postStatus`,
    {username: this.username, status, lifetime: time, 
      token: localStorage.getItem('userToken')}).subscribe((answer) => {
      var status = Object.assign(new Answer(), answer)
      if (status.success) {
        Swal.fire('You posted a status', 'Everyone can see it', 'success')
      } else {
        Swal.fire('Error!', 'Something went wrong, bad user token?', 'error')
      }
    })
  }
}