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';

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 userId: bigint = BigInt(0);
  private userToken: bigint = BigInt(0);

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

  public login(username: string, password: string, onFail: Function, onConnectionError: Function) {
    this.http.post(`${environment.apiURL}/users/presalt`, {username})
    .subscribe((answer: Object) => {
      var presaltAnswer = Object.assign(new PresaltAnswer(), answer)
      if (!presaltAnswer.success) {
        onFail()
        return
      }
      // this presalting and hashing is done to protect the user's password in case of a man-in-the-middle-attack,
      // where an attacker might be able to intercept a password if not hashed before. The password still has to be 
      // hashed on the server-side to be sure but this method prevents dumb users from having their passweord 
      // they use everywhere easily leaked, because you still need to crack this one layer first
      // also, typical automated hacking software will hopefully be confused by my weird code
      var passwordHash = new sha256().update(password + presaltAnswer.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
        if (loginSuccess) {
          localStorage.setItem('userToken', authenticateAnswer.token)
          this.updateUserInfo()
          this.username = username
          this.router.navigate(['admin'])
        } else {
          onFail()
        }
      }, (error) => {onConnectionError()})
    }, (error) => {onConnectionError()})
  }

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

  logout() {
    this.username = ''
    localStorage.removeItem('userToken')
  }
}