Repository navigation
perf: load the admin client key lazily - #76
Merged
Merged
Conversation
Since Nextcloud 29 every request loads the non-lazy app config values of every app, and the lazy ones only once some code asks for one lazily. The app wrote its app config with IConfig::setAppValue(), which always stores a value non-lazy, so the admin's NUITEQ client key was loaded on every request, while only the app's own requests, its admin settings and its migrations read it. The client key is read and written through IAppConfig with lazy: true everywhere now: in NuiteqAPIService, the admin settings, the admin-config endpoint and the 1.0.8 migration that encrypted it. IConfig::getAppValue() reads only the non-lazy values, so no read of a lazy key may stay on the old API: it would answer the default, and the requests would go out with the shipped key instead of the admin's. base_url and override_link_click stay non-lazy. Application::boot() reads both on every request, for the script it adds to every page, and the CSP listener reads base_url for every page. Their other reads, and the admin-config endpoint's write of base_url, move to IAppConfig with the same flag. The admin-config endpoint stored whatever keys a request named. Through the typed setter that does harm: it sets the type of the row it writes, and Nextcloud's own rows of the app are untyped. Once installed_version is a string, the next upgrade fails on the type conflict and leaves the instance in maintenance mode, and once enabled is one, enabling the app fails the same way. The endpoint takes only what the admin settings send, base_url and client_key, and only as strings, and answers anything else with a 400 before it writes anything. override_link_click has no setting and is left to occ. A new migration marks client_key lazy on existing installs, where the old API stored it non-lazy; it does nothing on an install without a key, and until it runs the lazy reads still find the non-lazy row. The stored values do not change: the key stays encrypted with ICrypto, and every value stays a string. Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
oleksandr-nc
force-pushed
the
perf/lazy-app-config
branch
from
October 21, 2026 11:13
23cb3f4 to
7a553d5
Compare
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.
Since Nextcloud 29 every request loads the non-lazy app config values of every app, and NUITEQ's admin client key was one of them, although only the app's own requests and settings use it.
The admin client key was loaded on every request
The app read and wrote its app config through the deprecated
IConfig::getAppValue()andsetAppValue(), andsetAppValue()always stores a value non-lazy. So the admin's client key, encrypted withICrypto, was loaded on every request to the instance, while onlyNuiteqAPIService(the login and the board requests), the admin settings and the 1.0.8 migration that encrypted it read it.The client key is lazy, the Stage URL and the link override stay non-lazy
Every app config read and write goes through the typed
IAppConfigmethods now, with the same flag for a key everywhere:client_keyis lazy.NuiteqAPIService, the admin settings and the 1.0.8 migration read it, the admin-config endpoint and that migration write it, all withlazy: true. A non-lazy read of a lazy value answers the default, so no read of it is left on the old API: the requests would go out with the shipped key instead of the admin's.base_urlstays non-lazy.Application::boot()reads it on every request for the script it adds to every page, and the CSP listener reads it for every page.override_link_clickstays non-lazy.Application::boot()reads it on every request, for the same script.The stored values do not change: the key stays encrypted with
ICrypto, and every value stays a string.The admin endpoint takes only the two admin settings
setAdminConfig()stored whatever keys a request named. Through the typed setter that does harm: it sets the type of the row it writes, and Nextcloud's own rows of the app are untyped. Onceinstalled_versionis a string, the nextocc upgradefails on the type conflict and leaves the instance in maintenance mode, and onceenabledis one, enabling the app fails the same way. The endpoint takes only what the admin settings send,base_urlandclient_key, and only as strings, and answers anything else with a 400 before it writes anything.override_link_clickhas no setting and is left toocc.Existing installs mark the key lazy when they upgrade
A new migration,
Version1301Date202610211026, callsupdateLazy()forclient_key, which the old API stored non-lazy. It does nothing on an install without a key, and until it runs, the lazy reads still find the non-lazy row.🤖 AI (if applicable)