initial commit

This commit is contained in:
Madison Grubb
2026-02-10 23:32:26 -05:00
commit b7046dc0e6
133 changed files with 26080 additions and 0 deletions

119
test/unit/feedUtils.spec.js Normal file
View File

@@ -0,0 +1,119 @@
import { describe, it, expect } from 'vitest'
import { isValidFeed, getValidFeeds, sanitizeStreamUrl, sanitizeFeedForResponse } from '../../server/utils/feedUtils.js'
describe('feedUtils', () => {
describe('isValidFeed', () => {
it('returns true for valid feed', () => {
expect(isValidFeed({
id: '1',
name: 'Cam',
lat: 37.7,
lng: -122.4,
})).toBe(true)
})
it('returns false for null', () => {
expect(isValidFeed(null)).toBe(false)
})
it('returns false for missing id', () => {
expect(isValidFeed({ name: 'x', lat: 0, lng: 0 })).toBe(false)
})
it('returns false for wrong lat type', () => {
expect(isValidFeed({ id: '1', name: 'x', lat: '37', lng: -122 })).toBe(false)
})
})
describe('getValidFeeds', () => {
it('returns only valid feeds', () => {
const list = [
{ id: 'a', name: 'A', lat: 1, lng: 2 },
null,
{ id: 'b', name: 'B', lat: 3, lng: 4 },
]
expect(getValidFeeds(list)).toHaveLength(2)
})
it('returns empty array for non-array', () => {
expect(getValidFeeds(null)).toEqual([])
expect(getValidFeeds({})).toEqual([])
})
})
describe('sanitizeStreamUrl', () => {
it('allows http and https', () => {
expect(sanitizeStreamUrl('https://example.com/stream')).toBe('https://example.com/stream')
expect(sanitizeStreamUrl('http://example.com/stream')).toBe('http://example.com/stream')
})
it('returns empty for javascript:, data:, and other schemes', () => {
expect(sanitizeStreamUrl('javascript:alert(1)')).toBe('')
expect(sanitizeStreamUrl('data:text/html,<script>')).toBe('')
expect(sanitizeStreamUrl('file:///etc/passwd')).toBe('')
})
it('returns empty for non-strings or empty', () => {
expect(sanitizeStreamUrl('')).toBe('')
expect(sanitizeStreamUrl(' ')).toBe('')
expect(sanitizeStreamUrl(null)).toBe('')
expect(sanitizeStreamUrl(123)).toBe('')
})
})
describe('sanitizeFeedForResponse', () => {
it('returns safe shape with sanitized streamUrl and sourceType', () => {
const feed = {
id: 'f1',
name: 'Cam',
lat: 37,
lng: -122,
streamUrl: 'https://safe.com/s',
sourceType: 'mjpeg',
}
const out = sanitizeFeedForResponse(feed)
expect(out).toEqual({
id: 'f1',
name: 'Cam',
lat: 37,
lng: -122,
streamUrl: 'https://safe.com/s',
sourceType: 'mjpeg',
})
})
it('strips dangerous streamUrl and normalizes sourceType', () => {
const feed = {
id: 'f2',
name: 'Bad',
lat: 0,
lng: 0,
streamUrl: 'javascript:alert(1)',
sourceType: 'hls',
}
const out = sanitizeFeedForResponse(feed)
expect(out.streamUrl).toBe('')
expect(out.sourceType).toBe('hls')
})
it('includes description only when string', () => {
const withDesc = sanitizeFeedForResponse({
id: 'a',
name: 'n',
lat: 0,
lng: 0,
description: 'A camera',
})
expect(withDesc.description).toBe('A camera')
const noDesc = sanitizeFeedForResponse({
id: 'b',
name: 'n',
lat: 0,
lng: 0,
description: 123,
})
expect(noDesc).not.toHaveProperty('description')
})
})
})