openvibers/openvibe.locker Commits
Enable silent sign-in on Locker arrivals (#41)
Changes
@@@ -16,7 +16,8 @@ function createPages({ config }) {name: 'OpenVibe.Locker', siteName: 'OpenVibe.Locker', title: `${title} · OpenVibe.Locker`, titleSuffix: '', lang: 'en',description: 'Your files, locked on your device. Private by math.', canonical: `${config.baseUrl}${req.path}`, robots: 'noindex, nofollow',navbar: { service: 'locker', history: false, brandName: 'OpenVibe.Locker', apiBase: config.networkUrl, links: nav.map((n) => ({ ...n, active: req.path === n.href })),-- sessionUrl: '/auth/me', loginUrl: '/auth/login?next={path}', logoutUrl: '/auth/logout?next={path}' },++ sessionUrl: '/auth/me', loginUrl: '/auth/login?next={path}', logoutUrl: '/auth/logout?next={path}',++ silentLogin: '/auth/login?silent=1&next={url}' },footer: { service: 'locker', variant: 'full', brandName: 'OpenVibe.Locker' },head: '<link rel="stylesheet" href="/shared/kit.css"><link rel="stylesheet" href="/shared/ov-locker.css"><link rel="stylesheet" href="/css/locker.css"><link rel="icon" href="/icon.svg"><meta name="referrer" content="no-referrer">',body: `<div id="navbar-mount"></div><main id="main" class="locker-page" data-mode="${mode}"><div id="notice" role="status" aria-live="polite"></div>${body}</main><script>window.LockerPage=${boot};window.OpenVibeLockerConfig={network:'',reauthUrl:'/reauth'};</script><script src="/shared/ov-locker-core.js"></script><script src="/shared/ov-locker.js"></script><script src="/shared/ov-share.js"></script><script src="/js/payload.js"></script><script src="/js/passwords.js"></script><script src="/js/app.js"></script>`,@@@ -32,6 +32,12 @@ test('the security policy lets an avatar from openvibe.media show in img-src', aassert.match(csp, /img-src[^;]*https:\/\/openvibe\.media(?:[ ;]|$)/, csp);});++test('public arrivals can check Network and start the existing silent sign-in flow', async () => {++ const page = await t.request('GET', '/', { user: null });++ assert.match(page.headers.get('content-security-policy'), /frame-src[^;]*https:\/\/openvibe\.network(?:[ ;]|$)/);++ assert.match(await page.text(), /"silentLogin":"\/auth\/login\?silent=1&next=\{url\}"/);++});++test('password login items use people locks and remain opaque in storage', async () => {const secret = JSON.stringify({ version: 1, site: 'https://example.test', username: 'alice', password: 'secret-password', totp: '', notes: '' });const encrypted = await locker.seal(secret, { lock: 'people', keys: [{ subject: { type: 'user', id: SUBJECT }, publicKey: t.people.get(SUBJECT).ecdhPublic }] });
@@ -16,7 +16,8 @@ function createPages({ config }) {
@@ -16,7 +16,8 @@ function createPages({ config }) {
name: 'OpenVibe.Locker', siteName: 'OpenVibe.Locker', title: `${title} · OpenVibe.Locker`, titleSuffix: '', lang: 'en',
name: 'OpenVibe.Locker', siteName: 'OpenVibe.Locker', title: `${title} · OpenVibe.Locker`, titleSuffix: '', lang: 'en',
description: 'Your files, locked on your device. Private by math.', canonical: `${config.baseUrl}${req.path}`, robots: 'noindex, nofollow',
description: 'Your files, locked on your device. Private by math.', canonical: `${config.baseUrl}${req.path}`, robots: 'noindex, nofollow',
navbar: { service: 'locker', history: false, brandName: 'OpenVibe.Locker', apiBase: config.networkUrl, links: nav.map((n) => ({ ...n, active: req.path === n.href })),
navbar: { service: 'locker', history: false, brandName: 'OpenVibe.Locker', apiBase: config.networkUrl, links: nav.map((n) => ({ ...n, active: req.path === n.href })),
- sessionUrl: '/auth/me', loginUrl: '/auth/login?next={path}', logoutUrl: '/auth/logout?next={path}' },
+ sessionUrl: '/auth/me', loginUrl: '/auth/login?next={path}', logoutUrl: '/auth/logout?next={path}',
+ silentLogin: '/auth/login?silent=1&next={url}' },
footer: { service: 'locker', variant: 'full', brandName: 'OpenVibe.Locker' },
footer: { service: 'locker', variant: 'full', brandName: 'OpenVibe.Locker' },
head: '<link rel="stylesheet" href="/shared/kit.css"><link rel="stylesheet" href="/shared/ov-locker.css"><link rel="stylesheet" href="/css/locker.css"><link rel="icon" href="/icon.svg"><meta name="referrer" content="no-referrer">',
head: '<link rel="stylesheet" href="/shared/kit.css"><link rel="stylesheet" href="/shared/ov-locker.css"><link rel="stylesheet" href="/css/locker.css"><link rel="icon" href="/icon.svg"><meta name="referrer" content="no-referrer">',
body: `<div id="navbar-mount"></div><main id="main" class="locker-page" data-mode="${mode}"><div id="notice" role="status" aria-live="polite"></div>${body}</main><script>window.LockerPage=${boot};window.OpenVibeLockerConfig={network:'',reauthUrl:'/reauth'};</script><script src="/shared/ov-locker-core.js"></script><script src="/shared/ov-locker.js"></script><script src="/shared/ov-share.js"></script><script src="/js/payload.js"></script><script src="/js/passwords.js"></script><script src="/js/app.js"></script>`,
body: `<div id="navbar-mount"></div><main id="main" class="locker-page" data-mode="${mode}"><div id="notice" role="status" aria-live="polite"></div>${body}</main><script>window.LockerPage=${boot};window.OpenVibeLockerConfig={network:'',reauthUrl:'/reauth'};</script><script src="/shared/ov-locker-core.js"></script><script src="/shared/ov-locker.js"></script><script src="/shared/ov-share.js"></script><script src="/js/payload.js"></script><script src="/js/passwords.js"></script><script src="/js/app.js"></script>`,
@@ -32,6 +32,12 @@ test('the security policy lets an avatar from openvibe.media show in img-src', a
@@ -32,6 +32,12 @@ test('the security policy lets an avatar from openvibe.media show in img-src', a
assert.match(csp, /img-src[^;]*https:\/\/openvibe\.media(?:[ ;]|$)/, csp);
assert.match(csp, /img-src[^;]*https:\/\/openvibe\.media(?:[ ;]|$)/, csp);
});
});
+test('public arrivals can check Network and start the existing silent sign-in flow', async () => {
+ const page = await t.request('GET', '/', { user: null });
+ assert.match(page.headers.get('content-security-policy'), /frame-src[^;]*https:\/\/openvibe\.network(?:[ ;]|$)/);
+ assert.match(await page.text(), /"silentLogin":"\/auth\/login\?silent=1&next=\{url\}"/);
+});
+
test('password login items use people locks and remain opaque in storage', async () => {
test('password login items use people locks and remain opaque in storage', async () => {
const secret = JSON.stringify({ version: 1, site: 'https://example.test', username: 'alice', password: 'secret-password', totp: '', notes: '' });
const secret = JSON.stringify({ version: 1, site: 'https://example.test', username: 'alice', password: 'secret-password', totp: '', notes: '' });
const encrypted = await locker.seal(secret, { lock: 'people', keys: [{ subject: { type: 'user', id: SUBJECT }, publicKey: t.people.get(SUBJECT).ecdhPublic }] });
const encrypted = await locker.seal(secret, { lock: 'people', keys: [{ subject: { type: 'user', id: SUBJECT }, publicKey: t.people.get(SUBJECT).ecdhPublic }] });