const assert = require("assert"); const fs = require("fs"); const path = require("path"); const root = path.join(__dirname, ".."); const sandbox = fs.mkdtempSync(path.join(root, ".tmp-lumi-content-library-")); const serviceDir = path.join(sandbox, "src", "services"); fs.mkdirSync(serviceDir, { recursive: true }); for (const file of [ "config.js", "db.js", "settings.js", "upload-security.js", "content-library.js", "content-routes.js" ]) { fs.copyFileSync(path.join(root, "src", "services", file), path.join(serviceDir, file)); } let database = null; (async () => { try { database = require(path.join(serviceDir, "db.js")); // Core imports the Web server before main() runs migrate(). The content // service must therefore be safe to load without touching database tables. const library = require(path.join(serviceDir, "content-library.js")); const routes = require(path.join(serviceDir, "content-routes.js")); database.migrate(); const settings = require(path.join(serviceDir, "settings.js")); settings.ensureDefaults(); settings.setSetting("session_secret", "content-library-verification-secret"); assert(database.db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'content_resources'").get()); library.ensureContentLibrary(); assert(library.supportedExtensions().includes(".mp4")); assert(library.supportedExtensions().includes(".mp3")); assert(library.supportedExtensions().includes(".webm")); assert(library.supportedExtensions().includes(".png")); assert(library.supportedExtensions().includes(".woff2")); const pngPath = path.join(library.INCOMING_DIR, "verify.png.upload"); fs.writeFileSync( pngPath, Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9ZK1sAAAAASUVORK5CYII=", "base64" ) ); const [created] = await library.importUploadedFiles([ { path: pngPath, originalname: "Alert Graphic.png", mimetype: "image/png" } ], { access_level: "locked", uploaded_by: "verify-admin" }); assert.strictEqual(created.access_level, "locked"); assert.strictEqual(created.category, "image"); assert.strictEqual(created.preview_kind, "image"); assert.strictEqual(library.publicUrl(created, "https://lumi.example"), null); assert(fs.existsSync(library.resourceFilePath(created))); const signed = new URL(library.createSignedUrl(created.id, { base_url: "https://lumi.example", ttl_seconds: 60 })); const signedResource = library.verifySignedResource( created.id, signed.searchParams.get("expires"), signed.searchParams.get("sig") ); assert.strictEqual(signedResource.id, created.id); const exposed = library.setResourceAccess(created.id, "exposed"); const publicUrl = new URL(library.publicUrl(exposed, "https://lumi.example")); const publicToken = publicUrl.pathname.split("/")[2]; assert(publicToken.length >= 40); assert.strictEqual(library.getResourceByExposedToken(publicToken).id, created.id); const renamed = library.updateResourceName(created.id, "Follower alert"); assert.strictEqual(renamed.display_name, "Follower alert"); assert.strictEqual(library.listResources({ category: "image" }).length, 1); assert.deepStrictEqual(routes.parseByteRange("bytes=0-9", 100), { start: 0, end: 9 }); assert.deepStrictEqual(routes.parseByteRange("bytes=-10", 100), { start: 90, end: 99 }); assert.strictEqual(routes.parseByteRange("bytes=200-300", 100).invalid, true); assert.strictEqual(routes.parseByteRange("bytes=0-1,4-5", 100).invalid, true); const stats = library.getStorageStats(); assert.strictEqual(stats.file_count, 1); assert(stats.used_bytes > 0); assert(stats.max_file_bytes > 0); const lockedAgain = library.setResourceAccess(created.id, "locked"); assert.strictEqual(library.getResourceByExposedToken(publicToken), null); assert.strictEqual(lockedAgain.public_token, ""); fs.rmSync(library.resourceFilePath(created), { force: true }); library.deleteResource(created.id); assert.strictEqual(library.getResource(created.id), null); assert.strictEqual(library.getStorageStats().file_count, 0); const serverSource = fs.readFileSync(path.join(root, "src", "web", "server.js"), "utf8"); assert(serverSource.includes("registerPublicContentRoutes(app)")); assert(serverSource.includes("registerContentAdminRoutes(app")); assert(serverSource.includes('path: "/admin/resources"')); assert(serverSource.includes("global.lumiFrameworks.resources")); const overlayRouteSource = fs.readFileSync(path.join(root, "src", "services", "overlay-routes.js"), "utf8"); assert(overlayRouteSource.includes("media-src https: http: data: blob:"), "OBS overlay CSP must allow configured media sources"); const viewSource = fs.readFileSync(path.join(root, "src", "web", "views", "admin-resources.ejs"), "utf8"); assert(viewSource.includes("data-resource-dropzone")); assert(viewSource.includes("data-resource-preview-modal")); assert(viewSource.includes("Available to Lumi")); assert(viewSource.includes("data-resource-access-form") && viewSource.includes("data-confirm-mode=\"modal\"")); const contentRouteSource = fs.readFileSync(path.join(root, "src", "services", "content-routes.js"), "utf8"); assert(contentRouteSource.includes('/admin/resources/:id/revoke')); const clientSource = fs.readFileSync(path.join(root, "src", "web", "public", "content-library.js"), "utf8"); assert(clientSource.includes("if (event.defaultPrevented) return;"), "AJAX actions must wait for shared timed confirmation"); assert(clientSource.includes('body.has("confirmation_token")') && clientSource.includes('[data-destructive-cancel]'), "confirmed AJAX actions must close the shared modal without losing the issued token"); const coreKnowledge = fs.readFileSync(path.join(root, "knowledge", "core", "lumi-core.md"), "utf8"); assert(coreKnowledge.includes("GET /admin/resources") && coreKnowledge.includes("GET /media/:token/:filename")); console.log("Content-library verification passed."); } finally { try { database?.db?.close(); } catch {} fs.rmSync(sandbox, { recursive: true, force: true }); } })().catch((error) => { console.error(error); process.exitCode = 1; });