From 0ea2f79d45b301fcd660efc894469a99b2239bf6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 8 Sep 2021 10:10:51 +0200 Subject: Safer image preview --- .../shared-actor-image-edit/actor-avatar-edit.component.ts | 7 +++---- .../shared-actor-image-edit/actor-banner-edit.component.ts | 6 +++--- .../app/shared/shared-actor-image/actor-avatar.component.ts | 3 +-- .../src/app/shared/shared-forms/preview-upload.component.ts | 8 +++----- client/src/root-helpers/images.ts | 13 +++++++++++++ client/src/root-helpers/index.ts | 1 + 6 files changed, 24 insertions(+), 14 deletions(-) create mode 100644 client/src/root-helpers/images.ts (limited to 'client') diff --git a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts index 2c0e45e20..8b7d64ed3 100644 --- a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts @@ -1,9 +1,9 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' -import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' import { Notifier, ServerService } from '@app/core' import { Account, VideoChannel } from '@app/shared/shared-main' import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' import { getBytes } from '@root-helpers/bytes' +import { imageToDataURL } from '@root-helpers/images' @Component({ selector: 'my-actor-avatar-edit', @@ -30,10 +30,9 @@ export class ActorAvatarEditComponent implements OnInit { maxAvatarSize = 0 avatarExtensions = '' - preview: SafeResourceUrl + preview: string constructor ( - private sanitizer: DomSanitizer, private serverService: ServerService, private notifier: Notifier ) { } @@ -63,7 +62,7 @@ export class ActorAvatarEditComponent implements OnInit { this.avatarChange.emit(formData) if (this.previewImage) { - this.preview = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(avatarfile)) + imageToDataURL(avatarfile).then(result => this.preview = result) } } diff --git a/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts index cba2c5db3..47b537b74 100644 --- a/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts +++ b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts @@ -1,9 +1,10 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' -import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' +import { SafeResourceUrl } from '@angular/platform-browser' import { Notifier, ServerService } from '@app/core' import { VideoChannel } from '@app/shared/shared-main' import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' import { getBytes } from '@root-helpers/bytes' +import { imageToDataURL } from '@root-helpers/images' @Component({ selector: 'my-actor-banner-edit', @@ -30,7 +31,6 @@ export class ActorBannerEditComponent implements OnInit { preview: SafeResourceUrl constructor ( - private sanitizer: DomSanitizer, private serverService: ServerService, private notifier: Notifier ) { } @@ -59,7 +59,7 @@ export class ActorBannerEditComponent implements OnInit { this.bannerChange.emit(formData) if (this.previewImage) { - this.preview = this.sanitizer.bypassSecurityTrustResourceUrl(URL.createObjectURL(bannerfile)) + imageToDataURL(bannerfile).then(result => this.preview = result) } } diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts index a4adfd1b7..c323dc724 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts @@ -1,5 +1,4 @@ import { Component, Input } from '@angular/core' -import { SafeResourceUrl } from '@angular/platform-browser' import { VideoChannel } from '../shared-main' import { Account } from '../shared-main/account/account.model' @@ -22,7 +21,7 @@ export class ActorAvatarComponent { @Input() account: ActorInput @Input() channel: ActorInput - @Input() previewImage: SafeResourceUrl + @Input() previewImage: string @Input() size: ActorAvatarSize diff --git a/client/src/app/shared/shared-forms/preview-upload.component.ts b/client/src/app/shared/shared-forms/preview-upload.component.ts index edee6786d..a857b0a4f 100644 --- a/client/src/app/shared/shared-forms/preview-upload.component.ts +++ b/client/src/app/shared/shared-forms/preview-upload.component.ts @@ -1,7 +1,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' -import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' import { ServerService } from '@app/core' +import { imageToDataURL } from '@root-helpers/images' import { HTMLServerConfig } from '@shared/models' import { BytesPipe } from '../shared-main' @@ -23,7 +23,7 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor { @Input() previewWidth: string @Input() previewHeight: string - imageSrc: SafeResourceUrl + imageSrc: string allowedExtensionsMessage = '' maxSizeText: string @@ -32,7 +32,6 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor { private file: Blob constructor ( - private sanitizer: DomSanitizer, private serverService: ServerService ) { this.bytesPipe = new BytesPipe() @@ -81,8 +80,7 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor { private updatePreview () { if (this.file) { - const url = URL.createObjectURL(this.file) - this.imageSrc = this.sanitizer.bypassSecurityTrustResourceUrl(url) + imageToDataURL(this.file).then(result => this.imageSrc = result) } } } diff --git a/client/src/root-helpers/images.ts b/client/src/root-helpers/images.ts new file mode 100644 index 000000000..fb229ce6d --- /dev/null +++ b/client/src/root-helpers/images.ts @@ -0,0 +1,13 @@ +function imageToDataURL (input: File | Blob) { + return new Promise(res => { + const reader = new FileReader() + + reader.onerror = err => console.error('Cannot read input file.', err) + reader.onloadend = () => res(reader.result as string) + reader.readAsDataURL(input) + }) +} + +export { + imageToDataURL +} diff --git a/client/src/root-helpers/index.ts b/client/src/root-helpers/index.ts index d62f07f9e..63d55d7ef 100644 --- a/client/src/root-helpers/index.ts +++ b/client/src/root-helpers/index.ts @@ -1,5 +1,6 @@ export * from './users' export * from './bytes' +export * from './images' export * from './peertube-web-storage' export * from './utils' export * from './plugins-manager' -- cgit v1.2.3