printhive/test/handoff.test.js
dlawler489 f3a69c82ec Open models in your slicer and drag files out
- Settings → Slicer: pick Bambu Studio, OrcaSlicer, PrusaSlicer, Cura, a
  custom open-link template, or plain download (remembered per browser)
- Bambu Studio / OrcaSlicer launch via their URL schemes with a 10-minute
  signed download link (/dl/<token>/<name>) that needs no session cookie
- PrusaSlicer and Cura fall back to a download (they can't open our links)
- 3MF projects report which app saved them; opening one in a different
  slicer asks first
- "slicer" action on every file row and archive entry
- Drag model cards (file, or zip of all files) and file/entry rows out to
  the desktop via Chromium's DownloadURL

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 09:15:37 +10:00

42 lines
2 KiB
JavaScript

// Short-lived "Open in slicer" download links (lib/handoff.js).
const test = require('node:test');
const assert = require('node:assert/strict');
const jwt = require('jsonwebtoken');
const handoff = require('../lib/handoff');
const SECRET = 'a'.repeat(96);
test('a link grants the file it was made for', () => {
const token = handoff.createToken(SECRET, { kind: 'entry', id: '42' });
assert.deepEqual(handoff.readToken(SECRET, token), { kind: 'entry', id: 42 });
});
test('expired, altered or foreign links grant nothing', () => {
const expired = handoff.createToken(SECRET, { kind: 'file', id: 1 }, -5);
assert.equal(handoff.readToken(SECRET, expired), null);
const token = handoff.createToken(SECRET, { kind: 'file', id: 1 });
const [head, , sig] = token.split('.');
const otherBody = Buffer.from(JSON.stringify({ k: 'file', id: 2, aud: 'printhive-handoff', exp: 9999999999 })).toString('base64url');
assert.equal(handoff.readToken(SECRET, `${head}.${otherBody}.${sig}`), null);
assert.equal(handoff.readToken('b'.repeat(96), token), null);
assert.equal(handoff.readToken(SECRET, 'not-a-token'), null);
});
test('a login token is not a hand-off link', () => {
const session = jwt.sign({ sub: 1, email: 'x@example.com' }, SECRET, { expiresIn: '30d' });
assert.equal(handoff.readToken(SECRET, session), null);
// …and a hand-off link doesn't verify as a login.
assert.throws(() => jwt.verify(handoff.createToken(SECRET, { kind: 'file', id: 1 }), SECRET));
});
test('only files and archive entries can be handed off', () => {
assert.throws(() => handoff.createToken(SECRET, { kind: 'model', id: 1 }), /Unknown hand-off kind/);
});
test('link file names stay plain ASCII and keep their extension', () => {
assert.equal(handoff.urlName('Toy Keychain (v2).3mf'), 'Toy_Keychain_v2.3mf');
assert.equal(handoff.urlName('Café déco.STL'), 'Cafe_deco.stl');
assert.equal(handoff.urlName('日本.stl'), 'model.stl');
assert.equal(handoff.urlName('../../etc/passwd.obj'), 'passwd.obj');
});