feat(worker): live box password apply route
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
|||||||
listBoxTree,
|
listBoxTree,
|
||||||
readBoxFile,
|
readBoxFile,
|
||||||
restartBox,
|
restartBox,
|
||||||
|
setBoxUserPassword,
|
||||||
startBox,
|
startBox,
|
||||||
stopBox,
|
stopBox,
|
||||||
writeBoxFile,
|
writeBoxFile,
|
||||||
@@ -66,7 +67,9 @@ const jobRoute = (pathname: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const boxRoute = (pathname: string) => {
|
export const boxRoute = (pathname: string) => {
|
||||||
const match = /^\/box\/(status|lifecycle|tree|file)$/.exec(pathname);
|
const match = /^\/box\/(status|lifecycle|tree|file|set-password)$/.exec(
|
||||||
|
pathname,
|
||||||
|
);
|
||||||
return match?.[1] ? { action: match[1] } : null;
|
return match?.[1] ? { action: match[1] } : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,6 +139,25 @@ export const startWorkerServer = () => {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (request.method === 'POST' && box.action === 'set-password') {
|
||||||
|
const body = await parseJson<{ password?: string | null }>(request);
|
||||||
|
// Convex owns validation/storage; this route only applies to the
|
||||||
|
// live container. Re-check bounds anyway so a bad caller can't
|
||||||
|
// push a malformed chpasswd line.
|
||||||
|
const password = body.password ?? null;
|
||||||
|
if (
|
||||||
|
password !== null &&
|
||||||
|
(password.length < 8 ||
|
||||||
|
password.length > 128 ||
|
||||||
|
// eslint-disable-next-line no-control-regex -- rejecting control chars is the point
|
||||||
|
/[\u0000-\u001f\u007f]/.test(password))
|
||||||
|
) {
|
||||||
|
sendJson(response, 400, { error: 'Invalid password' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendJson(response, 200, await setBoxUserPassword(user, password));
|
||||||
|
return;
|
||||||
|
}
|
||||||
sendJson(response, 404, { error: 'Not found' });
|
sendJson(response, 404, { error: 'Not found' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ const load = async () => {
|
|||||||
describe('boxRoute', () => {
|
describe('boxRoute', () => {
|
||||||
afterEach(() => vi.resetModules());
|
afterEach(() => vi.resetModules());
|
||||||
|
|
||||||
test('matches the four box actions', async () => {
|
test('matches the five box actions', async () => {
|
||||||
const { boxRoute } = await load();
|
const { boxRoute } = await load();
|
||||||
expect(boxRoute('/box/status')).toEqual({ action: 'status' });
|
expect(boxRoute('/box/status')).toEqual({ action: 'status' });
|
||||||
expect(boxRoute('/box/lifecycle')).toEqual({ action: 'lifecycle' });
|
expect(boxRoute('/box/lifecycle')).toEqual({ action: 'lifecycle' });
|
||||||
expect(boxRoute('/box/tree')).toEqual({ action: 'tree' });
|
expect(boxRoute('/box/tree')).toEqual({ action: 'tree' });
|
||||||
expect(boxRoute('/box/file')).toEqual({ action: 'file' });
|
expect(boxRoute('/box/file')).toEqual({ action: 'file' });
|
||||||
|
expect(boxRoute('/box/set-password')).toEqual({ action: 'set-password' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rejects unknown, nested, and trailing paths', async () => {
|
test('rejects unknown, nested, and trailing paths', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user