xdg_secret_portal_store 0.1.1 copy "xdg_secret_portal_store: ^0.1.1" to clipboard
xdg_secret_portal_store: ^0.1.1 copied to clipboard

A helper library for storing application secrets in an encrypted file using the master secret provided by the XDG Desktop Portal Secret API.

A helper library for storing application secrets in an encrypted file using the master secret provided by the XDG Desktop Portal Secret API. Designed to complement package:xdg_desktop_portal.

To add the dependencies:

dart pub add xdg_secret_portal_store xdg_desktop_portal

Usage #

import 'package:xdg_desktop_portal/xdg_desktop_portal.dart';
import 'package:xdg_secret_portal_store/xdg_secret_portal_store.dart';

final portalClient = XdgDesktopPortalClient();

final store = XdgSecretPortalStore(
  secretRetriever: portalClient.secret.retrieveSecret,
  persistence: SecretStorePersistenceFile(
    // Read the "File Path" section for details.
    File('/path/to/application/data/secrets.json'),
  ),
);

await store.loadMasterSecret();

final Map<String, String> secrets = await store.read();

secrets['password'] = '123';
await store.write(secrets);

// Closes the client when no longer needed.
await portalClient.close();

Tip

This package is intended to be a helper library rather than a portal client.

The portal org.freedesktop.portal.Secret provides a master secret for a sandboxed application.

package:xdg_desktop_portal already implements the secret portal (XdgSecretPortal).

Unlike org.freedesktop.secrets, the Secret Portal is not a secure storage API itself. This package provides a convenient encrypted secret store built on top of the portal-provided master secret.

Cryptography #

The Secret Portal specification states:

The master secret can be used for encrypting confidential data, but its format is opaque to the application. In particular, the length of the secret might not be sufficient for use with certain encryption algorithms. In that case, the application is supposed to expand it using a KDF algorithm.

The default implementation of this package:

  • derives a 32-byte encryption key using HKDF-SHA-256 with xdg_secret_portal_store as the HKDF info value.
  • uses XChaCha20-Poly1305 for authenticated encryption of the secret store.

The cryptographic operations are implemented using package:cryptography.

Additionally, SecretStoreCrypto can be implemented to provide a custom crypto implementation (which can be independent of package:cryptography):

class SecretStoreCryptoCustom implements SecretStoreCrypto {
  // ...
}

To override it:

final store = XdgSecretPortalStore(
  crypto: SecretStoreCryptoCustom(),
);

Storage format #

Secrets are stored as a UTF-8 encoded JSON file with the following structure:

{
  "version": 1,
  "kdf": "HKDF-SHA256",
  "cipher": "XChaCha20-Poly1305",
  "nonce": "...",
  "ciphertext": "...",
  "mac": "..."
}

Where:

  • version is the serialized storage format version.
  • kdf identifies the key derivation function used to derive the encryption key.
  • cipher is the authenticated encryption (AEAD) algorithm.
  • nonce is the Base64-encoded nonce.
  • ciphertext is the Base64-encoded encrypted UTF-8 JSON representation of the secret map (Map<String, String>).
  • mac is the Base64-encoded message authentication code.

File Path #

This package does not define a default file path. Applications should store the encrypted secret store in their own application data directory.

A typical XDG-compatible layout is:

$XDG_DATA_HOME/$APPLICATION_ID/xdg_secret_portal_store/secrets.json.

For example, path_provider can be used:

import 'dart:io';

import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

final filePath = p.join(
  await getApplicationSupportPath(),
  'xdg_secret_portal_store',
  'secrets.json',
);

final store = XdgSecretPortalStore(
  persistence: SecretStorePersistenceFile(File(filePath)),
);

Tip

To keep a package independent of Flutter, use xdg_directories, which is used by path_provider_linux.

To get the application ID on Linux, the package linux_application_id can be used.

See also: get_application_id_real.dart of path_provider_linux

Additionally, SecretStorePersistence can be implemented to provide a custom persistence implementation (which can be independent of dart:io's File):

class SecretStorePersistenceDatabase implements SecretStorePersistence {
  // ...
}

final store = XdgSecretPortalStore(
  persistence: SecretStorePersistenceDatabase(),
);

Not interoperable with GNOME libsecret #

This package cannot retrieve secrets stored by GNOME libsecret.

GNOME libsecret supports multiple storage backends. The two main ones are:

If available, secrets are stored in the freedesktop secret service. Otherwise, secrets are stored in a file that is encrypted using a master secret that was provided by the secret portal.

If GNOME libsecret is using the Secret Portal backend (see secret-backend.c#L156), it stores encrypted secrets in its own encrypted file format. According to this source, the data is stored in:

$XDG_DATA_HOME/keyrings/<default-collection>.keyring

If GNOME libsecret is using the Secret Service backend, this package is also not interoperable. However, package:freedesktop_secret is interoperable with GNOME libsecret when using that backend.

Disclaimer #

Support for this library is given as best effort.

This library has not been reviewed or vetted by security professionals.

See also #

Tip

Using direct access to the Secret Service API may result in Flathub app submission not being approved. New sandboxed applications should consider the XDG Desktop Portal Secret API when available.

2
likes
0
points
215
downloads

Publisher

verified publisherechoellet.dev

Weekly Downloads

A helper library for storing application secrets in an encrypted file using the master secret provided by the XDG Desktop Portal Secret API.

Repository (GitHub)
View/report issues

Topics

#os-integration #xdg-portal #secret-storage

License

unknown (license)

Dependencies

cryptography

More

Packages that depend on xdg_secret_portal_store