mosaic console start --dev-local-owner --dev-insecure-bind ADDR --dev-allow-host NAME[,NAME...] binds 0.0.0.0 or an IPv4 address and answers only NAME:<bound port> plus the loopback names. Both flags are refused without the dev owner, the bind without an allowed name, and a specific ADDR that is not itself a name. Start and console status print the no-sign-in warning; the state file records bind and allowHosts. serve.mjs takes devAllowHosts only with the dev owner; SSO, preview and tester listeners stay loopback. Writes need Origin http://<same Host>. Chromium sends no Fetch Metadata from a LAN http origin, so for an allowed name a write with that exact Origin and no Sec-Fetch-Site counts as same-origin; an explicit header is still judged by the routes. chat.js builds its operation keys without crypto.randomUUID, which an insecure context lacks.
45 lines
3.1 KiB
JavaScript
45 lines
3.1 KiB
JavaScript
// org-lan-bind: a browser on another machine opens the dev owner Console by an allowed LAN name
|
|
// (http://lan.test:PORT/, mapped to 127.0.0.1 for the test) and creates a project. That origin
|
|
// is not a secure context, so Chromium sends no Fetch Metadata and has no crypto.randomUUID.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { startServer } from '../src/serve.mjs';
|
|
import { createDevOwner } from '../src/dev-owner.mjs';
|
|
import { browser } from './browser.mjs';
|
|
import { close } from './fixture.mjs';
|
|
|
|
const ID = '20000000-0000-4000-8000-000000000002';
|
|
|
|
test('an allowed LAN name loads the org page and creates a project', { timeout: 45000 }, async t => {
|
|
const projects = [], created = [];
|
|
const organizations = {
|
|
list: async () => [{ id: 'alpha', label: 'alpha', busHealthy: true }],
|
|
resolve: async id => id === 'alpha' ? {
|
|
busHealthy: true, send: async () => ({}),
|
|
reads: { business: async () => ({ business: { id, projects: ['work'] } }), busStatus: async () => ({ live: true }) },
|
|
bus: { inbox: async () => [], agents: async () => [], messages: async () => ({ messages: [] }), tasks: async () => [] },
|
|
chat: {
|
|
projects: async () => projects, threads: async () => [],
|
|
createProject: async args => { created.push(args); const row = { id: ID, ...args }; projects.push(row); return row; },
|
|
},
|
|
} : null,
|
|
};
|
|
const server = await startServer({ host: '0.0.0.0', port: 0, devAllowHosts: ['lan.test'], sso: createDevOwner(), organizations, send: async () => ({}), board: 'http://127.0.0.1:9', log: () => {} });
|
|
t.after(() => close(server));
|
|
const port = server.address().port;
|
|
const b = await browser({ machine: false, args: ['--host-resolver-rules=MAP lan.test 127.0.0.1'] }); t.after(() => b.close());
|
|
const wait = expression => b.evaluate(`(async()=>{for(let i=0;i<300;i++){if(${expression})return;await new Promise(r=>setTimeout(r,30))}throw Error(${JSON.stringify(expression)})})()`);
|
|
const input = (selector, value) => b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(selector)});e.value=${JSON.stringify(value)};e.dispatchEvent(new Event('input',{bubbles:true}));e.dispatchEvent(new Event('change',{bubbles:true}));})()`);
|
|
const click = selector => b.evaluate(`document.querySelector(${JSON.stringify(selector)}).click()`);
|
|
await b.navigate(`http://lan.test:${port}/#/orgs/alpha/projects`);
|
|
assert.deepEqual(await b.evaluate('({ host: location.host, secure: isSecureContext, uuid: typeof crypto.randomUUID })'), { host: `lan.test:${port}`, secure: false, uuid: 'undefined' });
|
|
await wait('window.MosaicOrg?.id === "alpha" && !!document.querySelector("#chat-repo option[value=work]")');
|
|
await click('.project-create summary');
|
|
await input('#chat-project-name', 'Work'); await input('#chat-repo', 'work');
|
|
await click('#chat-project-form button[type=submit]');
|
|
await wait('/\\/projects\\/[0-9a-f-]{36}/i.test(location.hash)');
|
|
assert.equal(await b.evaluate('location.hash'), `#/orgs/alpha/projects/${ID}`);
|
|
assert.deepEqual(created, [{ name: 'Work', repo: 'work' }]);
|
|
assert.equal(await b.evaluate('location.host'), `lan.test:${port}`);
|
|
});
|