Skip to content

Releases: LordOfTheSnow/phpcirclebook

v1.1.2

Choose a tag to compare

@github-actions github-actions released this 12 Sep 12:13

Added

  • Outgoing emails (recipient list, admin approval request, approval confirmation) now end
    with a translatable footer naming the app and its APP_URL, e.g. "Originated by My
    Mailing List (https://list.example.com)" (mail.footer in lang/).
  • Optional TRUST_PROXY setting (.env): when the app runs behind a single trusted
    reverse proxy or load balancer, the client IP used for rate limiting is read from the
    X-Forwarded-For header instead of the proxy's own address. Left false by default.

Fixed

  • Mail subjects and the From display name are now RFC 2047 MIME-encoded
    (Mailer::encodeHeaderValue()) instead of sent as raw UTF-8. Some receiving mail
    servers rejected non-ASCII subjects outright ("550 Subject contains invalid
    characters"), even though most tolerate raw UTF-8 headers.
  • The web admin tool now shows a warning (instead of failing silently) when a status
    change to "approved" triggers a confirmation email that can't be sent, matching the
    CLI tool's existing behaviour.

Security

  • Fixed a CSV/spreadsheet formula injection vector: the name, public_note, and tags
    fields in the mailed recipient-list CSV attachment are now escaped (a leading =, +,
    -, @, tab, or carriage return is prefixed with '), so a registrant-supplied value
    can no longer be interpreted as a formula (e.g. =HYPERLINK(...)) by Excel or Sheets.
  • Pico CSS is now loaded from the CDN pinned to an exact version with a Subresource
    Integrity hash, instead of a floating @2 tag with no integrity check.
  • The admin tool now sends X-Frame-Options: DENY and a frame-ancestors 'none' CSP
    directive, preventing the login page from being framed for clickjacking / UI-redressing
    attacks.

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 01 Sep 15:51

Changed

  • Admin activity log moved from the bottom of the recipients page into a modal overlay.
    A "Logs" button in the action bar (next to "Add recipient" and "Log out") opens the
    overlay; it can be closed with the × button, a click on the backdrop, or the Escape
    key. The overlay is 85 % of the viewport width and scrolls vertically when the log
    contains more entries than fit on screen, with the column header remaining sticky.
  • Unsubscribe events are now recorded in the activity log (unsubscribed event) when a
    recipient removes themselves via the unsubscribe link.

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 31 Aug 16:53

Added

  • Activity log in the admin tool: a bounded log of the 200 most recent events, shown at
    the bottom of the admin page in a fixed-height, scrollable table (newest first). Logged
    events are membership applications (who applied), the admin's approve/reject decision,
    recipient deletions, and list requests by already-approved members. Entries are stored
    in a new logs table and pruned to the newest 200 on each insert.
  • List stats on the main page: below the info card, the current number of entries and the
    date of the last update are shown as a localised line (e.g. "No. of entries: 8. Last
    update: 30.08.2026."). Hidden while the list is empty.
  • APP_TIMEZONE setting: timezone used to display stored timestamps (the admin activity
    log and the main-page "last update" date). Any PHP timezone identifier, e.g.
    Europe/Berlin. Timestamps are stored in UTC and converted for display; when unset or
    invalid, the server's default timezone is used.

Changed

  • Recipient list emails now list public notes in a separate section below the addresses,
    under a divider, instead of appending them inline after each address. This keeps the
    address block clean so it can be copied straight into an email client. Each note line
    has the form Name (email): note, and only recipients that have a public note appear.
    The CSV attachment is unchanged and still carries the note column.
  • formatDate() now honours the timezone carried by a DateTimeInterface argument
    (previously the intl formatter ignored it and used PHP's default timezone), so
    timezone-converted values format on the correct local calendar day. Bare Unix-timestamp
    callers are unaffected.

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 30 Aug 11:46
1ea83ae

Added

  • Optional footer line on the main form, configurable via APP_FOOTER in .env.
    Shown only when set, with its own smaller serif styling and a divider above it.
  • Optional sidebar on the main form with two Markdown-driven cards, "Upcoming events"
    (content/events.md) and "Links" (content/links.md). Each card appears only when
    its file exists and is non-empty; if neither is present, the form stays full-width.
    The side is configurable via SIDEBAR_SIDE (left/right, default right) and the
    layout stacks below the form on narrow screens. Content is rendered with
    league/commonmark in a hardened mode (raw HTML stripped, unsafe links disallowed).
    Links in the cards open in a new tab (target="_blank", rel="noopener noreferrer").
    See ADR-004.
  • Logo left of the app name in the header, configurable via APP_LOGO in .env (a
    filename served from public/, or an absolute https URL). An empty value shows no
    logo; the shipped .env.example defaults to favicon.svg, so fresh installs show the
    bundled favicon. The logo auto-scales to the header height and may exceed it by at most
    40px; when taller than the title, the header row grows and its contents stay vertically
    centred.
  • Password show/hide toggle on the admin login field (an eye icon at the right edge).
  • Header attribution restyled: a smaller "powered by PHPCircleBook v… [GitHub icon]" link
    that wraps cleanly on mobile, on both the main and admin pages.

Security

  • Fixed an email header injection vector: a registrant's name flowed into the approval
    email subject, and a name containing CR/LF could inject extra mail headers (e.g. Bcc)
    or body content. Mail subjects are now stripped of all CR/LF at the lowest level in
    Mailer (sanitizeHeaderValue), covering all callers. Recipient addresses were already
    validated with FILTER_VALIDATE_EMAIL.
  • Hardened the admin status action to accept POST only (GET now redirects back to the
    list), matching the other state-changing actions. It was already CSRF-protected; this
    removes the inconsistency.

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 28 Aug 15:26

First tagged release. Covers the complete mailing-list application built so far: an
admin-gated registration flow, self-service list retrieval, and the supporting CLI
tooling, all running on plain PHP hosting with a single-file SQLite database.

Added

  • Admin-gated registration: visitors submit their email (and optional name) and the
    administrator receives an approval request with one-click approve/reject links. Nothing
    is exposed to the applicant until an admin acts.
  • Optional comment field on the registration form: a free-text field (max 500 characters,
    enforced both client-side and server-side) shown beneath the name field. The comment is
    stored in the database and included in the approval-request email to the admin, but is
    deliberately excluded from the recipient list and its CSV export.
  • Self-service list retrieval: approved members can request the current contact list at any
    time, delivered by email with a CSV attachment of all members.
  • Unsubscribe flow with a confirmation page, protected by an HMAC-signed token so links
    can't be forged.
  • Bot and abuse protection: a hidden honeypot field plus per-IP and per-email rate limiting.
  • Internationalisation: all user-facing strings live in per-locale PHP files (lang/en.php,
    lang/de.php), selected via APP_LOCALE, with English as the fallback for missing keys.
    Dates and numbers are formatted through the intl extension per locale.
  • Configurable info card on the main page via APP_DESCRIPTION, and an obfuscated admin
    contact email to deter harvesters.
  • CLI import tool (bin/import.php) for bulk-adding existing members from a
    semicolon-separated file. Entries are added as approved; the summary now reports which
    lines were actually imported alongside skipped duplicates and invalid lines.
  • CLI rate-limit reset tool (bin/reset-ratelimit.php) to clear throttling during testing.
  • MIT LICENSE file and project metadata (license, authors) in composer.json.
  • README badges (license, PHP version, SQLite, no-build) and setup/usage documentation.

Changed

  • Registration form styling made more prominent, especially on mobile: bolder, slightly
    larger field labels and clearly bordered, subtly filled input fields with a visible focus
    ring. Implemented by retuning Pico CSS's own custom properties and matching its control
    selectors, rather than plain overrides that Pico's shorthand would reset.