• v0.2.0 1440e9a1fd

    v0.2.0 Stable

    petrbalvin released this 2026-06-25 20:14:38 +00:00 | 39 commits to main since this release

    Added

    • <pubDate> in RSS feed items, derived from the post date.
    • <lastmod> in sitemap entries for SEO.
    • In-memory rate limiting on the login endpoint: 10 attempts per 60 seconds per IP.
    • <language> element in the RSS feed channel.
    • Periodic cleanup of stale login_attempts entries to prevent unbounded memory growth.
    • Slug format validation ([a-z0-9._-]) preventing path traversal and XSS in templates.
    • Username validation in change_username matching the create-user regex.
    • Escape-on-output for slug and username in admin template attributes.
    • Memoization of Store#all with mtime-based invalidation, eliminating N×read+parse
      per request.
    • Atomic file writes (tmp + rename) for posts and users.toml.
    • Post language directory routing: non-default-language posts now land in
      content_dir/<lang>/ instead of overwriting root-level files.
    • CLI test coverage (version, help, unknown command, option parsing, config bootstrap).
    • Test coverage for RSS feed and sitemap endpoints.
    • CORS preflight (OPTIONS /api/volumen/*) so browsers can reach the JSON API.
    • Users#all memoization with mtime-based invalidation, matching Store#all.
    • Session invalidation: deleted users can no longer use existing session cookies.
    • CSRF protection on POST /admin/preview.
    • Symlink-safe containment in Store#media_file via File.realpath.

    Added

    • Scheduled publishing: a publish_at frontmatter field hides posts from the
      public API and feeds until their publication date arrives. The admin form
      includes a Publish at date picker.
    • JSON Feed: GET /api/volumen/feed.json serves a jsonfeed.org v1.1 feed
      with content_html and date_published per item.
    • Fulltext search: GET /api/volumen/posts?q=… filters posts by
      case-insensitive match in title and body.

    Changed

    • Split lib/volumen/server.rb into api_routes.rb and admin_routes.rb modules,
      keeping the server class focused on configuration and shared helpers.

    Fixed

    • admin.session_ttl was defined but never read; it now controls
      Rack::Session::Cookie expiration via expire_after.
    • Derived post excerpts now strip HTML tags before stripping markdown markup,
      avoiding raw HTML leaks in auto-generated excerpts.
    • Draft posts no longer leak through the public detail endpoint (/api/volumen/posts/:slug).
    • Config::DEFAULTS inner hashes are now frozen and deep_merge builds fresh
      copies, preventing mutation from silently poisoning later Config.load calls.
    • A warning is emitted when admin.session_key is configured but shorter than
      64 bytes, instead of silently falling back to a random secret.
    Downloads