CallBackery
view release on metacpan or search on metacpan
"%2" standing in the result.
- New trmJoin($sep,@parts) for a message whose number of parts is only
known at run time -- a list of warnings, the flags on a table row.
join() was the obvious thing to reach for and it stringified every part;
the msgid trmJoin builds holds nothing but placeholders and the
separator, so all the words stay in the parts.
0.60.1 2026-09-09 22:37:58 +0200 Tobias Oetiker <tobi@oetiker.ch>
- SECURITY: CallBackery::Plugin::Doc passed the client supplied document
name to Pod::Simple::Search->find without validation. find() treats
"::" as a path separator, so a name such as "..::..::..::etc::motd"
escaped @INC and let an unauthenticated GET on /doc render the POD of
any file readable by the server process. Because the traversal stays
inside a single URL path segment, no browser, router or reverse proxy
ever saw a ".." segment to normalise away. The document name is now
required to be a plain module name (\w+ parts joined by "::") and
anything else answers 404 without echoing the name back. Reported by
CPANSec. (CWE-22)
- CallBackery::Plugin::Doc now reads the documentation file with a three
argument open instead of IO::File and a two argument "< $path", and
checks that the open succeeded. Hardening only, as the path is built
from the validated module name.
- The test suite no longer drops a callbackery.db into the current
directory. t/callbackery.cfg names its config database with a relative
path, so every test built straight from it wrote into the checkout
root. The new t/lib/CallBackeryTest.pm redirects cfg_db to a uniquely
named database below the system temp directory, which is removed when
the test process exits.
- MANIFEST was missing five of the seven test files, so released
tarballs shipped only t/basic.t. All tests are listed now.
0.60.0 2026-08-27 08:42:19 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Excel export: new makeExportAction option "extraCols" adds generated
columns to an XLSX export. The only type so far is "qrCode", which
embeds the content of a selectable field as a QR code image. The
content comes from a table key or a code reference, the column is
placed after its source column or at an explicit insertAfter index,
and label and size are configurable. Needs Text::QRCode, which is
loaded only when such a column is exported. CSV exports ignore the
option.
- CallBackery::GuiPlugin::AbstractTable used Mojo::Asset::Memory
without loading it, and only worked because Mojolicious happened to
have loaded it already.
0.59.0 2026-08-20 08:58:50 +0200 Tobias Oetiker <tobi@oetiker.ch>
- New optional actionCfg property "noBusyIndicator" for download and
display actions. When set, the modal busy indicator ("Preparing
Download ...") is not shown while the download is being prepared, so
the gui stays usable for actions which take a long time to produce
their data. Default behaviour is unchanged.
0.58.4 2026-07-31 16:15:51 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Frontend ui.Login: a login could be lost outright. The credentials
were copied into the hidden iframe form that exists only to make the
browser offer to save the password, and that copy ran before the
login call, unguarded. The iframe reloads /login every time the login
window appears, so whenever that fetch had not completed yet -- a
busy server is enough -- getElementById returned null, the handler
threw on it, and the login request was never sent. The form had
already disabled itself, so it just sat there greyed out with nothing
on screen to explain it, and only a reload got the user out of it.
The password manager hand-off now happens after a successful login
and is fully guarded, so it can miss the save prompt but can no
longer come between the user and their session.
0.58.3 2026-07-30 16:11:29 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Config: restoring a configuration blob replaced the configuration
database file, giving it a new inode. Every connection open at the
time stayed attached to the old, now unlinked file: it went on
reading the pre-restore configuration and failed on its first write
with SQLITE_READONLY_DBMOVED, which SQLite reports as "attempt to
write a readonly database". With a prefork server and background
helpers that is most of the processes on the machine. The
replacement database is now built beside the live one and copied in
with SQLite's online backup API, so the inode is preserved and open
connections simply see the restored data. If the write lock cannot
be had within 30 seconds the restore now gives up with an error and
leaves the database untouched, rather than restoring it half way.
0.58.2 2026-07-20 12:54:27 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Frontend ui.plugin.Form: make sure trigger load does not overwrite
fix for automated testing which fills forms very quickly
0.58.1 2026-07-16 08:39:18 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Frontend ui.plugin.Form: a trigger-field change made while form data
was still loading parked its form reconfiguration in _reconfPending
and never sent it â the affected form stayed in its stale layout
(e.g. fields that the reset should reveal never appeared) until the
user toggled the trigger field again. The pending queue is now
drained when loading completes.
0.58.0 2026-07-15 17:23:33 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Session expiry now surfaces as a dedicated RPC code 7 ("session
expired"), distinct from code 6 ("login required"). allow_rpc_access
guards plugin instantiation so an expired session no longer escapes as
a generic error. CallBackery::User gains a per-request `sessionExpired`
flag for subclasses that enforce a cookie max-age.
- Frontend data.Server: session expiry shows a single deduplicated
"Session Expired -> Reload" prompt instead of a storm of error popups.
Communication failures (server unreachable / proxy returning garbage)
now retry silently for idempotent reads, then show one "Connection
problem" dialog with Retry / Reload. MsgBox gains reload/retry buttons.
0.57.0 2026-06-16 08:58:42 +0200 Tobias Oetiker <tobi@oetiker.ch>
- We are on JSON-RPC 2.0 now. callbackery.data.Server now uses
qx.io.jsonrpc.Client (qooxdoo 7.x) instead of the deprecated
qx.io.remote.Rpc.
( run in 0.836 second using v1.01-cache-2.11-cpan-007c89162af )