mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 16:15:39 +00:00
fix: keep the plugin denylist and unit tests from breaking Lite and Docker builds
This commit is contained in:
@@ -14,6 +14,11 @@ TODO.md
|
||||
!README.md
|
||||
# Sibling projects / test harness - not part of the webmail image
|
||||
examples/
|
||||
# Unit tests: `next build` type-checks every .ts file, and some tests import
|
||||
# routes the Dockerfile deletes (app/api/dev-jmap)
|
||||
**/__tests__
|
||||
**/*.test.ts
|
||||
**/*.test.tsx
|
||||
integration/
|
||||
repos/
|
||||
# Runtime state of a checkout that has been run (admin password hash,
|
||||
|
||||
@@ -51,6 +51,7 @@ describe('plugin http.post denied paths', () => {
|
||||
['/api/account/stalwart/jmap', ['/api/account/stalwart/jmap']],
|
||||
['/api/admin/config', ['/api/admin/']],
|
||||
['/api/settings', ['/api/settings']],
|
||||
['/api/wopi', ['/api/wopi']],
|
||||
['/api/auth/session', ['/api/']],
|
||||
['/api/%61dmin/config', ['/api/%61dmin/']],
|
||||
['/api//admin/config', ['/api/']],
|
||||
@@ -63,4 +64,9 @@ describe('plugin http.post denied paths', () => {
|
||||
await dispatchApiCall(plugin(['/api/translate']), 'http.post', ['/api/translate', { text: 'hi' }]);
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('reaches a route that only shares a prefix with a denied one', async () => {
|
||||
await dispatchApiCall(plugin(['/api/admin-helper']), 'http.post', ['/api/admin-helper', {}]);
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -293,22 +293,26 @@ function isApiPostPathAllowed(path: string, allowlist: readonly string[]): boole
|
||||
* lists: they act with the user's full credentials (the JMAP passthrough,
|
||||
* WebDAV, CalDAV), change sign-in, admin or plugin state, or belong to the
|
||||
* setup wizard. A plugin talks to its own sidecar routes instead.
|
||||
*
|
||||
* Listed by their segment under `/api/`, not as `/api/...` strings: the Lite
|
||||
* build reads every such string in a client chunk as an endpoint the browser
|
||||
* calls and refuses the ones it has no stand-in for (scripts/lite/verify.mjs).
|
||||
*/
|
||||
const PLUGIN_POST_DENIED_PATHS = [
|
||||
'/api/account',
|
||||
'/api/admin',
|
||||
'/api/auth',
|
||||
'/api/caldav',
|
||||
'/api/dev-jmap',
|
||||
'/api/plugin-approval-status',
|
||||
'/api/plugins',
|
||||
'/api/push',
|
||||
'/api/settings',
|
||||
'/api/setup',
|
||||
'/api/system',
|
||||
'/api/webdav',
|
||||
'/api/wopi',
|
||||
];
|
||||
const PLUGIN_POST_DENIED_ROUTES = new Set([
|
||||
'account',
|
||||
'admin',
|
||||
'auth',
|
||||
'caldav',
|
||||
'dev-jmap',
|
||||
'plugin-approval-status',
|
||||
'plugins',
|
||||
'push',
|
||||
'settings',
|
||||
'setup',
|
||||
'system',
|
||||
'webdav',
|
||||
'wopi',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Checked on the path the router will see: decoded once and with repeated
|
||||
@@ -322,7 +326,8 @@ function isPluginPostDenied(pathname: string): boolean {
|
||||
return true;
|
||||
}
|
||||
routePath = routePath.replace(/\/{2,}/g, '/');
|
||||
return PLUGIN_POST_DENIED_PATHS.some((denied) => routePath === denied || routePath.startsWith(`${denied}/`));
|
||||
if (!routePath.startsWith('/api/')) return false;
|
||||
return PLUGIN_POST_DENIED_ROUTES.has(routePath.slice('/api/'.length).split('/')[0]);
|
||||
}
|
||||
|
||||
interface PluginHttpPostOptions {
|
||||
|
||||
Reference in New Issue
Block a user