This commit is contained in:
seb
2026-07-15 03:11:30 +02:00
parent 056c9e18cd
commit 1de4144ae2
23 changed files with 921 additions and 229 deletions

View File

@@ -2,7 +2,7 @@ import crypto from 'node:crypto';
import fs from 'node:fs';
import https from 'node:https';
import path from 'node:path';
import { URL } from 'node:url';
import { URL, pathToFileURL } from 'node:url';
import {
ACCESS_KEY,
@@ -32,6 +32,9 @@ function send(res, status, body = '', headers = {}) {
}
function readBody(req) {
if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'DELETE') {
return Promise.resolve(Buffer.alloc(0));
}
return new Promise((resolve, reject) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
@@ -169,10 +172,17 @@ function abortMultipart(uploadId) {
return true;
}
function debug(...args) {
if (process.env.S3_BACKUP_DEBUG) {
console.error(...args);
}
}
async function handle(req, res) {
const body = await readBody(req);
debug(`${req.method} ${req.url} len=${body.length}`);
if (!authOk(req, body)) {
console.error(`${req.method} ${req.url} -> 403 auth failed`);
debug(`auth failed ${req.method} ${req.url}`);
return send(res, 403, xml('<Error><Code>AccessDenied</Code><Message>Access Denied</Message></Error>'));
}
@@ -195,6 +205,10 @@ async function handle(req, res) {
return send(res, 200, listBucketXml(query.get('prefix') || ''));
}
if (req.method === 'HEAD' && !key) {
return send(res, 200, '');
}
if (req.method === 'GET' && key) {
const file = objectPath(key);
if (!fs.existsSync(file)) {
@@ -258,7 +272,6 @@ async function handle(req, res) {
}
export function startServer() {
ensureCerts(HOST);
fs.mkdirSync(DATA_DIR, { recursive: true });
fs.mkdirSync(TMP_DIR, { recursive: true });
@@ -272,7 +285,17 @@ export function startServer() {
}
);
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
reject(new Error(`Port ${PORT} is already in use`));
return;
}
reject(err);
});
server.on('secureConnection', (tlsSocket) => {
debug(`tls ${tlsSocket.remoteAddress}:${tlsSocket.remotePort}`);
});
server.listen(PORT, BIND, () => {
console.log(`S3 endpoint https://${HOST}:${PORT}/${BUCKET} -> ${DATA_DIR}`);
resolve(server);
@@ -280,6 +303,9 @@ export function startServer() {
});
}
if (import.meta.url === `file://${process.argv[1]}`) {
startServer();
if (process.env.S3_BACKUP_CHILD || import.meta.url === pathToFileURL(process.argv[1]).href) {
startServer().catch((err) => {
console.error(err.message || err);
process.exit(1);
});
}