Deploy production / deploy (push) Successful in 1m24s
- picnic.ts: crawls the category tree, subcategory and overview pages (RSC), maps Picnic categories to the shared list; no EANs, so matching is by name/brand/size - picnic-auth.ts + scripts/picnic-login.ts: one-shot login from /etc/grocery-tracker/picnic.env, token kept in ~/.config/groceries/picnic.env; 2FA is never requested unattended (run picnic-login.ts by hand) - migration: store row picnic; Picnic as own brand in stats
59 lines
2.2 KiB
TypeScript
59 lines
2.2 KiB
TypeScript
// Picnic session setup for the grocery importer (see src/lib/server/groceries/picnic-auth.ts).
|
|
//
|
|
// bun scripts/picnic-login.ts check the saved session; if missing/expired, log in once
|
|
// and, when Picnic asks for 2FA, have it text the code
|
|
// bun scripts/picnic-login.ts verify N finish that login with the texted code N
|
|
// bun scripts/picnic-login.ts resend C send the pending login's code again via C (SMS or EMAIL)
|
|
// bun scripts/picnic-login.ts status only check the saved session
|
|
//
|
|
// Never prints credentials or the auth key. One login attempt per run.
|
|
import {
|
|
PicnicAuthError,
|
|
checkAuth,
|
|
loadState,
|
|
login,
|
|
requestSmsCode,
|
|
saveState,
|
|
stateFile,
|
|
verifySmsCode
|
|
} from '../src/lib/server/groceries/picnic-auth';
|
|
|
|
const [cmd, arg] = process.argv.slice(2);
|
|
const s = loadState();
|
|
try {
|
|
if (cmd === 'verify') {
|
|
if (!arg || !/^\d{4,8}$/.test(arg)) throw new PicnicAuthError('usage: verify <code>');
|
|
await verifySmsCode(s, arg);
|
|
console.log(`picnic: 2FA verified; session saved to ${stateFile()}`);
|
|
console.log(`picnic: session ${(await checkAuth(s)) ? 'works' : 'REJECTED'}`);
|
|
} else if (cmd === 'resend') {
|
|
const channel = (arg ?? 'SMS').toUpperCase();
|
|
if (channel !== 'SMS' && channel !== 'EMAIL')
|
|
throw new PicnicAuthError('usage: resend SMS|EMAIL');
|
|
await requestSmsCode(s, channel);
|
|
console.log(
|
|
`picnic: 2FA code requested via ${channel}. Run: bun scripts/picnic-login.ts verify <code>`
|
|
);
|
|
} else if (cmd === 'status') {
|
|
console.log(`picnic: session ${(await checkAuth(s)) ? 'works' : 'missing or expired'}`);
|
|
} else if (!cmd) {
|
|
if (await checkAuth(s)) {
|
|
console.log('picnic: saved session still works; nothing to do');
|
|
} else {
|
|
saveState(s); // persist the device id before logging in with it
|
|
const r = await login(s);
|
|
if (r === 'ok') console.log(`picnic: logged in; session saved to ${stateFile()}`);
|
|
else {
|
|
await requestSmsCode(s);
|
|
console.log(
|
|
'picnic: 2FA required; Picnic is texting a code. Run: bun scripts/picnic-login.ts verify <code>'
|
|
);
|
|
process.exitCode = 2;
|
|
}
|
|
}
|
|
} else throw new PicnicAuthError(`unknown command ${cmd}`);
|
|
} catch (e) {
|
|
console.error(e instanceof Error ? e.message : String(e));
|
|
process.exitCode = 1;
|
|
}
|