Files
felhom.eu/documentation/audits/website-refresh-2026-10-08/shots/tools/mealie-probe.js
T
admin 67b3fd23d1
gates / gates (push) Failing after 13m1s
website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected
from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed
mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube,
radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins,
nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py
twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11,
§10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 08:29:17 +02:00

26 lines
1.8 KiB
JavaScript

// Mealie probe (no writes): after the API sign-in, what the box holds and what the frontend keeps for language.
const puppeteer = require('puppeteer');
const fs = require('fs');
const sleep = ms => new Promise(r => setTimeout(r, ms));
const S = JSON.parse(fs.readFileSync('/out/secrets.json'));
const D = process.env.DOMAIN, URL = `https://${process.env.SUB}.${D}`;
(async () => {
const b = await puppeteer.launch({args: ['--no-sandbox', '--ignore-certificate-errors', '--lang=hu-HU', '--host-resolver-rules=MAP * ' + process.env.TRAEFIK]});
const p = await b.newPage();
await p.setCookie({name: 'felhom_session', value: S.session, domain: `felhom.${D}`, path: '/', secure: true});
await p.goto(URL + '/login', {waitUntil: 'networkidle2'});
const r = await p.evaluate(async (pw) => {
const fd = new URLSearchParams({username: 'changeme@example.com', password: pw, remember_me: 'true'});
const st = (await fetch('/api/auth/token', {method: 'POST', body: fd})).status;
const g = async (u, n = 400) => { const x = await fetch(u); return [x.status, (await x.text()).slice(0, n)]; };
const rec = await g('/api/recipes?perPage=50', 1e6);
return {st, recipes: rec[0] + ' ' + (rec[1].match(/"total":\d+/) || [''])[0], names: (rec[1].match(/"name":"[^"]+"/g) || []).join(','),
startup: await g('/api/app/about/startup-info'), self: Object.keys(JSON.parse((await g('/api/users/self', 1e6))[1] || '{}'))};
}, S.gen.ADMIN_PASSWORD);
console.log(JSON.stringify(r).replace(/"(access_)?tok[a-z_]*":"[^"]*"/gi, '"…":"…"'));
await p.goto(URL + '/g/home', {waitUntil: 'networkidle2'});
await sleep(2000);
console.log('g/home ->', p.url(), JSON.stringify(await p.evaluate(() => Object.keys(localStorage))), JSON.stringify((await p.cookies()).map(c => c.name)));
await b.close();
})().catch(e => { console.error(e); process.exit(1); });