EaglePress

EaglePress CMS latest version!

version 1.19 Hot off the Press!

4095b754_eaglepress_v1.19.zip4095b754_eaglepress_v1.19.zip

Description changelog:
---- 1.19 on mobile phones, chrome & firefox wordwrap works of the editor of the syntax highlighting (programming languages and markdown content).

Welcome to EaglePress, version 1.18!

EaglePress
Direct Download #1 Recommended!
EaglePress 1.18c64c7a21_eaglepress_v1.18.zip

Download link #2 EaglePress 1.18

--- GitHub EaglePress v1.18

Markdown + HTML
# EaglePress — Summary Project Press

**Platform:** Python 3 CGI + PostgreSQL Web Publishing System
**Current Version:** 1.1.8
**Date:** May 2026

---

## What Is EaglePress?

A self-hosted, open-source CMS and blog platform built entirely in Python 3 and PostgreSQL. No web framework. No ORM. Runs on any Apache or Nginx server with CGI support.

---

## Core Highlights

- Pure Python 3 CGI router — zero external framework dependency
- PostgreSQL backend — 10 normalized tables, FK constraints, indexed queries
- Zero-config installer — one SQL file + one Python script sets up everything
- Clean URL routing via `PATH_INFO` with `?r=` fallback
- Full theme system — drop-in theme directories, exec-based renderer

---

## Security

- PBKDF2-HMAC-SHA256 passwords — 310,000 iterations (NIST-recommended)
- Session tokens — 64-character hex, stored in DB, 30-day expiry with IP + user-agent logging
- 100% parameterized queries — no SQL injection surface
- XSS protection — all output routed through `html.escape()`
- Upload safety — extension + MIME-type whitelist, server-side enforced
- CGI errors isolated to `tmp_errors/` — never exposed to visitors

---

## CGI Library — `cgi_improved2.py`

A custom drop-in replacement for Python's deprecated `cgi` and `cgitb` standard library modules, written specifically for EaglePress.

**Parsing architecture:**
- Streaming 64 KB-chunk multipart parser — peak memory scales with the largest single part, not the total body
- Replaces the legacy approach of reading the entire POST body into RAM before parsing

**Hard request limits:**
- 10 MB maximum total POST body
- 5 MB maximum per uploaded file
- 200 maximum form fields per request
- 70-byte maximum boundary length (RFC 2046)
- 1024-byte maximum uploaded filename length

**Security measures built into the library:**
- RFC 5987 filename decoding — handles `filename*=UTF-8''encoded` form
- Charset validation for text parts against a safe-charsets allowlist
- Error log redaction — sensitive local variable names (`password`, `password_hash`, `token`, `session`, `USERNAME`, `PASSWORD`, `cc_number`, database cursors, raw request body) are replaced with `<redacted>` in all traceback logs
- HTTP header redaction — `HTTP_COOKIE`, `HTTP_AUTHORIZATION`, `HTTP_PROXY_AUTHORIZATION` stripped from logged environment dumps
- Log file permissions set to `0o600` — readable only by the server process owner
- Traceback output suppressed from HTTP responses by default (`display=0`)
- Variable repr truncation — log entries capped at 200 characters per value, 30 variables per frame

**Drop-in compatible** — same `cgi.FieldStorage()` / `cgitb.enable()` interface as the standard library.

---

## Content Management

- Posts and pages — draft, published, preview states; soft-delete to trash
- Auto-generated slugs — deduplicated with `-2`, `-3` suffixes
- Categories (hierarchical) and tags
- Featured images, view counter, comment toggle per post
- Comment threading with moderation queue
- User profiles with avatar upload and Gravatar fallback

---

## Markdown Parser

Custom server-side Markdown-to-HTML with no third-party packages:

- ATX headings, bold, italic, strikethrough
- Fenced code blocks with syntax highlighting
- Ordered and unordered lists, blockquotes, horizontal rules
- Extended image syntax — size (`=WxH`), alignment, title
- Download buttons for non-image file links
- Shortcodes for embedding post/page links
- External links auto-tagged `rel="noopener"`
- Raw HTML pass-through

---

## Syntax Highlighting

Custom pure-Python engine (`syntax_highlight.py` + `syntax_themes.py`) — no external packages.

**12 languages** + plain text: Python 3, JavaScript, CSS, HTML, PHP, Bash, C, C++, Lua, Perl, SQL, Markdown + HTML

**11 colour themes**: github-dark, atom-one-dark, monokai, dracula, nord, tokyo-night-dark, github, atom-one-light, solarized-light, vs, xcode

**Per-block features:** language label, language selector drop-down, theme selector drop-down, copy button, keyboard navigation

**Score-based auto-detection** — no lang hint needed; fenced block content stripped before scoring to prevent embedded language examples from polluting outer document detection

---

## Frontend Reader Experience

- Image lightbox with keyboard navigation
- Reading progress bar
- Back-to-top button
- Like button (localStorage)
- Social share — Copy link, Twitter, Facebook
- Lazy image loading + fade-in scroll animations

---

## Admin Panel

- Dashboard with live stats
- Post / page editor with live Markdown preview
- Media library — upload, browse, delete
- User management — five roles: admin, editor, author, contributor, subscriber
- Comment moderation queue
- Category management
- Site settings

---

## Theme System

Themes are self-contained directories. The active theme's `theme.py` is exec'd by the router with all page variables pre-populated. Bundled themes: `firstTheme`, `secondTheme`, `americanTheme`, `USAtheme`.

---

## Version History (overview)

