Repository navigation
release: v1.6.69 - #294
Open
roncodes wants to merge 25 commits into
Open
release: v1.6.69#294roncodes wants to merge 25 commits into
roncodes wants to merge 25 commits into
Conversation
- Drop the 'public' visibility from Utils::urlToStorefrontFile: a bucket with BucketOwnerEnforced rejects any PUT carrying an ACL, so put() returned false. - Add File::signStoredUrl()/s3KeyFromUrl(): turn absolute URLs stored as strings (legacy unsigned bucket URLs, expired signed URLs) back into a key and re-sign. - Re-sign template builder image src at render time. - Cache signed URLs for 60 of their 120 minutes so every URL handed out has at least an hour left; cut Extension icon_url cache from 24h to 30m.
Replace the db:backup command, which piped mysqldump through gzip without pipefail, swallowed upload errors and returned success on a failed dump. That is how production uploaded 20-byte empty dumps on 2026-09-24/25 (no mysqldump in the image) and then nothing at all while reporting DONE. - DatabaseBackupService streams the dump client's stdout into gzip in PHP (no shell pipeline), passes the password via MYSQL_PWD, and fails a run on a non-zero exit, a missing '-- Dump completed' marker, a dump under min_size_bytes, or an uploaded object whose size differs from the file. - Uploads go to any filesystem disk (bucket override for s3, key prefix); retention by age and/or count runs only after a fully successful run and always keeps each database's newest backup. - Every attempt is recorded in database_backups (status, size, duration, error, trigger); failures can email configured addresses. - Settings live in system.database-backups (env defaults in config/database-backups.php) and drive the schedule; disabled by default. - Admin endpoints under int/v1/database-backups: settings get/save/reset, recent runs, and a queued 'run now'. - db:backup exits non-zero on any failure; --force runs while disabled.
Add VerificationCode::issue(), check() and attemptsLeft() for flows where a leaked table must not give away live codes: - issue() stores an HMAC of the code, keyed by the app key, and hands the plain code back once on the instance (plainCode), defaulting to a 10-minute expiry and an 'active' status. - check() compares with hash_equals, counts wrong attempts in meta and locks the code on the last allowed one. Expired and locked codes report as such. - The creating hook keeps a code that was already set, so issue() is not overwritten; codes made the old way still get a random one and still check. Existing generators and their callers are unchanged. First user: the FleetOps public tracking page's one-time codes.
Adds the realtime channel authentication core, switched on by SOCKETCLUSTER_AUTH_KEY (config auth_key, publish_url, token_ttl): - SocketToken mints and verifies HS256 socket tokens (iss/aud/iat/nbf/exp/jti plus kind, sub, cid, cpid, env, ids, adm, scp, sid); anything not HS256 with the configured key, or with a wrong issuer/audience or out-of-range time claims, is rejected. Includes the scoped public tracking token. - SocketSignature derives per-purpose HMAC keys and signs/verifies the timestamped requests exchanged with the socket server. - SocketPrincipal, ChannelDecision, the SocketChannelResolver contract and the SocketChannelRegistry extensions register their channel prefixes with. - ChannelAuthorizer applies install, expiry, scope, system and self rules, then the prefix resolver, caching decisions per token and channel. - Core resolvers for company, api, user, test, install/uninstall, chat, chat_channel, chat_participant, chat_message and file channels. - The registry and authorizer are container singletons.
- POST int/v1/socket/token (console session): a user token for the current
company, in the sandbox environment when the console is in sandbox mode.
- POST v1/socket/token (public API): an api token for an API credential; for a
Sanctum user token, the principal a registered resolver claims, else a user
token.
- POST int/v1/socket/authorize: called by the socket server only, admitted by
its signature (VerifySocketSignature) rather than a session; re-verifies the
token and returns {allow, ttl, reason}. Exempt from the configured-instance
check so an install page can follow the install channel before setup ends.
- Every mint route answers 404 while SOCKETCLUSTER_AUTH_KEY is unset.
When SOCKETCLUSTER_AUTH_KEY is set, the broadcaster and
SocketClusterService::publish()/send() post every channel of a broadcast in a
single request to {SOCKETCLUSTER_PUBLISH_URL}/publish, signed with the derived
publish key and short timeouts. Without the key the websocket publisher is
used as before.
Channels ending in "." (an empty suffix, e.g. a session read in a queue
worker) and names the socket server would reject are dropped before
publishing.
… channel
The SocketCluster settings test ignored nothing: any admin could publish an
arbitrary payload to any channel. It now always publishes to
test.{current user uuid} and returns that channel so the console can
subscribe to it.
POST v1/socket/system-token in the fleetbase.platform-api group mints a system token. A separate path because the platform and public API groups share the v1 prefix, where v1/socket/token is the public API mint route.
…annel decision The install-channel test skipped the users table but still seeded it. The cross-company and driver tests now compare every channel's decision reason (and any resolver error logged) in one assertion.
… model ChatMessage always eager loads its attachments, so authorizing a chat_message channel queried chat_attachments for nothing (and failed where that table is absent). Channel lookups now load only the model's own row.
getCountryCodeByCurrency() and getCountryCodeByName() rebuilt the full countries dataset (a 4.7 MB JSON file plus flag hydration) on every call. Storefront serializes a country per store, so listing stores paid that cost once per record and network store lists could take minutes. The name/ISO2/currency rows are now built once, kept in the application cache and memoized per process. Cache failures fall back to building the lookup, and flushCountryLookup() resets it.
Store media, product images and proofs of delivery are looked up by subject_uuid, which had no index, so each lookup scanned the whole files table.
fix(files): support a fully private S3 media bucket
feat(backups): settings-driven database backups that fail loudly
feat(verification): hashed one-time codes with attempt counting
perf: cache the country lookup and index files.subject_uuid
Socket authentication was on as soon as SOCKETCLUSTER_AUTH_KEY was set. That
also moved every broadcast to the socket server's HTTP publish endpoint, so
provisioning the key before every client fetched tokens (or before the new
socket server was deployed) would break existing socket clients.
- New `broadcasting.connections.socketcluster.auth_enabled`
(SOCKETCLUSTER_AUTH_ENABLED, default false). SocketToken::enabled() now
needs the switch and a valid key. Every gated path follows: token routes,
the authorize endpoint and its signature check, and HTTP publishing.
- With the switch off, the console's socket test publishes to the requested
channel (default `test`) as before. With it on, only to `test.{user}`.
- README: the switch and the rollout order (ship clients that fall back on
404, switch on with the socket server in log mode, then enforce).
RunDatabaseBackup::dispatch() comes from the Dispatchable trait. Several test files define an empty Illuminate\Foundation\Bus\Dispatchable shim, so when one of them loads first the static dispatch() is missing and DatabaseBackupsTest fails depending on test order (PHP CI on release/v1.6.69 fails this way). Dispatching through the bus contract behaves the same at runtime and does not depend on the trait.
fix(backups): queue the manual backup through the bus dispatcher
…er handshake The PHP publisher connected without an Origin header, which socketcluster-server treats as '*'. With origins restricted (scripts/docker-install.sh restricts them to the console host), every server broadcast was refused with 'Invalid origin: *'. SOCKETCLUSTER_ORIGIN now sets the header through phrity/websocket's headers option. Reported in #290.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #294 +/- ##
============================================
Coverage 100.00% 100.00%
- Complexity 7931 8269 +338
============================================
Files 438 453 +15
Lines 25665 26441 +776
============================================
+ Hits 25665 26441 +776
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
feat(socket-auth): authenticated realtime channels (tokens, authorizer, signed publish)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v1.6.69
Release branch for core-api v1.6.69. Merging into
maintriggersrelease.yml, which validates thatcomposer.jsonand the first line ofRELEASE.mdname1.6.69, then pushes thev1.6.69tag.This branch collects:
fleetbase/core-api ^1.6.69.files.subject_uuidindex. Adds a migration.Before merging
database_backups(feat(backups): settings-driven database backups that fail loudly #288) and thefiles.subject_uuidindex (perf: cache the country lookup and index files.subject_uuid #291).SOCKETCLUSTER_AUTH_ENABLED(defaultfalse),SOCKETCLUSTER_AUTH_KEY,SOCKETCLUSTER_PUBLISH_URL,SOCKETCLUSTER_TOKEN_TTL. Socket auth stays off untilSOCKETCLUSTER_AUTH_ENABLED=true, even with a key set, so existing socket clients keep working.