mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-18 17:11:21 +00:00
Compare commits
2 Commits
feature-tr
...
fix-harder
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6648941174 | ||
|
|
7c8db78a62 |
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -275,8 +275,12 @@ jobs:
|
||||
tests-frontend-e2e:
|
||||
name: "Frontend E2E Tests (Node ${{ matrix.node-version }} - ${{ matrix.shard-index }}/${{ matrix.shard-count }})"
|
||||
runs-on: ubuntu-24.04
|
||||
container: mcr.microsoft.com/playwright:v1.57.0-noble
|
||||
needs:
|
||||
- install-frontend-dependencies
|
||||
env:
|
||||
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -305,19 +309,8 @@ jobs:
|
||||
key: ${{ runner.os }}-frontenddeps-${{ hashFiles('src-ui/pnpm-lock.yaml') }}
|
||||
- name: Re-link Angular cli
|
||||
run: cd src-ui && pnpm link @angular/cli
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('src-ui/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
- name: Install Playwright system dependencies
|
||||
run: npx playwright install-deps
|
||||
- name: Install dependencies
|
||||
run: cd src-ui && pnpm install --no-frozen-lockfile
|
||||
- name: Install Playwright
|
||||
run: cd src-ui && pnpm exec playwright install
|
||||
- name: Run Playwright e2e tests
|
||||
run: cd src-ui && pnpm exec playwright test --shard ${{ matrix.shard-index }}/${{ matrix.shard-count }}
|
||||
frontend-bundle-analysis:
|
||||
|
||||
@@ -13,20 +13,45 @@ describe('SafeUrlPipe', () => {
|
||||
pipe = TestBed.inject(SafeUrlPipe)
|
||||
})
|
||||
|
||||
it('should bypass security and trust the url', () => {
|
||||
const url = 'https://example.com'
|
||||
it('should trust only same-origin http/https urls', () => {
|
||||
const origin = window.location.origin
|
||||
const url = `${origin}/some/path`
|
||||
const domSanitizer = TestBed.inject(DomSanitizer)
|
||||
const sanitizerSpy = jest.spyOn(
|
||||
domSanitizer,
|
||||
'bypassSecurityTrustResourceUrl'
|
||||
)
|
||||
|
||||
let safeResourceUrl = pipe.transform(url)
|
||||
const safeResourceUrl = pipe.transform(url)
|
||||
expect(safeResourceUrl).not.toBeNull()
|
||||
expect(sanitizerSpy).toHaveBeenCalled()
|
||||
expect(sanitizerSpy).toHaveBeenCalledWith(url)
|
||||
})
|
||||
|
||||
safeResourceUrl = pipe.transform(null)
|
||||
expect(safeResourceUrl).not.toBeNull()
|
||||
expect(sanitizerSpy).toHaveBeenCalled()
|
||||
it('should return null for null or unsafe urls', () => {
|
||||
const sanitizerSpy = jest.spyOn(
|
||||
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 { DomSanitizer } from '@angular/platform-browser'
|
||||
import { environment } from 'src/environments/environment'
|
||||
|
||||
@Pipe({
|
||||
name: 'safeUrl',
|
||||
@@ -7,11 +8,23 @@ import { DomSanitizer } from '@angular/platform-browser'
|
||||
export class SafeUrlPipe implements PipeTransform {
|
||||
private sanitizer = inject(DomSanitizer)
|
||||
|
||||
transform(url) {
|
||||
if (url == null) {
|
||||
transform(url: string | 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('')
|
||||
} else {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user