| Version | Title |
|---|---|
| v1.0 | Foundation Release |
| v1.01 | Theme Expansion |
| v1.02 | Syntax Highlighting Engine |
| v1.03 | Markdown Parser Overhaul |
| v1.04 | SQL Language Support |
| v1.05 | Per-Block Theme Scoping |
| v1.06 | Reader Theme Persistence |
| v1.07 | Frontend Reader Experience |
| v1.08 | Streaming CGI Parser & Security (`cgi_improved2.py`) |
| v1.09 | Project Documentation & Archive Policy |
| v1.10 | Markdown + HTML Language & SQL Detection Fix |
| v1.11 | Markdown Auto-Detection Fix — fenced block stripping |
| v1.12 | Markdown Detection Hardened — ATX heading rule, tilde fence signal |
| v1.13 | highlight.js Markdown Grammar Fix — underscore in identifiers (`highlight_custom_improved.js`) |
| v1.14 | Markdown Highlighting — server-side Python tokenizer in `syntax_highlight.py`; JS grammar `h.regex.concat()` fixed |
| v1.15 | Markdown Highlighting — JS tokenizer in `highlight_custom_improved.js` replaces Python; patches `hljs.highlightElement()` for consistent single code path; all themes now load custom script |
| v1.16 | USAtheme + "Register" → "Create Account" | New USAtheme (red-dominant americanTheme variant); "Register" label renamed to "Create Account" in nav, login page link, and browser title across all themes and core |
| v1.17 | Code Block Word Wrap Toggle | Checkbox in code block toolbar (left of theme dropdown) to toggle `white-space: pre-wrap`; gold `#D4AF37` outline on checkbox when active; state persisted per-block in localStorage (`ep_ww_{pathname}_{index}`); restored on page load; all 4 themes + admin panel |
| v1.18 | Admin Password Change + Theme Preview | Settings page: Account Security section — current/new/confirm password fields with show/hide eye toggle, live strength meter (Weak→Fair→Good→Strong), confirm-match hint, AJAX endpoint `www_password_change.py`; Appearance section: live theme preview image (`.svg`) below active-theme dropdown, updates dynamically on selection change; SVG preview images for all 4 bundled themes |
| v1.19 | Firefox Android Word Wrap Fix | Added `.ep-code-block.ep-code-wrap pre code` CSS rule in `styles_core.css`; targets the `code` element directly with `white-space: pre-wrap`, `word-break: break-word`, `overflow-wrap: anywhere`, `overflow-x: hidden` — overrides the HLJS CDN stylesheet's `pre code.hljs { overflow-x: auto }` which was creating an independent scroll container in Gecko, preventing inherited wrap properties from taking effect on Firefox for Android |

---

## Technical Stack

| Layer | Technology |
|---|---|
| Language | Python 3.8+ |
| Database | PostgreSQL 12+ |
| Web server | Apache `mod_cgi` / Nginx `fcgiwrap` |
| Frontend JS | jQuery 4.0 (CDN) |
| Syntax highlighting | highlight.js (CDN) + custom JS tokenizer (`highlight_custom_improved.js`) |
| Dependencies | `psycopg2` only |

example of the syntax highlighting:

Python 3

import os

for root, dirs, files in os.walk("."):
    for name in files:
        print(os.path.join(root, name)) # Prints the full path of every file
    for name in dirs:
        print(os.path.join(root, name)) # Prints the full path of every folder
Bash
traverse() {
    for file in "$1"/*; do
        if [ -d "$file" ]; then
            echo "Directory: $file"
            traverse "$file"  # Recursive call
        elif [ -f "$file" ]; then
            echo "File: $file"
        fi
    done
}

# Usage
traverse "/your/start/path"
JavaScript
function listFiles($dir) {
    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            listFiles($path); // Recursive call
        } else {
            echo $path . PHP_EOL;
        }
    }
}
C
#include <stdio.h>
#include <dirent.h>

int main() {
    struct dirent *entry;
    DIR *dp = opendir("."); // Open current directory

    if (dp == NULL) {
        perror("opendir");
        return 1;
    }

    while ((entry = readdir(dp))) {
        printf("%s\n", entry->d_name);
    }

    closedir(dp);
    return 0;
}
C++
#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    std::string path = "./my_directory";

    for (const auto& entry : fs::recursive_directory_iterator(path)) {
        std::cout << entry.path() << std::endl;
    }
    return 0;
}
Lua
local lfs = require("lfs")
local path = "."

for file in lfs.dir(path) do
    if file ~= "." and file ~= ".." then
        local full_path = path .. "/" .. file
        print("Found: " .. full_path)

        -- Check if it's a directory to recurse
        local mode = lfs.attributes(full_path, "mode")
        if mode == "directory" then
            print(full_path .. " is a directory")
        end
    end
end
Perl
use strict;
use warnings;
use File::Find;

# Specify the directory you want to start from
my $dir = '.'; 

# find() takes a code reference and the starting directory
find(\&process_file, $dir);

sub process_file {
    # $_ contains the current filename
    # $File::Find::name contains the full path to the file
    print "Found file: $File::Find::name\n" if -f $_;
}
SQL
CREATE TABLE Inventory (
    ProductID INT PRIMARY KEY,           -- Unique identifier (Integer)
    ProductName VARCHAR(100) NOT NULL,   -- Variable-length text (Name)
    Quantity INT DEFAULT 0,              -- Whole number (Stock count)
    UnitPrice DECIMAL(10, 2),            -- Precise decimal for currency (Price)
    IsActive BIT DEFAULT 1,              -- Boolean flag (1 for true, 0 for false)
    LastUpdated DATETIME DEFAULT CURRENT_TIMESTAMP -- Date and time stamp
);

0 Comments

No comments yet. Be the first!

Leave a Comment