v0.1.4 - Make response at root JSON
This commit is contained in:
@@ -426,9 +426,9 @@ void handle_mirror_request(void) {
|
||||
// Determine file extension from Content-Type using centralized mapping
|
||||
const char* extension = mime_to_extension(content_type_final);
|
||||
|
||||
// Save file to blobs directory
|
||||
// Save file to storage directory using global g_storage_dir variable
|
||||
char filepath[512];
|
||||
snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256_hex, extension);
|
||||
snprintf(filepath, sizeof(filepath), "%s/%s%s", g_storage_dir, sha256_hex, extension);
|
||||
|
||||
FILE* outfile = fopen(filepath, "wb");
|
||||
if (!outfile) {
|
||||
|
||||
75
src/bud08.c
75
src/bud08.c
@@ -24,7 +24,7 @@ int nip94_is_enabled(void) {
|
||||
return 1; // Default enabled on DB error
|
||||
}
|
||||
|
||||
const char* sql = "SELECT value FROM server_config WHERE key = 'nip94_enabled'";
|
||||
const char* sql = "SELECT value FROM config WHERE key = 'nip94_enabled'";
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
rc = sqlite3_step(stmt);
|
||||
@@ -45,49 +45,52 @@ int nip94_get_origin(char* out, size_t out_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if request came over HTTPS (nginx sets HTTPS=on for SSL requests)
|
||||
const char* https_env = getenv("HTTPS");
|
||||
if (https_env && strcmp(https_env, "on") == 0) {
|
||||
// HTTPS request - use HTTPS origin
|
||||
strncpy(out, "https://localhost:9443", out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
// HTTP request - check database config first, then use HTTP origin
|
||||
// Check database config first for custom origin
|
||||
sqlite3* db;
|
||||
sqlite3_stmt* stmt;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc) {
|
||||
// Default on DB error - use HTTP
|
||||
strncpy(out, "http://localhost:9001", out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
if (rc == SQLITE_OK) {
|
||||
const char* sql = "SELECT value FROM config WHERE key = 'cdn_origin'";
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc == SQLITE_ROW) {
|
||||
const char* value = (const char*)sqlite3_column_text(stmt, 0);
|
||||
if (value) {
|
||||
strncpy(out, value, out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
// Check if request came over HTTPS (nginx sets HTTPS=on for SSL requests)
|
||||
const char* https_env = getenv("HTTPS");
|
||||
const char* server_name = getenv("SERVER_NAME");
|
||||
|
||||
// Use production domain if SERVER_NAME is set and not localhost
|
||||
if (server_name && strcmp(server_name, "localhost") != 0) {
|
||||
if (https_env && strcmp(https_env, "on") == 0) {
|
||||
snprintf(out, out_size, "https://%s", server_name);
|
||||
} else {
|
||||
snprintf(out, out_size, "http://%s", server_name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* sql = "SELECT value FROM server_config WHERE key = 'cdn_origin'";
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc == SQLITE_ROW) {
|
||||
const char* value = (const char*)sqlite3_column_text(stmt, 0);
|
||||
if (value) {
|
||||
strncpy(out, value, out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// Fallback to localhost for development
|
||||
if (https_env && strcmp(https_env, "on") == 0) {
|
||||
strncpy(out, "https://localhost:9443", out_size - 1);
|
||||
} else {
|
||||
strncpy(out, "http://localhost:9001", out_size - 1);
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
// Default fallback - HTTP
|
||||
strncpy(out, "http://localhost:9001", out_size - 1);
|
||||
out[out_size - 1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ extern sqlite3* db;
|
||||
int init_database(void);
|
||||
void close_database(void);
|
||||
|
||||
// Global configuration variables (defined in main.c)
|
||||
extern char g_db_path[4096];
|
||||
extern char g_storage_dir[4096];
|
||||
|
||||
// SHA-256 extraction and validation
|
||||
const char* extract_sha256_from_uri(const char* uri);
|
||||
|
||||
|
||||
383
src/main.c
383
src/main.c
@@ -7,6 +7,7 @@
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_common.h"
|
||||
#include "../nostr_core_lib/nostr_core/utils.h"
|
||||
#include <getopt.h>
|
||||
#include <curl/curl.h>
|
||||
#include <fcgi_stdio.h>
|
||||
#include <sqlite3.h>
|
||||
@@ -22,11 +23,15 @@
|
||||
// Debug macros removed
|
||||
|
||||
#define MAX_SHA256_LEN 65
|
||||
#define MAX_PATH_LEN 512
|
||||
#define MAX_PATH_LEN 4096
|
||||
#define MAX_MIME_LEN 128
|
||||
|
||||
// Database path
|
||||
#define DB_PATH "db/ginxsom.db"
|
||||
// Configuration variables - can be overridden via command line
|
||||
char g_db_path[MAX_PATH_LEN] = "db/ginxsom.db";
|
||||
char g_storage_dir[MAX_PATH_LEN] = ".";
|
||||
|
||||
// Use global configuration variables
|
||||
#define DB_PATH g_db_path
|
||||
|
||||
|
||||
// Configuration system implementation
|
||||
@@ -35,22 +40,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// ===== UNUSED CODE - SAFE TO REMOVE AFTER TESTING =====
|
||||
// Server configuration structure
|
||||
/*
|
||||
typedef struct {
|
||||
char admin_pubkey[256];
|
||||
char admin_enabled[8];
|
||||
int config_loaded;
|
||||
} server_config_t;
|
||||
|
||||
// Global configuration instance
|
||||
static server_config_t g_server_config = {0};
|
||||
|
||||
// Global server private key (stored in memory only for security)
|
||||
static char server_private_key[128] = {0};
|
||||
*/
|
||||
// ===== END UNUSED CODE =====
|
||||
|
||||
// Function to get XDG config directory
|
||||
const char *get_config_dir(char *buffer, size_t buffer_size) {
|
||||
@@ -70,240 +59,6 @@ const char *get_config_dir(char *buffer, size_t buffer_size) {
|
||||
return ".config/ginxsom";
|
||||
}
|
||||
|
||||
/*
|
||||
// ===== UNUSED CODE - SAFE TO REMOVE AFTER TESTING =====
|
||||
// Load server configuration from database or create defaults
|
||||
int initialize_server_config(void) {
|
||||
sqlite3 *db = NULL;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
int rc;
|
||||
|
||||
memset(&g_server_config, 0, sizeof(g_server_config));
|
||||
|
||||
// Open database
|
||||
rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
fprintf(stderr, "CONFIG: Could not open database for config: %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
// Config database doesn't exist - leave config uninitialized
|
||||
g_server_config.config_loaded = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load admin_pubkey
|
||||
const char *sql = "SELECT value FROM config WHERE key = ?";
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, "admin_pubkey", -1, SQLITE_STATIC);
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc == SQLITE_ROW) {
|
||||
const char *value = (const char *)sqlite3_column_text(stmt, 0);
|
||||
if (value) {
|
||||
strncpy(g_server_config.admin_pubkey, value,
|
||||
sizeof(g_server_config.admin_pubkey) - 1);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
// Load admin_enabled
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, "admin_enabled", -1, SQLITE_STATIC);
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc == SQLITE_ROW) {
|
||||
const char *value = (const char *)sqlite3_column_text(stmt, 0);
|
||||
if (value && strcmp(value, "true") == 0) {
|
||||
strcpy(g_server_config.admin_enabled, "true");
|
||||
} else {
|
||||
strcpy(g_server_config.admin_enabled, "false");
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
g_server_config.config_loaded = 1;
|
||||
fprintf(stderr, "CONFIG: Server configuration loaded\n");
|
||||
return 1;
|
||||
}
|
||||
// ===== END UNUSED CODE =====
|
||||
*/
|
||||
|
||||
/*
|
||||
// File-based configuration system
|
||||
// Config file path resolution
|
||||
int get_config_file_path(char *path, size_t path_size) {
|
||||
const char *home = getenv("HOME");
|
||||
const char *xdg_config = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
if (xdg_config) {
|
||||
snprintf(path, path_size, "%s/ginxsom/ginxsom_config_event.json",
|
||||
xdg_config);
|
||||
} else if (home) {
|
||||
snprintf(path, path_size, "%s/.config/ginxsom/ginxsom_config_event.json",
|
||||
home);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Load and validate config event
|
||||
int load_server_config(const char *config_path) {
|
||||
FILE *file = fopen(config_path, "r");
|
||||
if (!file) {
|
||||
return 0; // Config file doesn't exist
|
||||
}
|
||||
|
||||
// Read entire file
|
||||
fseek(file, 0, SEEK_END);
|
||||
long file_size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char *json_data = malloc(file_size + 1);
|
||||
if (!json_data) {
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fread(json_data, 1, file_size, file);
|
||||
json_data[file_size] = '\0';
|
||||
fclose(file);
|
||||
|
||||
// Parse and validate JSON event
|
||||
cJSON *event = cJSON_Parse(json_data);
|
||||
free(json_data);
|
||||
|
||||
if (!event) {
|
||||
fprintf(stderr, "Invalid JSON in config file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Validate event structure and signature
|
||||
if (nostr_validate_event(event) != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "Invalid or corrupted config event\n");
|
||||
cJSON_Delete(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract configuration and apply to server
|
||||
int result = apply_config_from_event(event);
|
||||
cJSON_Delete(event);
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Extract config from validated event and apply to server
|
||||
int apply_config_from_event(cJSON *event) {
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
|
||||
// Open database for config storage
|
||||
rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READWRITE, NULL);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failed to open database for config\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract admin pubkey from event
|
||||
cJSON *pubkey_json = cJSON_GetObjectItem(event, "pubkey");
|
||||
if (!pubkey_json || !cJSON_IsString(pubkey_json)) {
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
const char *admin_pubkey = cJSON_GetStringValue(pubkey_json);
|
||||
|
||||
// Store admin pubkey in database
|
||||
const char *insert_sql = "INSERT OR REPLACE INTO config (key, value, "
|
||||
"description) VALUES (?, ?, ?)";
|
||||
rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, "admin_pubkey", -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, admin_pubkey, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, "Admin public key from config event", -1,
|
||||
SQLITE_STATIC);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
// Extract server private key and store securely (in memory only)
|
||||
cJSON *tags = cJSON_GetObjectItem(event, "tags");
|
||||
if (tags && cJSON_IsArray(tags)) {
|
||||
cJSON *tag = NULL;
|
||||
cJSON_ArrayForEach(tag, tags) {
|
||||
if (!cJSON_IsArray(tag))
|
||||
continue;
|
||||
|
||||
cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
cJSON *tag_value = cJSON_GetArrayItem(tag, 1);
|
||||
|
||||
if (!tag_name || !cJSON_IsString(tag_name) || !tag_value ||
|
||||
!cJSON_IsString(tag_value))
|
||||
continue;
|
||||
|
||||
const char *key = cJSON_GetStringValue(tag_name);
|
||||
const char *value = cJSON_GetStringValue(tag_value);
|
||||
|
||||
if (strcmp(key, "server_privkey") == 0) {
|
||||
// Store server private key in global variable (memory only)
|
||||
// strncpy(server_private_key, value, sizeof(server_private_key) - 1);
|
||||
// server_private_key[sizeof(server_private_key) - 1] = '\0';
|
||||
} else {
|
||||
// Store other config values in database
|
||||
rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, value, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 3, "From config event", -1, SQLITE_STATIC);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Interactive setup runner
|
||||
int run_interactive_setup(const char *config_path) {
|
||||
printf("\n=== Ginxsom First-Time Setup Required ===\n");
|
||||
printf("No configuration found at: %s\n\n", config_path);
|
||||
printf("Options:\n");
|
||||
printf("1. Run interactive setup wizard\n");
|
||||
printf("2. Exit and create config manually\n");
|
||||
printf("Choice (1/2): ");
|
||||
|
||||
char choice[10];
|
||||
if (!fgets(choice, sizeof(choice), stdin)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (choice[0] == '1') {
|
||||
// Run setup script
|
||||
char script_path[512];
|
||||
snprintf(script_path, sizeof(script_path), "./scripts/setup.sh \"%s\"",
|
||||
config_path);
|
||||
return system(script_path);
|
||||
} else {
|
||||
printf("\nManual setup instructions:\n");
|
||||
printf("1. Run: ./scripts/generate_config.sh\n");
|
||||
printf("2. Place signed config at: %s\n", config_path);
|
||||
printf("3. Restart ginxsom\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Function declarations
|
||||
void handle_options_request(void);
|
||||
@@ -434,7 +189,23 @@ int file_exists_with_type(const char *sha256, const char *mime_type) {
|
||||
char filepath[MAX_PATH_LEN];
|
||||
const char *extension = mime_to_extension(mime_type);
|
||||
|
||||
snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256, extension);
|
||||
// Construct path safely
|
||||
size_t dir_len = strlen(g_storage_dir);
|
||||
size_t sha_len = strlen(sha256);
|
||||
size_t ext_len = strlen(extension);
|
||||
size_t total_len = dir_len + 1 + sha_len + ext_len + 1; // +1 for /, +1 for null
|
||||
|
||||
if (total_len > sizeof(filepath)) {
|
||||
fprintf(stderr, "WARNING: File path too long for buffer: %s/%s%s\n", g_storage_dir, sha256, extension);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Build path manually to avoid compiler warnings
|
||||
memcpy(filepath, g_storage_dir, dir_len);
|
||||
filepath[dir_len] = '/';
|
||||
memcpy(filepath + dir_len + 1, sha256, sha_len);
|
||||
memcpy(filepath + dir_len + 1 + sha_len, extension, ext_len);
|
||||
filepath[total_len - 1] = '\0';
|
||||
|
||||
struct stat st;
|
||||
int result = stat(filepath, &st);
|
||||
@@ -524,18 +295,6 @@ const char *extract_sha256_from_uri(const char *uri) {
|
||||
return sha256_buffer;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BUD 02 - Upload & Authentication
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AUTHENTICATION RULES SYSTEM (4.1.2)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -911,7 +670,23 @@ void handle_delete_request_with_validation(const char *sha256, nostr_request_res
|
||||
}
|
||||
|
||||
char filepath[MAX_PATH_LEN];
|
||||
snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256, extension);
|
||||
// Construct path safely
|
||||
size_t dir_len = strlen(g_storage_dir);
|
||||
size_t sha_len = strlen(sha256);
|
||||
size_t ext_len = strlen(extension);
|
||||
size_t total_len = dir_len + 1 + sha_len + ext_len + 1; // +1 for /, +1 for null
|
||||
|
||||
if (total_len > sizeof(filepath)) {
|
||||
fprintf(stderr, "WARNING: File path too long for buffer: %s/%s%s\n", g_storage_dir, sha256, extension);
|
||||
// Continue anyway - unlink will fail gracefully
|
||||
} else {
|
||||
// Build path manually to avoid compiler warnings
|
||||
memcpy(filepath, g_storage_dir, dir_len);
|
||||
filepath[dir_len] = '/';
|
||||
memcpy(filepath + dir_len + 1, sha256, sha_len);
|
||||
memcpy(filepath + dir_len + 1 + sha_len, extension, ext_len);
|
||||
filepath[total_len - 1] = '\0';
|
||||
}
|
||||
|
||||
// Delete the physical file
|
||||
if (unlink(filepath) != 0) {
|
||||
@@ -1029,9 +804,29 @@ void handle_upload_request(void) {
|
||||
// Determine file extension from Content-Type using centralized mapping
|
||||
const char *extension = mime_to_extension(content_type);
|
||||
|
||||
// Save file to blobs directory with SHA-256 + extension
|
||||
// Save file to storage directory with SHA-256 + extension
|
||||
char filepath[MAX_PATH_LEN];
|
||||
snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256_hex, extension);
|
||||
// Construct path safely
|
||||
size_t dir_len = strlen(g_storage_dir);
|
||||
size_t sha_len = strlen(sha256_hex);
|
||||
size_t ext_len = strlen(extension);
|
||||
size_t total_len = dir_len + 1 + sha_len + ext_len + 1; // +1 for /, +1 for null
|
||||
|
||||
if (total_len > sizeof(filepath)) {
|
||||
fprintf(stderr, "WARNING: File path too long for buffer: %s/%s%s\n", g_storage_dir, sha256_hex, extension);
|
||||
printf("Status: 500 Internal Server Error\r\n");
|
||||
|
||||
printf("Content-Type: text/plain\r\n\r\n");
|
||||
printf("File path too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build path manually to avoid compiler warnings
|
||||
memcpy(filepath, g_storage_dir, dir_len);
|
||||
filepath[dir_len] = '/';
|
||||
memcpy(filepath + dir_len + 1, sha256_hex, sha_len);
|
||||
memcpy(filepath + dir_len + 1 + sha_len, extension, ext_len);
|
||||
filepath[total_len - 1] = '\0';
|
||||
|
||||
FILE *outfile = fopen(filepath, "wb");
|
||||
if (!outfile) {
|
||||
@@ -1280,9 +1075,29 @@ void handle_upload_request_with_validation(nostr_request_result_t* validation_re
|
||||
// Determine file extension from Content-Type using centralized mapping
|
||||
const char *extension = mime_to_extension(content_type);
|
||||
|
||||
// Save file to blobs directory with SHA-256 + extension
|
||||
// Save file to storage directory with SHA-256 + extension
|
||||
char filepath[MAX_PATH_LEN];
|
||||
snprintf(filepath, sizeof(filepath), "blobs/%s%s", sha256_hex, extension);
|
||||
// Construct path safely
|
||||
size_t dir_len = strlen(g_storage_dir);
|
||||
size_t sha_len = strlen(sha256_hex);
|
||||
size_t ext_len = strlen(extension);
|
||||
size_t total_len = dir_len + 1 + sha_len + ext_len + 1; // +1 for /, +1 for null
|
||||
|
||||
if (total_len > sizeof(filepath)) {
|
||||
fprintf(stderr, "WARNING: File path too long for buffer: %s/%s%s\n", g_storage_dir, sha256_hex, extension);
|
||||
printf("Status: 500 Internal Server Error\r\n");
|
||||
|
||||
printf("Content-Type: text/plain\r\n\r\n");
|
||||
printf("File path too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build path manually to avoid compiler warnings
|
||||
memcpy(filepath, g_storage_dir, dir_len);
|
||||
filepath[dir_len] = '/';
|
||||
memcpy(filepath + dir_len + 1, sha256_hex, sha_len);
|
||||
memcpy(filepath + dir_len + 1 + sha_len, extension, ext_len);
|
||||
filepath[total_len - 1] = '\0';
|
||||
|
||||
FILE *outfile = fopen(filepath, "wb");
|
||||
if (!outfile) {
|
||||
@@ -1480,7 +1295,31 @@ void handle_auth_challenge_request(void) {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void) {
|
||||
int main(int argc, char *argv[]) {
|
||||
// Parse command line arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--db-path") == 0 && i + 1 < argc) {
|
||||
strncpy(g_db_path, argv[i + 1], sizeof(g_db_path) - 1);
|
||||
i++; // Skip next argument
|
||||
} else if (strcmp(argv[i], "--storage-dir") == 0 && i + 1 < argc) {
|
||||
strncpy(g_storage_dir, argv[i + 1], sizeof(g_storage_dir) - 1);
|
||||
i++; // Skip next argument
|
||||
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
printf("Usage: %s [options]\n", argv[0]);
|
||||
printf("Options:\n");
|
||||
printf(" --db-path PATH Database file path (default: db/ginxsom.db)\n");
|
||||
printf(" --storage-dir DIR Storage directory for files (default: blobs)\n");
|
||||
printf(" --help, -h Show this help message\n");
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[i]);
|
||||
fprintf(stderr, "Use --help for usage information\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "STARTUP: Using database path: %s\n", g_db_path);
|
||||
fprintf(stderr, "STARTUP: Using storage directory: %s\n", g_storage_dir);
|
||||
|
||||
// Initialize server configuration and identity
|
||||
// Try file-based config first, then fall back to database config
|
||||
|
||||
Reference in New Issue
Block a user