website/ is hand-written HTML and CSS, uploaded as it is, like the MailifySMS site: SealShare as software a company installs for its own upload platform, how it works, features, a desktop/phone and light/dark gallery of the generated screenshots, a dated and sourced comparison with hosted transfer services and self-hosted tools, the Docker quick start, FAQ and a privacy page for Plausible. Colours come from the app's scheme, Google Sans Flex is served locally, nothing else loads from other hosts. The README shows three screenshots and no longer calls the encryption end-to-end. WebsiteTest guards missing files, other hosts, the screenshot set and the encryption wording. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
130 lines
4.9 KiB
PHP
130 lines
4.9 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('data-domain="sealshare.nonameweb.ch"');
|
|
}
|
|
});
|
|
|
|
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");
|
|
}
|
|
});
|