mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 16:15:39 +00:00
fix: serve plugin bundles only to signed-in users
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @vitest-environment node
|
||||
*/
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
let signedIn = false;
|
||||
vi.mock('@/lib/auth/instance-details', () => ({ canSeeInstanceDetails: vi.fn(async () => signedIn) }));
|
||||
vi.mock('@/lib/admin/plugin-dev', () => ({ getDevPlugin: vi.fn(async () => null), readDevBundle: vi.fn() }));
|
||||
vi.mock('@/lib/admin/plugin-registry', () => ({
|
||||
getPlugin: vi.fn(async () => ({ id: 'demo', enabled: true, bundleHash: 'h' })),
|
||||
getPluginBundle: vi.fn(async () => 'module.exports = {}'),
|
||||
getPluginSignature: vi.fn(async () => 'sig'),
|
||||
}));
|
||||
vi.mock('@/lib/admin/plugin-signing', () => ({ signBytes: vi.fn(async () => 'sig') }));
|
||||
|
||||
import { GET } from '../route';
|
||||
|
||||
function get() {
|
||||
return GET(new NextRequest('http://localhost/api/admin/plugins/demo/bundle'), { params: Promise.resolve({ id: 'demo' }) });
|
||||
}
|
||||
|
||||
beforeEach(() => { signedIn = false; });
|
||||
|
||||
describe('GET plugin bundle', () => {
|
||||
it('does not hand plugin code to someone who is not signed in', async () => {
|
||||
expect((await get()).status).toBe(401);
|
||||
});
|
||||
|
||||
it('serves it to a signed-in user with its signature', async () => {
|
||||
signedIn = true;
|
||||
const res = await get();
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers.get('x-bundle-signature')).toBe('sig');
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getPluginBundle, getPlugin, getPluginSignature } from '@/lib/admin/plugin-registry';
|
||||
import { getDevPlugin, readDevBundle } from '@/lib/admin/plugin-dev';
|
||||
import { signBytes } from '@/lib/admin/plugin-signing';
|
||||
import { canSeeInstanceDetails } from '@/lib/auth/instance-details';
|
||||
|
||||
async function safeSign(code: string): Promise<string | null> {
|
||||
try { return await signBytes(code); } catch { return null; }
|
||||
@@ -10,13 +11,18 @@ async function safeSign(code: string): Promise<string | null> {
|
||||
/**
|
||||
* GET /api/admin/plugins/[id]/bundle - Serve plugin JS bundle
|
||||
*
|
||||
* Public endpoint so the client-side plugin loader can fetch bundles.
|
||||
* Serves bundles to signed-in users so the client-side plugin loader can fetch them.
|
||||
* Only serves plugins that exist in the registry and are enabled.
|
||||
*/
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
// Bundles are delivered to signed-in users only, like the plugin list
|
||||
// that names them (/api/plugins).
|
||||
if (!(await canSeeInstanceDetails(request))) {
|
||||
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||
}
|
||||
try {
|
||||
const { id } = await params;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user