feat(api, web): implement short install link functionality for agents
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m37s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

- Added new API endpoints for creating, retrieving, and revoking install links for agents.
- Enhanced the agent installation process with short links accessible via `/agent-install/:id` and `/:slug`.
- Updated the README and documentation to reflect the new installation method and usage instructions.
- Refactored relevant components in the web application to support the new install link feature.
- Improved error handling and validation for install link operations.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-07-21 01:25:05 +07:00
co-authored by Cursor
parent 14f516d5cc
commit ef56da4d91
13 changed files with 677 additions and 117 deletions
+35 -3
View File
@@ -17,6 +17,10 @@ import { controlRoutes } from './routes/control.js'
import { agentRoutes } from './routes/agent.js'
import { refreshAllLists } from './services/lists/refresh.js'
import { repos } from '@evofw/db'
import {
isValidInstallSlug,
resolveAndRenderInstallScript,
} from './services/install-links.js'
export interface BuildAppOptions {
config?: AppConfig
@@ -68,11 +72,39 @@ export async function buildApp(opts: BuildAppOptions = {}) {
root: staticDir,
wildcard: false,
})
app.setNotFoundHandler(async (_request, reply) => {
return reply.sendFile('index.html')
})
}
app.setNotFoundHandler(async (request, reply) => {
const path = request.url.split('?')[0] ?? ''
const segment = path.startsWith('/') ? path.slice(1) : path
if (
request.method === 'GET' &&
segment &&
!segment.includes('/') &&
isValidInstallSlug(segment)
) {
const link = repos.getInstallLinkBySlug(app.db, segment)
if (link) {
const script = resolveAndRenderInstallScript(
app.db,
link,
config.publicBaseUrl,
config.enrollSeed,
)
return reply.type('text/x-shellscript').send(script)
}
}
if (config.staticDir !== null) {
return reply.sendFile('index.html')
}
return reply.code(404).send({
type: 'about:blank',
title: 'Not Found',
status: 404,
})
})
if (!opts.memory) {
await app.register(import('@fastify/schedule'))
const task = new AsyncTask(