Browse Source

Security fixes (#1328)

* Security fixes.

* Fix build.

* Fix build.

* UI fixes.

* Fix asset tags.

* Info the save the query.
master
Sebastian Stehle 2 weeks ago
committed by GitHub
parent
commit
0ecfe2fc68
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      backend/i18n/frontend_de.json
  2. 1
      backend/i18n/frontend_en.json
  3. 1
      backend/i18n/frontend_fr.json
  4. 1
      backend/i18n/frontend_it.json
  5. 1
      backend/i18n/frontend_nl.json
  6. 1
      backend/i18n/frontend_pt.json
  7. 1
      backend/i18n/frontend_zh.json
  8. 1
      backend/i18n/source/frontend_en.json
  9. 2
      frontend/src/app/features/assets/pages/asset-tags.component.html
  10. 12
      frontend/src/app/features/assets/pages/asset-tags.component.scss
  11. 1
      frontend/src/app/framework/angular/forms/editors/date-time-editor.component.html
  12. 2
      frontend/src/app/framework/angular/modals/dialog-renderer.component.html
  13. 6
      frontend/src/app/shared/components/search/query-list.component.html
  14. 14
      frontend/src/app/shared/components/search/query-list.component.scss
  15. 7
      frontend/src/app/shared/components/search/search-form.component.html
  16. 20
      frontend/src/app/shared/components/search/search-form.component.ts

1
backend/i18n/frontend_de.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Suchen Sie nach {types} und verwenden Sie das <i class=\"icon-star-empty\"></i>-Symbol im Suchformular, um die Abfrage für alle Mitwirkenden zu speichern.", "search.queriesEmpty": "Suchen Sie nach {types} und verwenden Sie das <i class=\"icon-star-empty\"></i>-Symbol im Suchformular, um die Abfrage für alle Mitwirkenden zu speichern.",
"search.queryAllNewestFirst": "Alle (neueste zuerst)", "search.queryAllNewestFirst": "Alle (neueste zuerst)",
"search.queryAllOldestFirst": "Alle (älteste zuerst)", "search.queryAllOldestFirst": "Alle (älteste zuerst)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Schnellnavigation (Taste 'q' drücken)", "search.quickNavPlaceholder": "Schnellnavigation (Taste 'q' drücken)",
"search.saveQueryMyself": "Die Abfrage nur für mich speichern.", "search.saveQueryMyself": "Die Abfrage nur für mich speichern.",
"search.searchFailed": "Fehler bei der Suche. Bitte neu laden.", "search.searchFailed": "Fehler bei der Suche. Bitte neu laden.",

1
backend/i18n/frontend_en.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Search for {types} and use <i class=\"icon-star-empty\"></i> icon in search form to save query for all contributors.", "search.queriesEmpty": "Search for {types} and use <i class=\"icon-star-empty\"></i> icon in search form to save query for all contributors.",
"search.queryAllNewestFirst": "All (newest first)", "search.queryAllNewestFirst": "All (newest first)",
"search.queryAllOldestFirst": "All (oldest first)", "search.queryAllOldestFirst": "All (oldest first)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Quick Nav (Press 'q')", "search.quickNavPlaceholder": "Quick Nav (Press 'q')",
"search.saveQueryMyself": "Save the query only for myself.", "search.saveQueryMyself": "Save the query only for myself.",
"search.searchFailed": "Failed to make search. Please reload.", "search.searchFailed": "Failed to make search. Please reload.",

1
backend/i18n/frontend_fr.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Recherchez {types} et utilisez<i class=\"icon-star-empty\"></i> icône dans le formulaire de recherche pour enregistrer la requête pour tous les contributeurs.", "search.queriesEmpty": "Recherchez {types} et utilisez<i class=\"icon-star-empty\"></i> icône dans le formulaire de recherche pour enregistrer la requête pour tous les contributeurs.",
"search.queryAllNewestFirst": "Tous (le plus récent en premier)", "search.queryAllNewestFirst": "Tous (le plus récent en premier)",
"search.queryAllOldestFirst": "Tous (le plus ancien en premier)", "search.queryAllOldestFirst": "Tous (le plus ancien en premier)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Navigation rapide (Appuyez sur 'q')", "search.quickNavPlaceholder": "Navigation rapide (Appuyez sur 'q')",
"search.saveQueryMyself": "Enregistrer la requête uniquement pour moi-même.", "search.saveQueryMyself": "Enregistrer la requête uniquement pour moi-même.",
"search.searchFailed": "Échec de la recherche. Veuillez recharger.", "search.searchFailed": "Échec de la recherche. Veuillez recharger.",

1
backend/i18n/frontend_it.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Ricerca per {types} e utilizza l'icona <i class=\"icon-star-empty\"></i> nella ricerca per salvare la query per tutti i collaboratori.", "search.queriesEmpty": "Ricerca per {types} e utilizza l'icona <i class=\"icon-star-empty\"></i> nella ricerca per salvare la query per tutti i collaboratori.",
"search.queryAllNewestFirst": "Tutto (prima i più recenti)", "search.queryAllNewestFirst": "Tutto (prima i più recenti)",
"search.queryAllOldestFirst": "Tutto (prima i meno recenti)", "search.queryAllOldestFirst": "Tutto (prima i meno recenti)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Navigazione veloce (Press 'q')", "search.quickNavPlaceholder": "Navigazione veloce (Press 'q')",
"search.saveQueryMyself": "Salva la query solamente per me.", "search.saveQueryMyself": "Salva la query solamente per me.",
"search.searchFailed": "Non è stato possibile eseguire la ricerca. Per favore ricarica.", "search.searchFailed": "Non è stato possibile eseguire la ricerca. Per favore ricarica.",

1
backend/i18n/frontend_nl.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Zoek naar {types} en gebruik <i class = \" icon-star-empty \"> </i> icon in het zoekformulier om de zoekopdracht op te slaan voor alle bijdragers.", "search.queriesEmpty": "Zoek naar {types} en gebruik <i class = \" icon-star-empty \"> </i> icon in het zoekformulier om de zoekopdracht op te slaan voor alle bijdragers.",
"search.queryAllNewestFirst": "Alle (nieuwste eerst)", "search.queryAllNewestFirst": "Alle (nieuwste eerst)",
"search.queryAllOldestFirst": "Alle (oudste eerst)", "search.queryAllOldestFirst": "Alle (oudste eerst)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Snelle navigatie (druk op 'q')", "search.quickNavPlaceholder": "Snelle navigatie (druk op 'q')",
"search.saveQueryMyself": "Bewaar de zoekopdracht alleen voor mezelf.", "search.saveQueryMyself": "Bewaar de zoekopdracht alleen voor mezelf.",
"search.searchFailed": "Zoeken mislukt. Laad opnieuw.", "search.searchFailed": "Zoeken mislukt. Laad opnieuw.",

1
backend/i18n/frontend_pt.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Procure por {types} e use <i class=\"icon-star-empty\"></i> ícone em forma de pesquisa para guardar consulta para todos os contribuintes.", "search.queriesEmpty": "Procure por {types} e use <i class=\"icon-star-empty\"></i> ícone em forma de pesquisa para guardar consulta para todos os contribuintes.",
"search.queryAllNewestFirst": "Todos (o mais novo primeiro)", "search.queryAllNewestFirst": "Todos (o mais novo primeiro)",
"search.queryAllOldestFirst": "Todos (o mais velho primeiro)", "search.queryAllOldestFirst": "Todos (o mais velho primeiro)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Quick Nav (Prima 'q')", "search.quickNavPlaceholder": "Quick Nav (Prima 'q')",
"search.saveQueryMyself": "Guarde a consulta apenas para mim.", "search.saveQueryMyself": "Guarde a consulta apenas para mim.",
"search.searchFailed": "Falhou em fazer uma busca. Por favor, recarregue.", "search.searchFailed": "Falhou em fazer uma busca. Por favor, recarregue.",

1
backend/i18n/frontend_zh.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "搜索 {types} 并在搜索表单中使用 <i class=\"icon-star-empty\"></i> 图标来保存所有贡献者的查询。", "search.queriesEmpty": "搜索 {types} 并在搜索表单中使用 <i class=\"icon-star-empty\"></i> 图标来保存所有贡献者的查询。",
"search.queryAllNewestFirst": "全部(最新的在前)", "search.queryAllNewestFirst": "全部(最新的在前)",
"search.queryAllOldestFirst": "所有(最旧的在前)", "search.queryAllOldestFirst": "所有(最旧的在前)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "快速导航(按'q')", "search.quickNavPlaceholder": "快速导航(按'q')",
"search.saveQueryMyself": "只为我保存查询。", "search.saveQueryMyself": "只为我保存查询。",
"search.searchFailed": "搜索失败,请重新加载。", "search.searchFailed": "搜索失败,请重新加载。",

1
backend/i18n/source/frontend_en.json

@ -1130,6 +1130,7 @@
"search.queriesEmpty": "Search for {types} and use <i class=\"icon-star-empty\"></i> icon in search form to save query for all contributors.", "search.queriesEmpty": "Search for {types} and use <i class=\"icon-star-empty\"></i> icon in search form to save query for all contributors.",
"search.queryAllNewestFirst": "All (newest first)", "search.queryAllNewestFirst": "All (newest first)",
"search.queryAllOldestFirst": "All (oldest first)", "search.queryAllOldestFirst": "All (oldest first)",
"search.queryNotUsed": "Run the query before you save it",
"search.quickNavPlaceholder": "Quick Nav (Press 'q')", "search.quickNavPlaceholder": "Quick Nav (Press 'q')",
"search.saveQueryMyself": "Save the query only for myself.", "search.saveQueryMyself": "Save the query only for myself.",
"search.searchFailed": "Failed to make search. Please reload.", "search.searchFailed": "Failed to make search. Please reload.",

2
frontend/src/app/features/assets/pages/asset-tags.component.html

@ -16,7 +16,7 @@
@if (canRename) { @if (canRename) {
<button <button
class="btn-sm btn-text-secondary btn-rename" class="btn btn-sm btn-text-secondary btn-rename"
attr.aria-label="{{ 'common.rename' | sqxTranslate }}" attr.aria-label="{{ 'common.rename' | sqxTranslate }}"
(click)="renameTag(tag)" (click)="renameTag(tag)"
sqxStopClick sqxStopClick

12
frontend/src/app/features/assets/pages/asset-tags.component.scss

@ -29,6 +29,18 @@
} }
.nav-item { .nav-item {
.nav-link {
display: flex;
align-items: center;
width: 100%;
text-align: left;
text-decoration: none;
}
.row {
width: 100%;
}
&:hover { &:hover {
.btn-rename { .btn-rename {
display: block; display: block;

1
frontend/src/app/framework/angular/forms/editors/date-time-editor.component.html

@ -28,6 +28,7 @@
(ngModelChange)="updateValue($event)" (ngModelChange)="updateValue($event)"
[ngModelOptions]="{ standalone: true }" [ngModelOptions]="{ standalone: true }"
placeholder="{{ 'common.date' | sqxTranslate }}" placeholder="{{ 'common.date' | sqxTranslate }}"
step="1"
sqxForwardFormClasses sqxForwardFormClasses
[type]="isDateTimeMode ? 'datetime-local' : 'date'" /> [type]="isDateTimeMode ? 'datetime-local' : 'date'" />
</div> </div>

2
frontend/src/app/framework/angular/modals/dialog-renderer.component.html

@ -28,7 +28,7 @@
animate.leave="fade-out" animate.leave="fade-out"
(click)="close(notification)" (click)="close(notification)"
role="alert"> role="alert">
<button class="btn-sm btn-close" data-dismiss="alert" (dialogClose)="close(notification)" type="button"></button> <button class="btn btn-sm btn-close" data-dismiss="alert" (dialogClose)="close(notification)" type="button"></button>
<div class="timer timer-{{ notification.messageType }}"></div> <div class="timer timer-{{ notification.messageType }}"></div>
<div [sqxMarkdown]="notification.message | sqxTranslate"></div> <div [sqxMarkdown]="notification.message | sqxTranslate"></div>
</div> </div>

6
frontend/src/app/shared/components/search/query-list.component.html

@ -2,8 +2,8 @@
<ul class="nav nav-light flex-column"> <ul class="nav nav-light flex-column">
@for (saved of queries; track saved.name) { @for (saved of queries; track saved.name) {
<li class="nav-item"> <li class="nav-item">
<button class="nav-link" [class.active]="isSelectedQuery(saved)" (click)="search.emit(saved.query)" type="button"> <button class="nav-link w-full" [class.active]="isSelectedQuery(saved)" (click)="search.emit(saved.query)" type="button">
<div class="row g-0"> <div class="row g-1 align-items-center">
<div class="col truncate"> <div class="col truncate">
<i class="icon-circle" [class.hidden]="!saved.color" [style.color]="saved.color"></i> <i class="icon-circle" [class.hidden]="!saved.color" [style.color]="saved.color"></i>
{{ saved.name | sqxTranslate }} {{ saved.name | sqxTranslate }}
@ -12,7 +12,7 @@
<div class="col-auto"> <div class="col-auto">
@if (canRemove) { @if (canRemove) {
<button <button
class="btn-sm btn-text-danger btn-remove" class="btn btn-sm btn-text-danger btn-remove"
attr.aria-label="{{ 'common.delete' | sqxTranslate }}" attr.aria-label="{{ 'common.delete' | sqxTranslate }}"
(click)="remove.emit(saved)" (click)="remove.emit(saved)"
sqxStopClick sqxStopClick

14
frontend/src/app/shared/components/search/query-list.component.scss

@ -3,6 +3,8 @@
.btn-remove { .btn-remove {
visibility: hidden; visibility: hidden;
margin-left: 0;
margin-right: -.5rem;
i { i {
margin: 0; margin: 0;
@ -10,6 +12,18 @@
} }
.nav-item { .nav-item {
.nav-link {
display: flex;
align-items: center;
width: 100%;
text-align: left;
text-decoration: none;
}
.row {
width: 100%;
}
&:hover { &:hover {
.btn-remove { .btn-remove {
visibility: visible; visibility: visible;

7
frontend/src/app/shared/components/search/search-form.component.html

@ -72,6 +72,8 @@
<sqx-modal-dialog (dialogClose)="saveQueryDialog.hide()"> <sqx-modal-dialog (dialogClose)="saveQueryDialog.hide()">
<ng-container title> {{ "search.nameQuery" | sqxTranslate }}</ng-container> <ng-container title> {{ "search.nameQuery" | sqxTranslate }}</ng-container>
<ng-container content> <ng-container content>
<sqx-form-error [error]="saveQueryForm.error | async" />
<sqx-form-row for="name" label="common.name" vertical> <sqx-form-row for="name" label="common.name" vertical>
<input class="form-control" id="name" autocomplete="off" formControlName="name" sqxFocusOnInit /> <input class="form-control" id="name" autocomplete="off" formControlName="name" sqxFocusOnInit />
</sqx-form-row> </sqx-form-row>
@ -79,11 +81,6 @@
<sqx-form-row check for="user" label="search.saveQueryMyself" vertical> <sqx-form-row check for="user" label="search.saveQueryMyself" vertical>
<input class="form-check-input" id="user" formControlName="user" type="checkbox" /> <input class="form-check-input" id="user" formControlName="user" type="checkbox" />
</sqx-form-row> </sqx-form-row>
<div class="form-check">
<input class="form-check-input" id="user" formControlName="user" type="checkbox" />
<label class="form-check-label" for="user"> {{ "search.saveQueryMyself" | sqxTranslate }}</label>
</div>
</ng-container> </ng-container>
<ng-container footer> <ng-container footer>
<button class="btn btn-text-secondary" (click)="saveQueryDialog.hide()" type="button"> <button class="btn btn-text-secondary" (click)="saveQueryDialog.hide()" type="button">

20
frontend/src/app/shared/components/search/search-form.component.ts

@ -10,7 +10,7 @@ import { booleanAttribute, ChangeDetectionStrategy, Component, EventEmitter, Inp
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BooleanValue, BootstrapClasses, EMPTY_FILTER_MODEL, FieldComponent, FilterField, Input as FilterInput, FilterModel, FilterOptions, NumberValue, SelectValue, StringValue } from 'ngx-inline-filter'; import { BooleanValue, BootstrapClasses, EMPTY_FILTER_MODEL, FieldComponent, FilterField, Input as FilterInput, FilterModel, FilterOptions, NumberValue, SelectValue, StringValue } from 'ngx-inline-filter';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { DateTimeEditorComponent, DropdownComponent, FocusOnInitDirective, FormRowComponent, HighlightPipe, LocalizerService, ModalDialogComponent, ModalDirective, ShortcutComponent, TooltipDirective, TourStepDirective, TranslatePipe, Types } from '@app/framework'; import { DateTimeEditorComponent, DropdownComponent, FocusOnInitDirective, FormErrorComponent, FormRowComponent, HighlightPipe, LocalizerService, ModalDialogComponent, ModalDirective, ShortcutComponent, TooltipDirective, TourStepDirective, TranslatePipe, Types } from '@app/framework';
import { AppLanguageDto, ContributorsState, DialogModel, Queries, Query, QueryModel, sanitize, SaveQueryForm, TypedSimpleChanges } from '@app/shared/internal'; import { AppLanguageDto, ContributorsState, DialogModel, Queries, Query, QueryModel, sanitize, SaveQueryForm, TypedSimpleChanges } from '@app/shared/internal';
import { UserDtoPicture } from '../pipes'; import { UserDtoPicture } from '../pipes';
import { ReferenceInputComponent } from '../references/reference-input.component'; import { ReferenceInputComponent } from '../references/reference-input.component';
@ -40,6 +40,7 @@ import { TourHintDirective } from '../tour-hint.directive';
TourStepDirective, TourStepDirective,
TranslatePipe, TranslatePipe,
UserDtoPicture, UserDtoPicture,
FormErrorComponent,
], ],
}) })
export class SearchFormComponent { export class SearchFormComponent {
@ -217,16 +218,19 @@ export class SearchFormComponent {
public saveQueryComplete() { public saveQueryComplete() {
const value = this.saveQueryForm.submit(); const value = this.saveQueryForm.submit();
if (!value) { if (!value || !this.queries) {
return; return;
} }
if (this.queries && this.query) { if (!this.query) {
if (value.user) { this.saveQueryForm.submitFailed('i18n:search.queryNotUsed')
this.queries.addUser(value.name, this.query); return;
} else { }
this.queries.addShared(value.name, this.query);
} if (value.user) {
this.queries.addUser(value.name, this.query);
} else {
this.queries.addShared(value.name, this.query);
} }
this.saveQueryForm.submitCompleted(); this.saveQueryForm.submitCompleted();

Loading…
Cancel
Save