juice-shop/juice-shop

View on GitHub
frontend/src/app/navbar/navbar.component.ts

Summary

Maintainability
A
0 mins
Test Coverage
C
73%
/*
 * Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
 * SPDX-License-Identifier: MIT
 */

import { environment } from '../../environments/environment'
import { ChallengeService } from '../Services/challenge.service'
import { UserService } from '../Services/user.service'
import { AdministrationService } from '../Services/administration.service'
import { ConfigurationService } from '../Services/configuration.service'
import { Component, EventEmitter, NgZone, type OnInit, Output } from '@angular/core'
import { CookieService } from 'ngx-cookie'
import { TranslateService } from '@ngx-translate/core'
import { Router } from '@angular/router'
import { SocketIoService } from '../Services/socket-io.service'
import { LanguagesService } from '../Services/languages.service'
import { MatSnackBar } from '@angular/material/snack-bar'
import { BasketService } from '../Services/basket.service'

import {
  faBomb,
  faComment,
  faInfoCircle,
  faLanguage,
  faMapMarker,
  faRecycle,
  faSearch,
  faShoppingCart,
  faSignInAlt,
  faSignOutAlt,
  faThermometerEmpty,
  faThermometerFull,
  faThermometerHalf,
  faThermometerQuarter,
  faThermometerThreeQuarters,
  faTrophy,
  faUserCircle,
  faUserSecret
} from '@fortawesome/free-solid-svg-icons'
import { faComments } from '@fortawesome/free-regular-svg-icons'
import { faGithub } from '@fortawesome/free-brands-svg-icons'
import { library } from '@fortawesome/fontawesome-svg-core'
import { LoginGuard } from '../app.guard'
import { roles } from '../roles'

library.add(faLanguage, faSearch, faSignInAlt, faSignOutAlt, faComment, faBomb, faTrophy, faInfoCircle, faShoppingCart, faUserSecret, faRecycle, faMapMarker, faUserCircle, faGithub, faComments, faThermometerEmpty, faThermometerQuarter, faThermometerHalf, faThermometerThreeQuarters, faThermometerFull)

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
  public userEmail: string = ''
  public languages: any = []
  public selectedLanguage: string = 'placeholder'
  public version: string = ''
  public applicationName: string = 'OWASP Juice Shop'
  public showGitHubLink: boolean = true
  public logoSrc: string = 'assets/public/images/JuiceShop_Logo.png'
  public scoreBoardVisible: boolean = false
  public shortKeyLang: string = 'placeholder'
  public itemTotal = 0

  @Output() public sidenavToggle = new EventEmitter()

  constructor (private readonly administrationService: AdministrationService, private readonly challengeService: ChallengeService,
    private readonly configurationService: ConfigurationService, private readonly userService: UserService, private readonly ngZone: NgZone,
    private readonly cookieService: CookieService, private readonly router: Router, private readonly translate: TranslateService,
    private readonly io: SocketIoService, private readonly langService: LanguagesService, private readonly loginGuard: LoginGuard,
    private readonly snackBar: MatSnackBar, private readonly basketService: BasketService) { }

  ngOnInit () {
    this.getLanguages()
    this.basketService.getItemTotal().subscribe(x => (this.itemTotal = x))
    this.administrationService.getApplicationVersion().subscribe((version: any) => {
      if (version) {
        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
        this.version = `v${version}`
      }
    }, (err) => { console.log(err) })

    this.configurationService.getApplicationConfiguration().subscribe((config: any) => {
      if (config?.application?.name) {
        this.applicationName = config.application.name
      }
      if (config?.application) {
        this.showGitHubLink = config.application.showGitHubLinks
      }

      if (config?.application?.logo) {
        let logo: string = config.application.logo

        if (logo.substring(0, 4) === 'http') {
          logo = decodeURIComponent(logo.substring(logo.lastIndexOf('/') + 1))
        }
        this.logoSrc = 'assets/public/images/' + logo
      }
    }, (err) => { console.log(err) })

    if (localStorage.getItem('token')) {
      this.getUserDetails()
    } else {
      this.userEmail = ''
    }

    this.userService.getLoggedInState().subscribe((isLoggedIn) => {
      if (isLoggedIn) {
        this.getUserDetails()
      } else {
        this.userEmail = ''
      }
    })

    this.getScoreBoardStatus()

    this.ngZone.runOutsideAngular(() => {
      this.io.socket().on('challenge solved', (challenge) => {
        if (challenge.key === 'scoreBoardChallenge') {
          this.scoreBoardVisible = true
        }
      })
    })
  }

  checkLanguage () {
    if (this.cookieService.get('language')) {
      const langKey = this.cookieService.get('language')
      this.translate.use(langKey)
      this.selectedLanguage = this.languages.find((y: { key: string }) => y.key === langKey)
      this.shortKeyLang = this.languages.find((y: { key: string }) => y.key === langKey).shortKey
    } else {
      this.changeLanguage('en')
      this.selectedLanguage = this.languages.find((y: { key: string }) => y.key === 'en')
      this.shortKeyLang = this.languages.find((y: { key: string }) => y.key === 'en').shortKey
    }
  }

  search (value: string) {
    if (value) {
      const queryParams = { queryParams: { q: value } }
      this.ngZone.run(async () => await this.router.navigate(['/search'], queryParams))
    } else {
      this.ngZone.run(async () => await this.router.navigate(['/search']))
    }
  }

  getUserDetails () {
    this.userService.whoAmI().subscribe((user: any) => {
      this.userEmail = user.email
    }, (err) => { console.log(err) })
  }

  isLoggedIn () {
    return localStorage.getItem('token')
  }

  logout () {
    this.userService.saveLastLoginIp().subscribe((user: any) => { this.noop() }, (err) => { console.log(err) })
    localStorage.removeItem('token')
    this.cookieService.remove('token')
    sessionStorage.removeItem('bid')
    sessionStorage.removeItem('itemTotal')
    this.userService.isLoggedIn.next(false)
    this.ngZone.run(async () => await this.router.navigate(['/']))
  }

  changeLanguage (langKey: string) {
    this.translate.use(langKey)
    const expires = new Date()
    expires.setFullYear(expires.getFullYear() + 1)
    this.cookieService.put('language', langKey, { expires })
    if (this.languages.find((y: { key: string }) => y.key === langKey)) {
      const language = this.languages.find((y: { key: string }) => y.key === langKey)
      this.shortKeyLang = language.shortKey
      // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
      const snackBarRef = this.snackBar.open(`Language has been changed to ${language.lang}`, 'Force page reload', {
        duration: 5000
      })
      snackBarRef.onAction().subscribe(() => {
        location.reload()
      })
    }
  }

  getScoreBoardStatus () {
    this.challengeService.find({ name: 'Score Board' }).subscribe((challenges: any) => {
      this.ngZone.run(() => {
        this.scoreBoardVisible = challenges[0].solved
      })
    }, (err) => { console.log(err) })
  }

  goToProfilePage () {
    window.location.replace(environment.hostServer + '/profile')
  }

  goToDataErasurePage () {
    window.location.replace(environment.hostServer + '/dataerasure')
  }

  onToggleSidenav = () => {
    this.sidenavToggle.emit()
  }

  // eslint-disable-next-line no-empty,@typescript-eslint/no-empty-function
  noop () { }

  getLanguages () {
    this.langService.getLanguages().subscribe((res) => {
      this.languages = res
      this.checkLanguage()
    })
  }

  isAccounting () {
    const payload = this.loginGuard.tokenDecode()
    return payload?.data && payload.data.role === roles.accounting
  }
}