import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
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 { GroupService } from 'src/app/services/rest/group.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
ConfirmDialogComponent,
CheckComponent,
ColorComponent,
- SafeHtmlPipe,
SelectComponent,
TextComponent,
NumberComponent,
} from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { of, throwError } from 'rxjs'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { ToastService } from 'src/app/services/toast.service'
import { TrashService } from 'src/app/services/trash.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
TrashComponent,
PageHeaderComponent,
ConfirmDialogComponent,
- SafeHtmlPipe,
],
}).compileComponents()
<p><b>{{messageBold}}</b></p>
}
@if (message) {
- <p class="mb-0" [innerHTML]="message | safeHtml"></p>
+ <p class="mb-0" [innerHTML]="message"></p>
}
</div>
<div class="modal-footer">
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Subject } from 'rxjs'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { ConfirmDialogComponent } from './confirm-dialog.component'
describe('ConfirmDialogComponent', () => {
beforeEach(async () => {
TestBed.configureTestingModule({
- providers: [NgbActiveModal, SafeHtmlPipe],
- imports: [ConfirmDialogComponent, SafeHtmlPipe],
+ providers: [NgbActiveModal],
+ imports: [ConfirmDialogComponent],
}).compileComponents()
modal = TestBed.inject(NgbActiveModal)
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Subject } from 'rxjs'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
@Component({
selector: 'pngx-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.scss'],
- imports: [DecimalPipe, SafeHtmlPipe],
+ imports: [DecimalPipe],
})
export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
activeModal = inject(NgbActiveModal)
<div class="modal-footer flex-nowrap">
<div class="col">
@if (message) {
- <p [innerHTML]="message | safeHtml"></p>
+ <p>{{message}}</p>
}
@if (messageBold) {
- <p class="mb-0 small"><b [innerHTML]="messageBold | safeHtml"></b></p>
+ <p class="mb-0 small"><b>{{messageBold}}</b></p>
}
</div>
<button type="button" class="btn" [class]="cancelBtnClass" (click)="cancel()" [disabled]="!buttonsEnabled">
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { RotateConfirmDialogComponent } from './rotate-confirm-dialog.component'
describe('RotateConfirmDialogComponent', () => {
imports: [
NgxBootstrapIconsModule.pick(allIcons),
RotateConfirmDialogComponent,
- SafeHtmlPipe,
],
providers: [
NgbActiveModal,
- SafeHtmlPipe,
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(),
],
import { NgStyle } from '@angular/common'
import { Component, inject } from '@angular/core'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { DocumentService } from 'src/app/services/rest/document.service'
import { ConfirmDialogComponent } from '../confirm-dialog.component'
selector: 'pngx-rotate-confirm-dialog',
templateUrl: './rotate-confirm-dialog.component.html',
styleUrl: './rotate-confirm-dialog.component.scss',
- imports: [NgStyle, NgxBootstrapIconsModule, SafeHtmlPipe],
+ imports: [NgStyle, NgxBootstrapIconsModule],
})
export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
documentService = inject(DocumentService)
import { CustomFieldDataType } from 'src/app/data/custom-field'
import { IfOwnerDirective } from 'src/app/directives/if-owner.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 { SelectComponent } from '../../input/select/select.component'
import { TextComponent } from '../../input/text/text.component'
IfOwnerDirective,
SelectComponent,
TextComponent,
- SafeHtmlPipe,
],
providers: [
NgbActiveModal,
} from 'src/app/data/mail-rule'
import { IfOwnerDirective } from 'src/app/directives/if-owner.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 { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
PermissionsFormComponent,
NumberComponent,
TagsComponent,
- SafeHtmlPipe,
CheckComponent,
SwitchComponent,
],
} from 'src/app/data/workflow-trigger'
import { IfOwnerDirective } from 'src/app/directives/if-owner.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 { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
TagsComponent,
PermissionsUserComponent,
PermissionsGroupComponent,
- SafeHtmlPipe,
ConfirmButtonComponent,
],
providers: [
</div>
}
@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">
{{error}}
}
<input #inputField type="hidden" class="form-control small" [(ngModel)]="value" [disabled]="true">
@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">
{{error}}
{{error}}
</div>
@if (hint) {
- <small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
+ <small class="form-text text-muted" [innerHTML]="hint"></small>
}
</div>
<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">
@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">
{{error}}
ReactiveFormsModule,
} from '@angular/forms'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { AbstractInputComponent } from '../abstract-input'
@Component({
selector: 'pngx-input-text',
templateUrl: './text.component.html',
styleUrls: ['./text.component.scss'],
- imports: [
- FormsModule,
- ReactiveFormsModule,
- SafeHtmlPipe,
- NgxBootstrapIconsModule,
- ],
+ imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
})
export class TextComponent extends AbstractInputComponent<string> {
@Input()
rows="4">
</textarea>
@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">
{{error}}
ReactiveFormsModule,
} from '@angular/forms'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { AbstractInputComponent } from '../abstract-input'
@Component({
selector: 'pngx-input-textarea',
templateUrl: './textarea.component.html',
styleUrls: ['./textarea.component.scss'],
- imports: [
- FormsModule,
- ReactiveFormsModule,
- SafeHtmlPipe,
- NgxBootstrapIconsModule,
- ],
+ imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
})
export class TextAreaComponent extends AbstractInputComponent<string> {
@Input()
</div>
</div>
@if (hint) {
- <small class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
+ <small class="form-text text-muted" [innerHTML]="hint"></small>
}
</div>
</div>
import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectModule } from '@ng-select/ng-select'
import { of } from 'rxjs'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { UserService } from 'src/app/services/rest/user.service'
import { PermissionsFormComponent } from '../input/permissions/permissions-form/permissions-form.component'
import { PermissionsGroupComponent } from '../input/permissions/permissions-group/permissions-group.component'
ReactiveFormsModule,
NgbModule,
PermissionsDialogComponent,
- SafeHtmlPipe,
SelectComponent,
SwitchComponent,
PermissionsFormComponent,
<div class="visually-hidden" i18n>Loading...</div>
} @else if (totpSettings) {
<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>
</figure>
<p>
SocialAccountProvider,
TotpSettings,
} from 'src/app/data/user-profile'
-import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { ProfileService } from 'src/app/services/profile.service'
import { ToastService } from 'src/app/services/toast.service'
import { setLocationHref } from 'src/app/utils/navigation'
PasswordComponent,
FormsModule,
ReactiveFormsModule,
- SafeHtmlPipe,
NgbAccordionModule,
NgbPopoverModule,
NgxBootstrapIconsModule,
public socialAccounts: SocialAccount[] = []
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 {
this.networkActive = true
this.profileService
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.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 { DocumentListViewService } from 'src/app/services/document-list-view.service'
import { PermissionsService } from 'src/app/services/permissions.service'
DatePipe,
DocumentTitlePipe,
UsernamePipe,
- SafeHtmlPipe,
PermissionsGuard,
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(),
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
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 { MailAccountService } from 'src/app/services/rest/mail-account.service'
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
CustomDatePipe,
ConfirmDialogComponent,
CheckComponent,
- SafeHtmlPipe,
SelectComponent,
TextComponent,
PasswordComponent,
<td scope="row">{{ getDocumentCount(object) }}</td>
@for (column of extraColumns; track column) {
<td scope="row" [ngClass]="{ 'd-none d-sm-table-cell' : column.hideOnMobile }">
- @if (column.rendersHtml) {
- <div [innerHtml]="column.valueFn.call(null, object) | safeHtml"></div>
+ @if (column.badgeFn) {
+ <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) {
<span class="font-monospace">{{ column.valueFn.call(null, object) }}</span>
} @else {
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive'
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 {
PermissionAction,
SortableDirective,
PageHeaderComponent,
IfPermissionsDirective,
- SafeHtmlPipe,
ConfirmDialogComponent,
PermissionsDialogComponent,
],
name: string
- valueFn: any
+ valueFn?: any
- rendersHtml?: boolean
+ badgeFn?: (object: any) => {
+ text: string
+ textColor?: string
+ backgroundColor?: string
+ }
hideOnMobile?: boolean
import { StoragePath } from 'src/app/data/storage-path'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.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 { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { StoragePathListComponent } from './storage-path-list.component'
SortableDirective,
PageHeaderComponent,
IfPermissionsDirective,
- SafeHtmlPipe,
],
providers: [
DatePipe,
import { StoragePath } from 'src/app/data/storage-path'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.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 { StoragePathService } from 'src/app/services/rest/storage-path.service'
import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
PageHeaderComponent,
TitleCasePipe,
IfPermissionsDirective,
- SafeHtmlPipe,
FormsModule,
ReactiveFormsModule,
NgClass,
import { of } from 'rxjs'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.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 { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { TagListComponent } from './tag-list.component'
SortableDirective,
PageHeaderComponent,
IfPermissionsDirective,
- SafeHtmlPipe,
],
providers: [
DatePipe,
import { Tag } from 'src/app/data/tag'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.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 { TagService } from 'src/app/services/rest/tag.service'
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
PageHeaderComponent,
TitleCasePipe,
IfPermissionsDirective,
- SafeHtmlPipe,
FormsModule,
ReactiveFormsModule,
NgClass,
{
key: 'color',
name: $localize`Color`,
- rendersHtml: true,
- valueFn: (t: Tag) => {
- return `<span class="badge" style="color: ${t.text_color}; background-color: ${t.color}">${t.color}</span>`
- },
+ badgeFn: (t: Tag) => ({
+ text: t.color,
+ textColor: t.text_color,
+ backgroundColor: t.color,
+ }),
},
]
}
+++ /dev/null
-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()
- })
-})
+++ /dev/null
-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)
- }
-}