mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-22 01:55:49 -06:00
Chore: harden SafeUrlPipe
This commit is contained in:
@@ -13,20 +13,45 @@ describe('SafeUrlPipe', () => {
|
|||||||
pipe = TestBed.inject(SafeUrlPipe)
|
pipe = TestBed.inject(SafeUrlPipe)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should bypass security and trust the url', () => {
|
it('should trust only same-origin http/https urls', () => {
|
||||||
const url = 'https://example.com'
|
const origin = window.location.origin
|
||||||
|
const url = `${origin}/some/path`
|
||||||
const domSanitizer = TestBed.inject(DomSanitizer)
|
const domSanitizer = TestBed.inject(DomSanitizer)
|
||||||
const sanitizerSpy = jest.spyOn(
|
const sanitizerSpy = jest.spyOn(
|
||||||
domSanitizer,
|
domSanitizer,
|
||||||
'bypassSecurityTrustResourceUrl'
|
'bypassSecurityTrustResourceUrl'
|
||||||
)
|
)
|
||||||
|
|
||||||
let safeResourceUrl = pipe.transform(url)
|
const safeResourceUrl = pipe.transform(url)
|
||||||
expect(safeResourceUrl).not.toBeNull()
|
expect(safeResourceUrl).not.toBeNull()
|
||||||
expect(sanitizerSpy).toHaveBeenCalled()
|
expect(sanitizerSpy).toHaveBeenCalledWith(url)
|
||||||
|
})
|
||||||
|
|
||||||
safeResourceUrl = pipe.transform(null)
|
it('should return null for null or unsafe urls', () => {
|
||||||
expect(safeResourceUrl).not.toBeNull()
|
const sanitizerSpy = jest.spyOn(
|
||||||
expect(sanitizerSpy).toHaveBeenCalled()
|
TestBed.inject(DomSanitizer),
|
||||||
|
'bypassSecurityTrustResourceUrl'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(pipe.transform(null)).toBeTruthy()
|
||||||
|
expect(sanitizerSpy).toHaveBeenCalledWith('')
|
||||||
|
expect(pipe.transform('javascript:alert(1)')).toBeTruthy()
|
||||||
|
expect(sanitizerSpy).toHaveBeenCalledWith('')
|
||||||
|
const otherOrigin =
|
||||||
|
window.location.origin === 'https://example.com'
|
||||||
|
? 'https://evil.com'
|
||||||
|
: 'https://example.com'
|
||||||
|
expect(pipe.transform(`${otherOrigin}/file`)).toBeTruthy()
|
||||||
|
expect(sanitizerSpy).toHaveBeenCalledWith('')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return null for malformed urls', () => {
|
||||||
|
const sanitizerSpy = jest.spyOn(
|
||||||
|
TestBed.inject(DomSanitizer),
|
||||||
|
'bypassSecurityTrustResourceUrl'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(pipe.transform('http://[invalid-url')).toBeTruthy()
|
||||||
|
expect(sanitizerSpy).toHaveBeenCalledWith('')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Pipe, PipeTransform, inject } from '@angular/core'
|
import { Pipe, PipeTransform, inject } from '@angular/core'
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
import { DomSanitizer } from '@angular/platform-browser'
|
||||||
|
import { environment } from 'src/environments/environment'
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'safeUrl',
|
name: 'safeUrl',
|
||||||
@@ -7,11 +8,23 @@ import { DomSanitizer } from '@angular/platform-browser'
|
|||||||
export class SafeUrlPipe implements PipeTransform {
|
export class SafeUrlPipe implements PipeTransform {
|
||||||
private sanitizer = inject(DomSanitizer)
|
private sanitizer = inject(DomSanitizer)
|
||||||
|
|
||||||
transform(url) {
|
transform(url: string | null) {
|
||||||
if (url == null) {
|
if (!url) return this.sanitizer.bypassSecurityTrustResourceUrl('')
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url, window.location.origin)
|
||||||
|
const allowedOrigins = new Set([
|
||||||
|
window.location.origin,
|
||||||
|
new URL(environment.apiBaseUrl).origin,
|
||||||
|
])
|
||||||
|
const isHttp = ['http:', 'https:'].includes(parsed.protocol)
|
||||||
|
const originAllowed = allowedOrigins.has(parsed.origin)
|
||||||
|
|
||||||
|
if (!isHttp || !originAllowed) {
|
||||||
|
return this.sanitizer.bypassSecurityTrustResourceUrl('')
|
||||||
|
}
|
||||||
|
return this.sanitizer.bypassSecurityTrustResourceUrl(parsed.toString())
|
||||||
|
} catch {
|
||||||
return this.sanitizer.bypassSecurityTrustResourceUrl('')
|
return this.sanitizer.bypassSecurityTrustResourceUrl('')
|
||||||
} else {
|
|
||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(url)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user