Files
Andreas Reinhold / reiniandClaude Opus 5 c95d0c43c2
linter / quality (push) Successful in 1m7s
tests / ci (8.5) (push) Successful in 2m16s
docker / build-and-push (push) Successful in 7m5s
docker / test (8.5) (push) Successful in 2m25s
docker / release (push) Successful in 5s
Load the website's Plausible site script
Plausible gives each new site its own script and an init call instead
of the generic script with data-domain.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 16:21:51 +02:00

131 lines
5.0 KiB
PHP

<?php
/*
* website/ is uploaded by hand as it is, so these guard what a broken upload would show: files that
* are not there, requests to other hosts, and claims the application does not keep.
*/
/**
* The site's HTML pages, by name.
*
* @return array<string, string>
*/
function websitePages(): array
{
return [
'index.html' => file_get_contents(base_path('website/index.html')),
'privacy.html' => file_get_contents(base_path('website/privacy.html')),
];
}
/**
* Every URL an HTML document refers to in `src`, `href`, `srcset` and the gallery's `data-*-src` and
* `data-*-srcset`, with each srcset entry on its own.
*
* @return list<string>
*/
function websiteReferences(string $html): array
{
preg_match_all('/\s(src|href|srcset|data-[a-z]+-src|data-[a-z]+-srcset)="([^"]*)"/', $html, $matches, PREG_SET_ORDER);
return collect($matches)
->flatMap(fn (array $match): array => str_ends_with($match[1], 'srcset')
? array_map(fn (string $candidate): string => strtok(trim($candidate), ' '), explode(',', $match[2]))
: [$match[2]])
->map(fn (string $url): string => html_entity_decode($url))
->values()
->all();
}
test('every file the pages, their stylesheets and the README refer to exists', function () {
$missing = [];
foreach (websitePages() as $page => $html) {
foreach (websiteReferences($html) as $url) {
if (preg_match('/^(#|https?:|mailto:)/', $url) === 1) {
continue;
}
if (! is_file(base_path('website/'.strtok($url, '#?')))) {
$missing[] = "{$page}: {$url}";
}
}
}
foreach (glob(base_path('website/css/*.css')) as $stylesheet) {
preg_match_all('/url\([\'"]?([^\'")]+)[\'"]?\)/', file_get_contents($stylesheet), $matches);
foreach ($matches[1] as $url) {
if (! str_starts_with($url, 'data:') && ! is_file(dirname($stylesheet).'/'.strtok($url, '#?'))) {
$missing[] = basename($stylesheet).": {$url}";
}
}
}
foreach (websiteReferences(file_get_contents(base_path('README.md'))) as $url) {
if (str_starts_with($url, 'website/') && ! is_file(base_path($url))) {
$missing[] = "README.md: {$url}";
}
}
expect($missing)->toBe([]);
});
test('the screenshots are all there, for both themes and both widths', function () {
$expected = collect([
'desktop' => ['01-upload', '02-share-created', '03-qr-code', '04-download', '05-admin-dashboard', '06-admin-settings'],
'phone' => ['01-upload', '02-password', '03-download', '04-qr-code'],
])->flatMap(fn (array $names, string $device): array => collect(['light', 'dark'])
->crossJoin($names, $device === 'desktop' ? [1600, 800] : [1080, 540])
->map(fn (array $shot): string => "{$device}/{$shot[0]}/{$shot[1]}-{$shot[2]}.webp")
->all())
->sort()->values()->all();
$published = collect(glob(base_path('website/img/screenshots/*/*/*.webp')))
->map(fn (string $path): string => str($path)->after('website/img/screenshots/')->toString())
->sort()->values()->all();
expect($published)->toBe($expected);
});
test('the pages load nothing from another host but Plausible', function () {
foreach (websitePages() as $page => $html) {
preg_match_all('/<(?:script|img|source|link)\b[^>]*\s(?:src|srcset|href)="(https?:[^"]*)"/', $html, $matches);
expect(collect($matches[1])->reject(fn (string $url): bool => str_starts_with($url, 'https://plausible.io/'))->all())
->toBe([], "{$page} loads from another host");
}
foreach (glob(base_path('website/css/*.css')) as $stylesheet) {
expect(file_get_contents($stylesheet))->not->toMatch('/(url\(\s*[\'"]?https?:|@import)/');
}
});
test('the pages are titled, described and in English', function () {
foreach (websitePages() as $page => $html) {
expect($html)
->toContain('<html lang="en"')
->toMatch('/<title>[^<]+<\/title>/')
->toMatch('/<meta name="description" content="[^"]+"/')
->toContain('<script async src="https://plausible.io/js/pa-zWB4R2-rrBeLfwms3uIBT.js"></script>')
->toContain('plausible.init()');
}
});
test('neither the site nor the README calls the encryption end-to-end', function () {
$index = websitePages()['index.html'];
preg_match('/<section[^>]*id="features".*?<\/section>/s', $index, $features);
preg_match_all('/data-compare="sealshare-e2e">([^<]*)</', $index, $cells);
expect($features[0])->not->toMatch('/end-to-end/i')
->and($cells[1])->not->toBeEmpty()->each->toBe('No')
->and(file_get_contents(base_path('README.md')))->not->toContain('End-to-End Encryption');
});
test('nothing is left to fill in', function () {
foreach ([...websitePages(), 'theme.css' => file_get_contents(base_path('website/css/theme.css'))] as $file => $contents) {
expect(str_contains($contents, 'TODO'))->toBeFalse("{$file} still has a TODO");
}
});