mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-21 02:21:17 +00:00
Security: remove safe html pipe
This commit is contained in:
@@ -28,7 +28,6 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
|||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||||
import { GroupService } from 'src/app/services/rest/group.service'
|
import { GroupService } from 'src/app/services/rest/group.service'
|
||||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
||||||
@@ -129,7 +128,6 @@ describe('SettingsComponent', () => {
|
|||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
CheckComponent,
|
CheckComponent,
|
||||||
ColorComponent,
|
ColorComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
SelectComponent,
|
SelectComponent,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
NumberComponent,
|
NumberComponent,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from '@ng-bootstrap/ng-bootstrap'
|
} from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
import { of, throwError } from 'rxjs'
|
import { of, throwError } from 'rxjs'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
import { TrashService } from 'src/app/services/trash.service'
|
import { TrashService } from 'src/app/services/trash.service'
|
||||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||||
@@ -53,7 +52,6 @@ describe('TrashComponent', () => {
|
|||||||
TrashComponent,
|
TrashComponent,
|
||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
],
|
],
|
||||||
}).compileComponents()
|
}).compileComponents()
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<p><b>{{messageBold}}</b></p>
|
<p><b>{{messageBold}}</b></p>
|
||||||
}
|
}
|
||||||
@if (message) {
|
@if (message) {
|
||||||
<p class="mb-0" [innerHTML]="message | safeHtml"></p>
|
<p class="mb-0" [innerHTML]="message"></p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Subject } from 'rxjs'
|
import { Subject } from 'rxjs'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { ConfirmDialogComponent } from './confirm-dialog.component'
|
import { ConfirmDialogComponent } from './confirm-dialog.component'
|
||||||
|
|
||||||
describe('ConfirmDialogComponent', () => {
|
describe('ConfirmDialogComponent', () => {
|
||||||
@@ -11,8 +10,8 @@ describe('ConfirmDialogComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [NgbActiveModal, SafeHtmlPipe],
|
providers: [NgbActiveModal],
|
||||||
imports: [ConfirmDialogComponent, SafeHtmlPipe],
|
imports: [ConfirmDialogComponent],
|
||||||
}).compileComponents()
|
}).compileComponents()
|
||||||
|
|
||||||
modal = TestBed.inject(NgbActiveModal)
|
modal = TestBed.inject(NgbActiveModal)
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ import { DecimalPipe } from '@angular/common'
|
|||||||
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
|
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Subject } from 'rxjs'
|
import { Subject } from 'rxjs'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pngx-confirm-dialog',
|
selector: 'pngx-confirm-dialog',
|
||||||
templateUrl: './confirm-dialog.component.html',
|
templateUrl: './confirm-dialog.component.html',
|
||||||
styleUrls: ['./confirm-dialog.component.scss'],
|
styleUrls: ['./confirm-dialog.component.scss'],
|
||||||
imports: [DecimalPipe, SafeHtmlPipe],
|
imports: [DecimalPipe],
|
||||||
})
|
})
|
||||||
export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
|
export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
|
||||||
activeModal = inject(NgbActiveModal)
|
activeModal = inject(NgbActiveModal)
|
||||||
|
|||||||
@@ -28,10 +28,10 @@
|
|||||||
<div class="modal-footer flex-nowrap">
|
<div class="modal-footer flex-nowrap">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@if (message) {
|
@if (message) {
|
||||||
<p [innerHTML]="message | safeHtml"></p>
|
<p>{{message}}</p>
|
||||||
}
|
}
|
||||||
@if (messageBold) {
|
@if (messageBold) {
|
||||||
<p class="mb-0 small"><b [innerHTML]="messageBold | safeHtml"></b></p>
|
<p class="mb-0 small"><b>{{messageBold}}</b></p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn" [class]="cancelBtnClass" (click)="cancel()" [disabled]="!buttonsEnabled">
|
<button type="button" class="btn" [class]="cancelBtnClass" (click)="cancel()" [disabled]="!buttonsEnabled">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { RotateConfirmDialogComponent } from './rotate-confirm-dialog.component'
|
import { RotateConfirmDialogComponent } from './rotate-confirm-dialog.component'
|
||||||
|
|
||||||
describe('RotateConfirmDialogComponent', () => {
|
describe('RotateConfirmDialogComponent', () => {
|
||||||
@@ -15,11 +14,9 @@ describe('RotateConfirmDialogComponent', () => {
|
|||||||
imports: [
|
imports: [
|
||||||
NgxBootstrapIconsModule.pick(allIcons),
|
NgxBootstrapIconsModule.pick(allIcons),
|
||||||
RotateConfirmDialogComponent,
|
RotateConfirmDialogComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
NgbActiveModal,
|
NgbActiveModal,
|
||||||
SafeHtmlPipe,
|
|
||||||
provideHttpClient(withInterceptorsFromDi()),
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
provideHttpClientTesting(),
|
provideHttpClientTesting(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { NgStyle } from '@angular/common'
|
import { NgStyle } from '@angular/common'
|
||||||
import { Component, inject } from '@angular/core'
|
import { Component, inject } from '@angular/core'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||||
import { ConfirmDialogComponent } from '../confirm-dialog.component'
|
import { ConfirmDialogComponent } from '../confirm-dialog.component'
|
||||||
|
|
||||||
@@ -9,7 +8,7 @@ import { ConfirmDialogComponent } from '../confirm-dialog.component'
|
|||||||
selector: 'pngx-rotate-confirm-dialog',
|
selector: 'pngx-rotate-confirm-dialog',
|
||||||
templateUrl: './rotate-confirm-dialog.component.html',
|
templateUrl: './rotate-confirm-dialog.component.html',
|
||||||
styleUrl: './rotate-confirm-dialog.component.scss',
|
styleUrl: './rotate-confirm-dialog.component.scss',
|
||||||
imports: [NgStyle, NgxBootstrapIconsModule, SafeHtmlPipe],
|
imports: [NgStyle, NgxBootstrapIconsModule],
|
||||||
})
|
})
|
||||||
export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
|
export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
|
||||||
documentService = inject(DocumentService)
|
documentService = inject(DocumentService)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
|||||||
import { CustomFieldDataType } from 'src/app/data/custom-field'
|
import { CustomFieldDataType } from 'src/app/data/custom-field'
|
||||||
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { SettingsService } from 'src/app/services/settings.service'
|
import { SettingsService } from 'src/app/services/settings.service'
|
||||||
import { SelectComponent } from '../../input/select/select.component'
|
import { SelectComponent } from '../../input/select/select.component'
|
||||||
import { TextComponent } from '../../input/text/text.component'
|
import { TextComponent } from '../../input/text/text.component'
|
||||||
@@ -35,7 +34,6 @@ describe('CustomFieldEditDialogComponent', () => {
|
|||||||
IfOwnerDirective,
|
IfOwnerDirective,
|
||||||
SelectComponent,
|
SelectComponent,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
NgbActiveModal,
|
NgbActiveModal,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from 'src/app/data/mail-rule'
|
} from 'src/app/data/mail-rule'
|
||||||
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
||||||
@@ -46,7 +45,6 @@ describe('MailRuleEditDialogComponent', () => {
|
|||||||
PermissionsFormComponent,
|
PermissionsFormComponent,
|
||||||
NumberComponent,
|
NumberComponent,
|
||||||
TagsComponent,
|
TagsComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
CheckComponent,
|
CheckComponent,
|
||||||
SwitchComponent,
|
SwitchComponent,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
} from 'src/app/data/workflow-trigger'
|
} from 'src/app/data/workflow-trigger'
|
||||||
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||||
@@ -105,7 +104,6 @@ describe('WorkflowEditDialogComponent', () => {
|
|||||||
TagsComponent,
|
TagsComponent,
|
||||||
PermissionsUserComponent,
|
PermissionsUserComponent,
|
||||||
PermissionsGroupComponent,
|
PermissionsGroupComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
ConfirmButtonComponent,
|
ConfirmButtonComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
<div class="invalid-feedback position-absolute top-100">
|
<div class="invalid-feedback position-absolute top-100">
|
||||||
{{error}}
|
{{error}}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
<input #inputField type="hidden" class="form-control small" [(ngModel)]="value" [disabled]="true">
|
<input #inputField type="hidden" class="form-control small" [(ngModel)]="value" [disabled]="true">
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
<div class="invalid-feedback position-absolute top-100">
|
<div class="invalid-feedback position-absolute top-100">
|
||||||
{{error}}
|
{{error}}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@
|
|||||||
{{error}}
|
{{error}}
|
||||||
</div>
|
</div>
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="position-relative" [class.col-md-9]="horizontal">
|
<div class="position-relative" [class.col-md-9]="horizontal">
|
||||||
<input #inputField type="text" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete" [placeholder]="placeholder">
|
<input #inputField type="text" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete" [placeholder]="placeholder">
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
<div class="invalid-feedback position-absolute top-100">
|
<div class="invalid-feedback position-absolute top-100">
|
||||||
{{error}}
|
{{error}}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
} from '@angular/forms'
|
} from '@angular/forms'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { AbstractInputComponent } from '../abstract-input'
|
import { AbstractInputComponent } from '../abstract-input'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -19,12 +18,7 @@ import { AbstractInputComponent } from '../abstract-input'
|
|||||||
selector: 'pngx-input-text',
|
selector: 'pngx-input-text',
|
||||||
templateUrl: './text.component.html',
|
templateUrl: './text.component.html',
|
||||||
styleUrls: ['./text.component.scss'],
|
styleUrls: ['./text.component.scss'],
|
||||||
imports: [
|
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
SafeHtmlPipe,
|
|
||||||
NgxBootstrapIconsModule,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class TextComponent extends AbstractInputComponent<string> {
|
export class TextComponent extends AbstractInputComponent<string> {
|
||||||
@Input()
|
@Input()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
rows="4">
|
rows="4">
|
||||||
</textarea>
|
</textarea>
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
<div class="invalid-feedback position-absolute top-100">
|
<div class="invalid-feedback position-absolute top-100">
|
||||||
{{error}}
|
{{error}}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
} from '@angular/forms'
|
} from '@angular/forms'
|
||||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { AbstractInputComponent } from '../abstract-input'
|
import { AbstractInputComponent } from '../abstract-input'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -19,12 +18,7 @@ import { AbstractInputComponent } from '../abstract-input'
|
|||||||
selector: 'pngx-input-textarea',
|
selector: 'pngx-input-textarea',
|
||||||
templateUrl: './textarea.component.html',
|
templateUrl: './textarea.component.html',
|
||||||
styleUrls: ['./textarea.component.scss'],
|
styleUrls: ['./textarea.component.scss'],
|
||||||
imports: [
|
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
SafeHtmlPipe,
|
|
||||||
NgxBootstrapIconsModule,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class TextAreaComponent extends AbstractInputComponent<string> {
|
export class TextAreaComponent extends AbstractInputComponent<string> {
|
||||||
@Input()
|
@Input()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (hint) {
|
@if (hint) {
|
||||||
<small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
<small class="form-text text-muted" [innerHTML]="hint"></small>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
|||||||
import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgSelectModule } from '@ng-select/ng-select'
|
import { NgSelectModule } from '@ng-select/ng-select'
|
||||||
import { of } from 'rxjs'
|
import { of } from 'rxjs'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { UserService } from 'src/app/services/rest/user.service'
|
import { UserService } from 'src/app/services/rest/user.service'
|
||||||
import { PermissionsFormComponent } from '../input/permissions/permissions-form/permissions-form.component'
|
import { PermissionsFormComponent } from '../input/permissions/permissions-form/permissions-form.component'
|
||||||
import { PermissionsGroupComponent } from '../input/permissions/permissions-group/permissions-group.component'
|
import { PermissionsGroupComponent } from '../input/permissions/permissions-group/permissions-group.component'
|
||||||
@@ -41,7 +40,6 @@ describe('PermissionsDialogComponent', () => {
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
PermissionsDialogComponent,
|
PermissionsDialogComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
SelectComponent,
|
SelectComponent,
|
||||||
SwitchComponent,
|
SwitchComponent,
|
||||||
PermissionsFormComponent,
|
PermissionsFormComponent,
|
||||||
|
|||||||
@@ -110,7 +110,9 @@
|
|||||||
<div class="visually-hidden" i18n>Loading...</div>
|
<div class="visually-hidden" i18n>Loading...</div>
|
||||||
} @else if (totpSettings) {
|
} @else if (totpSettings) {
|
||||||
<figure class="figure">
|
<figure class="figure">
|
||||||
<div class="bg-white d-inline-block" [innerHTML]="totpSettings.qr_svg | safeHtml"></div>
|
@if (qrSvgDataUrl) {
|
||||||
|
<img class="bg-white d-inline-block" [src]="qrSvgDataUrl" alt="Authenticator QR code">
|
||||||
|
}
|
||||||
<figcaption class="figure-caption text-end mt-2" i18n>Scan the QR code with your authenticator app and then enter the code below</figcaption>
|
<figcaption class="figure-caption text-end mt-2" i18n>Scan the QR code with your authenticator app and then enter the code below</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
SocialAccountProvider,
|
SocialAccountProvider,
|
||||||
TotpSettings,
|
TotpSettings,
|
||||||
} from 'src/app/data/user-profile'
|
} from 'src/app/data/user-profile'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { ProfileService } from 'src/app/services/profile.service'
|
import { ProfileService } from 'src/app/services/profile.service'
|
||||||
import { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
import { setLocationHref } from 'src/app/utils/navigation'
|
import { setLocationHref } from 'src/app/utils/navigation'
|
||||||
@@ -37,7 +36,6 @@ import { TextComponent } from '../input/text/text.component'
|
|||||||
PasswordComponent,
|
PasswordComponent,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
SafeHtmlPipe,
|
|
||||||
NgbAccordionModule,
|
NgbAccordionModule,
|
||||||
NgbPopoverModule,
|
NgbPopoverModule,
|
||||||
NgxBootstrapIconsModule,
|
NgxBootstrapIconsModule,
|
||||||
@@ -89,6 +87,13 @@ export class ProfileEditDialogComponent
|
|||||||
public socialAccounts: SocialAccount[] = []
|
public socialAccounts: SocialAccount[] = []
|
||||||
public socialAccountProviders: SocialAccountProvider[] = []
|
public socialAccountProviders: SocialAccountProvider[] = []
|
||||||
|
|
||||||
|
get qrSvgDataUrl(): string | null {
|
||||||
|
if (!this.totpSettings?.qr_svg) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return `data:image/svg+xml;utf8,${encodeURIComponent(this.totpSettings.qr_svg)}`
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.networkActive = true
|
this.networkActive = true
|
||||||
this.profileService
|
this.profileService
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
|||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||||
import { FilterPipe } from 'src/app/pipes/filter.pipe'
|
import { FilterPipe } from 'src/app/pipes/filter.pipe'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||||
@@ -103,7 +102,6 @@ describe('DocumentListComponent', () => {
|
|||||||
DatePipe,
|
DatePipe,
|
||||||
DocumentTitlePipe,
|
DocumentTitlePipe,
|
||||||
UsernamePipe,
|
UsernamePipe,
|
||||||
SafeHtmlPipe,
|
|
||||||
PermissionsGuard,
|
PermissionsGuard,
|
||||||
provideHttpClient(withInterceptorsFromDi()),
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
provideHttpClientTesting(),
|
provideHttpClientTesting(),
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
|||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
||||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||||
@@ -84,7 +83,6 @@ describe('MailComponent', () => {
|
|||||||
CustomDatePipe,
|
CustomDatePipe,
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
CheckComponent,
|
CheckComponent,
|
||||||
SafeHtmlPipe,
|
|
||||||
SelectComponent,
|
SelectComponent,
|
||||||
TextComponent,
|
TextComponent,
|
||||||
PasswordComponent,
|
PasswordComponent,
|
||||||
|
|||||||
@@ -94,8 +94,14 @@
|
|||||||
<td scope="row">{{ getDocumentCount(object) }}</td>
|
<td scope="row">{{ getDocumentCount(object) }}</td>
|
||||||
@for (column of extraColumns; track column) {
|
@for (column of extraColumns; track column) {
|
||||||
<td scope="row" [ngClass]="{ 'd-none d-sm-table-cell' : column.hideOnMobile }">
|
<td scope="row" [ngClass]="{ 'd-none d-sm-table-cell' : column.hideOnMobile }">
|
||||||
@if (column.rendersHtml) {
|
@if (column.badgeFn) {
|
||||||
<div [innerHtml]="column.valueFn.call(null, object) | safeHtml"></div>
|
<span
|
||||||
|
class="badge"
|
||||||
|
[style.color]="column.badgeFn.call(null, object)?.textColor"
|
||||||
|
[style.backgroundColor]="column.badgeFn.call(null, object)?.backgroundColor"
|
||||||
|
>
|
||||||
|
{{ column.badgeFn.call(null, object)?.text }}
|
||||||
|
</span>
|
||||||
} @else if (column.monospace) {
|
} @else if (column.monospace) {
|
||||||
<span class="font-monospace">{{ column.valueFn.call(null, object) }}</span>
|
<span class="font-monospace">{{ column.valueFn.call(null, object) }}</span>
|
||||||
} @else {
|
} @else {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import { Tag } from 'src/app/data/tag'
|
|||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||||
import {
|
import {
|
||||||
PermissionAction,
|
PermissionAction,
|
||||||
@@ -93,7 +92,6 @@ describe('ManagementListComponent', () => {
|
|||||||
SortableDirective,
|
SortableDirective,
|
||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
IfPermissionsDirective,
|
IfPermissionsDirective,
|
||||||
SafeHtmlPipe,
|
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
PermissionsDialogComponent,
|
PermissionsDialogComponent,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -48,9 +48,13 @@ export interface ManagementListColumn {
|
|||||||
|
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
valueFn: any
|
valueFn?: any
|
||||||
|
|
||||||
rendersHtml?: boolean
|
badgeFn?: (object: any) => {
|
||||||
|
text: string
|
||||||
|
textColor?: string
|
||||||
|
backgroundColor?: string
|
||||||
|
}
|
||||||
|
|
||||||
hideOnMobile?: boolean
|
hideOnMobile?: boolean
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { of } from 'rxjs'
|
|||||||
import { StoragePath } from 'src/app/data/storage-path'
|
import { StoragePath } from 'src/app/data/storage-path'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||||
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
|
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
|
||||||
import { StoragePathListComponent } from './storage-path-list.component'
|
import { StoragePathListComponent } from './storage-path-list.component'
|
||||||
@@ -30,7 +29,6 @@ describe('StoragePathListComponent', () => {
|
|||||||
SortableDirective,
|
SortableDirective,
|
||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
IfPermissionsDirective,
|
IfPermissionsDirective,
|
||||||
SafeHtmlPipe,
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
DatePipe,
|
DatePipe,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { FILTER_HAS_STORAGE_PATH_ANY } from 'src/app/data/filter-rule-type'
|
|||||||
import { StoragePath } from 'src/app/data/storage-path'
|
import { StoragePath } from 'src/app/data/storage-path'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { PermissionType } from 'src/app/services/permissions.service'
|
import { PermissionType } from 'src/app/services/permissions.service'
|
||||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||||
import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
||||||
@@ -26,7 +25,6 @@ import { ManagementListComponent } from '../management-list/management-list.comp
|
|||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
TitleCasePipe,
|
TitleCasePipe,
|
||||||
IfPermissionsDirective,
|
IfPermissionsDirective,
|
||||||
SafeHtmlPipe,
|
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
NgClass,
|
NgClass,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
|||||||
import { of } from 'rxjs'
|
import { of } from 'rxjs'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { TagService } from 'src/app/services/rest/tag.service'
|
import { TagService } from 'src/app/services/rest/tag.service'
|
||||||
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
|
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
|
||||||
import { TagListComponent } from './tag-list.component'
|
import { TagListComponent } from './tag-list.component'
|
||||||
@@ -30,7 +29,6 @@ describe('TagListComponent', () => {
|
|||||||
SortableDirective,
|
SortableDirective,
|
||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
IfPermissionsDirective,
|
IfPermissionsDirective,
|
||||||
SafeHtmlPipe,
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
DatePipe,
|
DatePipe,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type'
|
|||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
|
||||||
import { PermissionType } from 'src/app/services/permissions.service'
|
import { PermissionType } from 'src/app/services/permissions.service'
|
||||||
import { TagService } from 'src/app/services/rest/tag.service'
|
import { TagService } from 'src/app/services/rest/tag.service'
|
||||||
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
|
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
|
||||||
@@ -26,7 +25,6 @@ import { ManagementListComponent } from '../management-list/management-list.comp
|
|||||||
PageHeaderComponent,
|
PageHeaderComponent,
|
||||||
TitleCasePipe,
|
TitleCasePipe,
|
||||||
IfPermissionsDirective,
|
IfPermissionsDirective,
|
||||||
SafeHtmlPipe,
|
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
NgClass,
|
NgClass,
|
||||||
@@ -49,10 +47,11 @@ export class TagListComponent extends ManagementListComponent<Tag> {
|
|||||||
{
|
{
|
||||||
key: 'color',
|
key: 'color',
|
||||||
name: $localize`Color`,
|
name: $localize`Color`,
|
||||||
rendersHtml: true,
|
badgeFn: (t: Tag) => ({
|
||||||
valueFn: (t: Tag) => {
|
text: t.color,
|
||||||
return `<span class="badge" style="color: ${t.text_color}; background-color: ${t.color}">${t.color}</span>`
|
textColor: t.text_color,
|
||||||
},
|
backgroundColor: t.color,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing'
|
|
||||||
import { BrowserModule, DomSanitizer } from '@angular/platform-browser'
|
|
||||||
import { SafeHtmlPipe } from './safehtml.pipe'
|
|
||||||
|
|
||||||
describe('SafeHtmlPipe', () => {
|
|
||||||
let pipe: SafeHtmlPipe
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [SafeHtmlPipe],
|
|
||||||
imports: [BrowserModule],
|
|
||||||
})
|
|
||||||
pipe = TestBed.inject(SafeHtmlPipe)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should bypass security and trust the url', () => {
|
|
||||||
const html = '<div>some content</div>'
|
|
||||||
const domSanitizer = TestBed.inject(DomSanitizer)
|
|
||||||
const sanitizerSpy = jest.spyOn(domSanitizer, 'bypassSecurityTrustHtml')
|
|
||||||
let safeHtml = pipe.transform(html)
|
|
||||||
expect(safeHtml).not.toBeNull()
|
|
||||||
expect(sanitizerSpy).toHaveBeenCalled()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Pipe, PipeTransform, inject } from '@angular/core'
|
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
|
||||||
|
|
||||||
@Pipe({
|
|
||||||
name: 'safeHtml',
|
|
||||||
})
|
|
||||||
export class SafeHtmlPipe implements PipeTransform {
|
|
||||||
private sanitizer = inject(DomSanitizer)
|
|
||||||
|
|
||||||
transform(html) {
|
|
||||||
return this.sanitizer.bypassSecurityTrustHtml(html)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user