juice-shop

Форк
0
/
search-result.component.ts 
255 строк · 10.1 Кб
1
/*
2
 * Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3
 * SPDX-License-Identifier: MIT
4
 */
5

6
import { ProductDetailsComponent } from '../product-details/product-details.component'
7
import { ActivatedRoute, Router } from '@angular/router'
8
import { ProductService } from '../Services/product.service'
9
import { BasketService } from '../Services/basket.service'
10
import { type AfterViewInit, Component, NgZone, type OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core'
11
import { MatPaginator } from '@angular/material/paginator'
12
import { forkJoin, type Subscription } from 'rxjs'
13
import { MatTableDataSource } from '@angular/material/table'
14
import { MatDialog } from '@angular/material/dialog'
15
import { DomSanitizer, type SafeHtml } from '@angular/platform-browser'
16
import { TranslateService } from '@ngx-translate/core'
17
import { SocketIoService } from '../Services/socket-io.service'
18
import { SnackBarHelperService } from '../Services/snack-bar-helper.service'
19

20
import { library } from '@fortawesome/fontawesome-svg-core'
21
import { faCartPlus, faEye } from '@fortawesome/free-solid-svg-icons'
22
import { type Product } from '../Models/product.model'
23
import { QuantityService } from '../Services/quantity.service'
24
import { DeluxeGuard } from '../app.guard'
25

26
library.add(faEye, faCartPlus)
27

28
interface TableEntry {
29
  name: string
30
  price: number
31
  deluxePrice: number
32
  id: number
33
  image: string
34
  description: string
35
  quantity?: number
36
}
37

38
@Component({
39
  selector: 'app-search-result',
40
  templateUrl: './search-result.component.html',
41
  styleUrls: ['./search-result.component.scss']
42
})
43
export class SearchResultComponent implements OnDestroy, AfterViewInit {
44
  public displayedColumns = ['Image', 'Product', 'Description', 'Price', 'Select']
45
  public tableData!: any[]
46
  public pageSizeOptions: number[] = []
47
  public dataSource!: MatTableDataSource<TableEntry>
48
  public gridDataSource!: any
49
  public searchValue?: SafeHtml
50
  public resultsLength = 0
51
  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator | null = null
52
  private readonly productSubscription?: Subscription
53
  private routerSubscription?: Subscription
54
  public breakpoint: number = 6
55
  public emptyState = false
56

57
  constructor (private readonly deluxeGuard: DeluxeGuard, private readonly dialog: MatDialog, private readonly productService: ProductService,
58
    private readonly quantityService: QuantityService, private readonly basketService: BasketService, private readonly translateService: TranslateService,
59
    private readonly router: Router, private readonly route: ActivatedRoute, private readonly sanitizer: DomSanitizer, private readonly ngZone: NgZone, private readonly io: SocketIoService,
60
    private readonly snackBarHelperService: SnackBarHelperService, private readonly cdRef: ChangeDetectorRef) { }
61

62
  // vuln-code-snippet start restfulXssChallenge
63
  ngAfterViewInit () {
64
    const products = this.productService.search('')
65
    const quantities = this.quantityService.getAll()
66
    forkJoin([quantities, products]).subscribe(([quantities, products]) => {
67
      const dataTable: TableEntry[] = []
68
      this.tableData = products
69
      this.trustProductDescription(products) // vuln-code-snippet neutral-line restfulXssChallenge
70
      for (const product of products) {
71
        dataTable.push({
72
          name: product.name,
73
          price: product.price,
74
          deluxePrice: product.deluxePrice,
75
          id: product.id,
76
          image: product.image,
77
          description: product.description
78
        })
79
      }
80
      for (const quantity of quantities) {
81
        const entry = dataTable.find((dataTableEntry) => {
82
          return dataTableEntry.id === quantity.ProductId
83
        })
84
        if (entry === undefined) {
85
          continue
86
        }
87
        entry.quantity = quantity.quantity
88
      }
89
      this.dataSource = new MatTableDataSource<TableEntry>(dataTable)
90
      for (let i = 1; i <= Math.ceil(this.dataSource.data.length / 12); i++) {
91
        this.pageSizeOptions.push(i * 12)
92
      }
93
      this.paginator.pageSizeOptions = this.pageSizeOptions
94
      this.dataSource.paginator = this.paginator
95
      this.gridDataSource = this.dataSource.connect()
96
      this.resultsLength = this.dataSource.data.length
97
      this.filterTable()
98
      this.routerSubscription = this.router.events.subscribe(() => {
99
        this.filterTable()
100
      })
101
      const challenge: string = this.route.snapshot.queryParams.challenge // vuln-code-snippet hide-start
102
      if (challenge && this.route.snapshot.url.join('').match(/hacking-instructor/)) {
103
        this.startHackingInstructor(decodeURIComponent(challenge))
104
      } // vuln-code-snippet hide-end
105
      if (window.innerWidth < 2600) {
106
        this.breakpoint = 4
107
        if (window.innerWidth < 1740) {
108
          this.breakpoint = 3
109
          if (window.innerWidth < 1280) {
110
            this.breakpoint = 2
111
            if (window.innerWidth < 850) {
112
              this.breakpoint = 1
113
            }
114
          }
115
        }
116
      } else {
117
        this.breakpoint = 6
118
      }
119
      this.cdRef.detectChanges()
120
    }, (err) => { console.log(err) })
121
  }
122

123
  trustProductDescription (tableData: any[]) { // vuln-code-snippet neutral-line restfulXssChallenge
124
    for (let i = 0; i < tableData.length; i++) { // vuln-code-snippet neutral-line restfulXssChallenge
125
      tableData[i].description = this.sanitizer.bypassSecurityTrustHtml(tableData[i].description) // vuln-code-snippet vuln-line restfulXssChallenge
126
    } // vuln-code-snippet neutral-line restfulXssChallenge
127
  } // vuln-code-snippet neutral-line restfulXssChallenge
128
  // vuln-code-snippet end restfulXssChallenge
129

130
  ngOnDestroy () {
131
    if (this.routerSubscription) {
132
      this.routerSubscription.unsubscribe()
133
    }
134
    if (this.productSubscription) {
135
      this.productSubscription.unsubscribe()
136
    }
137
    if (this.dataSource) {
138
      this.dataSource.disconnect()
139
    }
140
  }
141

142
  // vuln-code-snippet start localXssChallenge xssBonusChallenge
143
  filterTable () {
144
    let queryParam: string = this.route.snapshot.queryParams.q
145
    if (queryParam) {
146
      queryParam = queryParam.trim()
147
      this.ngZone.runOutsideAngular(() => { // vuln-code-snippet hide-start
148
        this.io.socket().emit('verifyLocalXssChallenge', queryParam)
149
      }) // vuln-code-snippet hide-end
150
      this.dataSource.filter = queryParam.toLowerCase()
151
      this.searchValue = this.sanitizer.bypassSecurityTrustHtml(queryParam) // vuln-code-snippet vuln-line localXssChallenge xssBonusChallenge
152
      this.gridDataSource.subscribe((result: any) => {
153
        if (result.length === 0) {
154
          this.emptyState = true
155
        } else {
156
          this.emptyState = false
157
        }
158
      })
159
    } else {
160
      this.dataSource.filter = ''
161
      this.searchValue = undefined
162
      this.emptyState = false
163
    }
164
  }
165
  // vuln-code-snippet end localXssChallenge xssBonusChallenge
166

167
  startHackingInstructor (challengeName: string) {
168
    console.log(`Starting instructions for challenge "${challengeName}"`)
169
    import(/* webpackChunkName: "tutorial" */ '../../hacking-instructor').then(module => {
170
      module.startHackingInstructorFor(challengeName)
171
    })
172
  }
173

174
  showDetail (element: Product) {
175
    this.dialog.open(ProductDetailsComponent, {
176
      width: '500px',
177
      height: 'max-content',
178
      data: {
179
        productData: element
180
      }
181
    })
182
  }
183

184
  addToBasket (id?: number) {
185
    this.basketService.find(Number(sessionStorage.getItem('bid'))).subscribe((basket) => {
186
      const productsInBasket: any = basket.Products
187
      let found = false
188
      for (let i = 0; i < productsInBasket.length; i++) {
189
        if (productsInBasket[i].id === id) {
190
          found = true
191
          this.basketService.get(productsInBasket[i].BasketItem.id).subscribe((existingBasketItem) => {
192
            // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
193
            const newQuantity = existingBasketItem.quantity + 1
194
            this.basketService.put(existingBasketItem.id, { quantity: newQuantity }).subscribe((updatedBasketItem) => {
195
              this.productService.get(updatedBasketItem.ProductId).subscribe((product) => {
196
                this.translateService.get('BASKET_ADD_SAME_PRODUCT', { product: product.name }).subscribe((basketAddSameProduct) => {
197
                  this.snackBarHelperService.open(basketAddSameProduct, 'confirmBar')
198
                  this.basketService.updateNumberOfCartItems()
199
                }, (translationId) => {
200
                  this.snackBarHelperService.open(translationId, 'confirmBar')
201
                  this.basketService.updateNumberOfCartItems()
202
                })
203
              }, (err) => { console.log(err) })
204
            }, (err) => {
205
              this.snackBarHelperService.open(err.error?.error, 'errorBar')
206
              console.log(err)
207
            })
208
          }, (err) => { console.log(err) })
209
          break
210
        }
211
      }
212
      if (!found) {
213
        this.basketService.save({ ProductId: id, BasketId: sessionStorage.getItem('bid'), quantity: 1 }).subscribe((newBasketItem) => {
214
          this.productService.get(newBasketItem.ProductId).subscribe((product) => {
215
            this.translateService.get('BASKET_ADD_PRODUCT', { product: product.name }).subscribe((basketAddProduct) => {
216
              this.snackBarHelperService.open(basketAddProduct, 'confirmBar')
217
              this.basketService.updateNumberOfCartItems()
218
            }, (translationId) => {
219
              this.snackBarHelperService.open(translationId, 'confirmBar')
220
              this.basketService.updateNumberOfCartItems()
221
            })
222
          }, (err) => { console.log(err) })
223
        }, (err) => {
224
          this.snackBarHelperService.open(err.error?.error, 'errorBar')
225
          console.log(err)
226
        })
227
      }
228
    }, (err) => { console.log(err) })
229
  }
230

231
  isLoggedIn () {
232
    return localStorage.getItem('token')
233
  }
234

235
  onResize (event: any) {
236
    if (event.target.innerWidth < 2600) {
237
      this.breakpoint = 4
238
      if (event.target.innerWidth < 1740) {
239
        this.breakpoint = 3
240
        if (event.target.innerWidth < 1280) {
241
          this.breakpoint = 2
242
          if (event.target.innerWidth < 850) {
243
            this.breakpoint = 1
244
          }
245
        }
246
      }
247
    } else {
248
      this.breakpoint = 6
249
    }
250
  }
251

252
  isDeluxe () {
253
    return this.deluxeGuard.isDeluxe()
254
  }
255
}
256

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.