Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- **Extension manifest `id` is checked before it becomes a folder** — a sideloaded `.qext` with `"id": "../some/dir"` made the installer recursively delete and overwrite a folder outside the extensions directory. The id must now be letters, digits, `.`, `_` or `-` (starting with a letter or digit, no `..`), and every install / uninstall refuses a folder that is not inside the extensions directory (#1560).

- **macOS: saved passwords use the login keychain** — the secure storage plugin defaults to the data protection keychain, which needs an entitlement no Querya build has, so saving or reading a connection password failed with "Could not read the saved credentials from the system keyring". macOS may ask once to allow Querya Desktop to use its keychain items, and again after an update of an unsigned build (#1586).
=======
- **Zip limits hold even when an archive lies about its sizes** — the per-entry, total and ratio limits for extension installs, sideloads and updates are checked against the sizes the zip headers declare; the app now requires `archive` 4.5+, which refuses to decode an entry past its declared size, and reports that as an error instead of inflating it (#1561).

- **`querya-ext-tester` sends a `--connect` password with `system.injectCredentials`, like the app** — a driver that reads its password only from the injected secret (the ClickHouse driver) failed authentication under the tester because the password was in the `db.connect` payload only.
- **Demo Marketplace themes were named `${manifest.name}`** — the generated theme.json now carries the real name (the demo catalog is only used with `--dart-define=QUERYA_MARKETPLACE_MOCK=true`).
- **In-app update of a package install (AUR, `.deb`, `.rpm`)** — the updater no longer downloads a zip and quits when the app lives in `/opt/querya-desktop` (owned by root): the update dialog says how to update it (`yay -Syu querya-desktop`, `apt`, `dnf`) with a *Copy update command* button, or offers the release page for any other folder the user cannot write. If an in-place replace fails anyway, the app is started again and the reason is logged to `~/.local/state/querya-update.log`, instead of staying closed.
Expand Down
15 changes: 13 additions & 2 deletions lib/core/storage/connection_secrets_store.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

/// Backend for reading/writing per-connection secrets (password, connection string).
Expand All @@ -9,8 +10,9 @@ abstract class SecretsStorageBackend {
}

class _FlutterSecureStorageBackend implements SecretsStorageBackend {
/// Desktop targets use the default platform options from the plugin.
final FlutterSecureStorage _storage = const FlutterSecureStorage();
final FlutterSecureStorage _storage = const FlutterSecureStorage(
mOptions: ConnectionSecretsStore.macOsOptions,
);

@override
Future<String?> read(String key) => _storage.read(key: key);
Expand Down Expand Up @@ -60,6 +62,15 @@ class ConnectionSecretsStore {
/// Production uses OS-backed storage; tests override [backend] (see `test/flutter_test_config.dart`).
static SecretsStorageBackend backend = _FlutterSecureStorageBackend();

/// macOS: the file-based login keychain. The plugin's default, the data
/// protection keychain, needs the `keychain-access-groups` entitlement,
/// which none of the builds carry (a restricted entitlement: a Developer ID
/// build with it needs a provisioning profile or does not launch), so every
/// read and write failed with errSecMissingEntitlement (#1586).
@visibleForTesting
static const MacOsOptions macOsOptions =
MacOsOptions(usesDataProtectionKeychain: false);

/// Identifies the current profile's local database (installed / portable /
/// migrated-legacy — see `AppDataRoot`), so that two independent profile
/// databases never collide in the shared OS keyring even when they each
Expand Down
14 changes: 14 additions & 0 deletions test/core/storage/connection_secrets_store_macos_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/core/storage/connection_secrets_store.dart';

void main() {
test('macOS secrets go to the login keychain, not the data protection one '
'(#1586)', () {
// What the native plugin reads: "true" (its default) needs the
// keychain-access-groups entitlement, which the app does not have.
expect(
ConnectionSecretsStore.macOsOptions.toMap()['usesDataProtectionKeychain'],
'false',
);
});
}
Loading