diff --git a/index.c b/index.c
index 90c0089..98b02dc 100755
--- a/index.c
+++ b/index.c
@@ -12,6 +12,7 @@
#define MAX_ENTRIES 1000
#define TEMPLATE_PATH "/home/romkazvo/www/cgi-bin/template.html"
#define OUTPUT_BUFFER_SIZE 65536
+#define PASSWD_FILE "/home/romkazvo/www/cgi-bin/.htpasswd"
typedef struct {
char name[256];
@@ -20,6 +21,7 @@ typedef struct {
char icon[8];
char encoded_path[1024];
char file_url[1024];
+ int is_protected;
} entry_t;
// Быстрый буферизированный вывод
@@ -58,6 +60,53 @@ void buffer_free(buffer_t *buf) {
free(buf->data);
}
+// Функция проверки пароля для папки
+int check_folder_password(const char *folder_name, const char *password) {
+ FILE *f = fopen(PASSWD_FILE, "r");
+ if (!f) return 1; // Если нет файла с паролями - доступ разрешен
+
+ char line[512];
+ while (fgets(line, sizeof(line), f)) {
+ // Убираем перевод строки
+ line[strcspn(line, "\r\n")] = 0;
+
+ char *colon = strchr(line, ':');
+ if (!colon) continue;
+
+ *colon = '\0';
+ char *folder = line;
+ char *pass = colon + 1;
+
+ if (strcmp(folder, folder_name) == 0) {
+ fclose(f);
+ return strcmp(pass, password) == 0;
+ }
+ }
+ fclose(f);
+ return 1; // Папка не найдена в списке - доступ разрешен
+}
+
+// Проверяет, защищена ли папка паролем
+int is_folder_protected(const char *folder_name) {
+ FILE *f = fopen(PASSWD_FILE, "r");
+ if (!f) return 0;
+
+ char line[512];
+ while (fgets(line, sizeof(line), f)) {
+ line[strcspn(line, "\r\n")] = 0;
+ char *colon = strchr(line, ':');
+ if (!colon) continue;
+
+ *colon = '\0';
+ if (strcmp(line, folder_name) == 0) {
+ fclose(f);
+ return 1;
+ }
+ }
+ fclose(f);
+ return 0;
+}
+
const char* get_file_icon(const char* filename) {
const char *ext = strrchr(filename, '.');
if (!ext) return "📄";
@@ -90,21 +139,18 @@ const char* get_file_icon(const char* filename) {
return "📄";
}
-// Проверяет, можно ли открыть файл в браузере
int is_previewable(const char* filename) {
const char *ext = strrchr(filename, '.');
if (!ext) return 0;
ext++;
- // Изображения
if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0 ||
strcasecmp(ext, "png") == 0 || strcasecmp(ext, "gif") == 0 ||
strcasecmp(ext, "webp") == 0 || strcasecmp(ext, "bmp") == 0 ||
strcasecmp(ext, "svg") == 0 || strcasecmp(ext, "ico") == 0)
return 1;
- // Текстовые файлы
if (strcasecmp(ext, "txt") == 0 || strcasecmp(ext, "md") == 0 ||
strcasecmp(ext, "html") == 0 || strcasecmp(ext, "htm") == 0 ||
strcasecmp(ext, "css") == 0 || strcasecmp(ext, "js") == 0 ||
@@ -112,17 +158,14 @@ int is_previewable(const char* filename) {
strcasecmp(ext, "csv") == 0)
return 1;
- // PDF
if (strcasecmp(ext, "pdf") == 0)
return 1;
- // Аудио
if (strcasecmp(ext, "mp3") == 0 || strcasecmp(ext, "wav") == 0 ||
strcasecmp(ext, "ogg") == 0 || strcasecmp(ext, "flac") == 0 ||
strcasecmp(ext, "m4a") == 0 || strcasecmp(ext, "aac") == 0)
return 1;
- // Видео
if (strcasecmp(ext, "mp4") == 0 || strcasecmp(ext, "webm") == 0 ||
strcasecmp(ext, "ogv") == 0 || strcasecmp(ext, "mov") == 0 ||
strcasecmp(ext, "avi") == 0 || strcasecmp(ext, "mkv") == 0)
@@ -254,6 +297,37 @@ void print_breadcrumb(buffer_t *buf, const char *display_path) {
buffer_append(buf, "\n\n");
}
+void print_password_form(buffer_t *buf, const char *folder_name) {
+ buffer_append(buf, "
\n");
+}
+
void print_content(buffer_t *buf, const char *base_path, const char *display_path) {
DIR *dir;
struct dirent *entry;
@@ -265,6 +339,46 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
int dir_count = 0, file_count = 0;
long long total_size = 0;
+ // Проверяем, не защищена ли текущая папка паролем
+ char folder_name[256] = "";
+ if (display_path && display_path[0]) {
+ char *last_slash = strrchr(display_path, '/');
+ if (last_slash) {
+ strcpy(folder_name, last_slash + 1);
+ } else {
+ strcpy(folder_name, display_path);
+ }
+
+ // Проверяем пароль
+ char *query_string = getenv("QUERY_STRING");
+ char *password = NULL;
+ if (query_string) {
+ char *pass_start = strstr(query_string, "password=");
+ if (pass_start) {
+ pass_start += 9;
+ char *pass_end = strchr(pass_start, '&');
+ int pass_len = pass_end ? pass_end - pass_start : strlen(pass_start);
+ if (pass_len > 0 && pass_len < 256) {
+ char pass_buf[256];
+ strncpy(pass_buf, pass_start, pass_len);
+ pass_buf[pass_len] = '\0';
+ // URL декодируем пароль
+ char decoded_pass[256];
+ url_decode_enhanced(pass_buf, decoded_pass, sizeof(decoded_pass));
+ password = decoded_pass;
+ }
+ }
+ }
+
+ if (is_folder_protected(folder_name)) {
+ if (!password || !check_folder_password(folder_name, password)) {
+ // Показываем форму ввода пароля
+ print_password_form(buf, folder_name);
+ return;
+ }
+ }
+ }
+
dir = opendir(base_path);
if (!dir) {
char alt_path[1024];
@@ -298,6 +412,14 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
continue;
if (strcmp(entry->d_name, "cgi-bin") == 0)
continue;
+ // Скрываем файл с паролями (на всякий случай, если кто-то сможет получить доступ)
+ if (strcmp(entry->d_name, ".htpasswd") == 0)
+ continue;
+ if (strcmp(entry->d_name, ".htaccess") == 0)
+ continue;
+ // Скрываем все файлы, начинающиеся с точки
+ if (entry->d_name[0] == '.')
+ continue;
snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name);
@@ -308,9 +430,16 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
if (S_ISDIR(file_stat.st_mode)) {
entries[entry_count].is_dir = 1;
entries[entry_count].size = 0;
- strcpy(entries[entry_count].icon, "📁");
- // Предварительно кодируем путь для папок
+ // Проверяем, защищена ли папка
+ if (is_folder_protected(entry->d_name)) {
+ strcpy(entries[entry_count].icon, "🔒");
+ entries[entry_count].is_protected = 1;
+ } else {
+ strcpy(entries[entry_count].icon, "📁");
+ entries[entry_count].is_protected = 0;
+ }
+
char new_path[2048];
snprintf(new_path, sizeof(new_path), "%s%s%s", display_path,
display_path[0] ? "/" : "", entries[entry_count].name);
@@ -321,8 +450,8 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
entries[entry_count].is_dir = 0;
entries[entry_count].size = file_stat.st_size;
strcpy(entries[entry_count].icon, get_file_icon(entry->d_name));
+ entries[entry_count].is_protected = 0;
- // Предварительно формируем URL для файлов
snprintf(entries[entry_count].file_url, sizeof(entries[0].file_url),
"%s%s%s", display_path, display_path[0] ? "/" : "", entries[entry_count].name);
@@ -349,7 +478,7 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
buffer_append(buf, "\n");
- // Вывод папок с предварительно закодированными путями
+ // Вывод папок
if (dir_count > 0) {
char section_title[128];
snprintf(section_title, sizeof(section_title), " - 📁 Папки (%d)
\n", dir_count);
@@ -358,24 +487,49 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
for (int i = 0; i < entry_count; i++) {
if (entries[i].is_dir) {
buffer_append(buf, " - \n");
- char dir_link[512];
- snprintf(dir_link, sizeof(dir_link),
- " \n",
- entries[i].encoded_path);
- buffer_append(buf, dir_link);
- buffer_append(buf, " ");
- buffer_append(buf, entries[i].icon);
- buffer_append(buf, "\n");
- buffer_append(buf, " ");
- buffer_append(buf, entries[i].name);
- buffer_append(buf, "\n");
- buffer_append(buf, " \n");
+
+ if (entries[i].is_protected) {
+ // Защищенная папка
+ buffer_append(buf, "
\n");
+ buffer_append(buf, "
\n");
+ buffer_append(buf, " 🔒\n");
+ buffer_append(buf, " ");
+ buffer_append(buf, entries[i].name);
+ buffer_append(buf, " (защищена)\n");
+ buffer_append(buf, " \n");
+ buffer_append(buf, "
\n");
+ buffer_append(buf, " \n");
+ buffer_append(buf, "
\n");
+ buffer_append(buf, "
\n");
+ } else {
+ // Обычная папка
+ char dir_link[512];
+ snprintf(dir_link, sizeof(dir_link),
+ " \n",
+ entries[i].encoded_path);
+ buffer_append(buf, dir_link);
+ buffer_append(buf, " ");
+ buffer_append(buf, entries[i].icon);
+ buffer_append(buf, "\n");
+ buffer_append(buf, " ");
+ buffer_append(buf, entries[i].name);
+ buffer_append(buf, "\n");
+ buffer_append(buf, " \n");
+ }
buffer_append(buf, " \n");
}
}
}
- // Вывод файлов с предварительно сформированными URL
+ // Вывод файлов
if (file_count > 0) {
char section_title[128];
snprintf(section_title, sizeof(section_title), " - 📄 Файлы (%d)
\n", file_count);
@@ -389,7 +543,6 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
buffer_append(buf, " - \n");
buffer_append(buf, "
\n");
- // Основная ссылка для скачивания
buffer_append(buf, "
\n");
@@ -403,7 +556,6 @@ void print_content(buffer_t *buf, const char *base_path, const char *display_pat
buffer_append(buf, " \n");
- // Кнопка предпросмотра (если поддерживается)
if (is_previewable(entries[i].name)) {
buffer_append(buf, "