fix : securite middle et execfile

This commit is contained in:
2026-03-12 08:37:53 +01:00
parent 126d6b505a
commit 47bc8ba966
13 changed files with 116 additions and 42 deletions

View File

@@ -1,4 +1,4 @@
import { exec } from "node:child_process"
import { execFile } from "node:child_process"
import scripts from "../config/backup-script.json"
type BackupScript = {
@@ -6,11 +6,12 @@ type BackupScript = {
label: string
downloadFolders?: string[]
command: string
args?: string[]
}
function runCommand(command: string): Promise<string> {
function runCommand(command: string, args: string[] = []): Promise<string> {
return new Promise((resolve, reject) => {
exec(command, { timeout: 10 * 60 * 1000 }, (error, stdout, stderr) => {
execFile(command, args, { timeout: 10 * 60 * 1000 }, (error, stdout, stderr) => {
if (error) {
reject(stderr || error.message)
return
@@ -40,7 +41,7 @@ export default defineEventHandler(async (event) => {
}
try {
const output = await runCommand(script.command)
const output = await runCommand(script.command, script.args || [])
return {
ok: true,
key: script.key,

View File

@@ -1,10 +1,11 @@
import { exec } from "child_process"
import { execFile } from "child_process"
import diskSources from "../config/disk-commands.json"
type DiskSource = {
key: string
label: string
command: string
args?: string[]
}
function getCommand(source: DiskSource) {
@@ -15,9 +16,9 @@ function getCommand(source: DiskSource) {
return process.env[envKey] || (legacyEnvKey ? process.env[legacyEnvKey] : undefined) || source.command
}
function runCommand(command: string): Promise<string> {
function runCommand(command: string, args: string[] = []): Promise<string> {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
execFile(command, args, (error, stdout, stderr) => {
if (error) {
reject(stderr || error.message)
return
@@ -31,7 +32,7 @@ export default defineEventHandler(async () => {
const results = await Promise.all(
(diskSources as DiskSource[]).map(async (source) => {
try {
const output = await runCommand(getCommand(source))
const output = await runCommand(source.command, source.args || [])
return {
key: source.key,
label: source.label,

View File

@@ -4,19 +4,31 @@
"label": "Backup BDD recette",
"icon": "mdi:database-export",
"downloadFolders": ["ferme", "inventory", "sirh", "user"],
"command": "ssh ferme 'cd /home/malio/Malio-ops/RecetteScripts && bash backup-bdd-recette.sh && exit'"
"command": "ssh",
"args": [
"ferme",
"cd /home/malio/Malio-ops/RecetteScripts && bash backup-bdd-recette.sh"
]
},
{
"key": "check-statut-recette",
"label": "Check statut recette",
"icon": "mdi:server-network",
"command": "ssh ferme 'cd /home/malio/Malio-ops/RecetteScripts && bash check-statut-recette.sh && exit'"
"command": "ssh",
"args": [
"ferme",
"cd /home/malio/Malio-ops/RecetteScripts && bash check-statut-recette.sh"
]
},
{
"key": "backup-vaultwarden",
"label": "Backup vaultwarden",
"icon": "mdi:data",
"downloadFolders": ["bitwarden"],
"command": "ssh bitwarden 'cd /home/matt/vaultwarden/Malio-ops/BackupVaultWarden && bash backup-vaultwarden.sh && exit'"
"command": "ssh",
"args": [
"bitwarden",
"cd /home/matt/vaultwarden/Malio-ops/BackupVaultWarden && bash backup-vaultwarden.sh"
]
}
]
]

View File

@@ -2,11 +2,18 @@
{
"key": "remote",
"label": "Serveur distant",
"command": "ssh malio-b 'cd /home/malio-b/Malio-ops/CheckStorage && bash check-storage.sh && exit'"
"command": "ssh",
"args": [
"malio-b",
"cd /home/malio-b/Malio-ops/CheckStorage && bash check-storage.sh"
]
},
{
"key": "local",
"label": "Machine locale",
"command": "bash /home/kevin/check_storage.sh"
"command": "bash",
"args": [
"/home/kevin/check_storage.sh"
]
}
]
]

30
server/middleware/auth.ts Normal file
View File

@@ -0,0 +1,30 @@
export default defineEventHandler((event) => {
const path = event.path || event.node.req.url || ""
// Le middleware ne s'applique qu'aux routes API, sauf l'endpoint de ping
// qui reste public pour les tests de connectivite.
if (!path.startsWith("/api/") || path === "/api/ping") {
return
}
const runtimeConfig = useRuntimeConfig(event)
const authorization = getHeader(event, "authorization")
const expectedToken = runtimeConfig.apiSecretKey
// Si aucun secret n'est configure cote serveur, on refuse la requete.
if (!expectedToken) {
throw createError({
statusCode: 401,
statusMessage: "Unauthorized"
})
}
// Le header doit correspondre exactement au format attendu :
// Authorization: Bearer <token>
if (authorization !== `Bearer ${expectedToken}`) {
throw createError({
statusCode: 401,
statusMessage: "Unauthorized"
})
}
})