How AionUi Plugin Credential Encryption Works Using Base64 in credentialCrypto.ts

AionUi uses Base64 encoding with format prefixes in credentialCrypto.ts to obfuscate plugin credentials like OAuth tokens and API keys before persisting them to SQLite, while maintaining backward compatibility with legacy storage formats.

The AionUi desktop application manages sensitive plugin configurations—such as Telegram bot tokens or OAuth credentials—through a lightweight encryption layer implemented in src/channels/utils/credentialCrypto.ts. Rather than storing secrets in plain text within the local SQLite database, the module applies Base64 transformation with identifiable prefixes to deter casual inspection and support migration from older encryption schemes.

Core Encryption Functions in credentialCrypto.ts

The credentialCrypto.ts module exposes two primary string-level functions that handle the encoding and decoding of individual credential values.

String-Level Encoding with encryptString

The encryptString(plaintext) function converts sensitive strings into obfuscated form using the following algorithm as implemented in lines 26-33:

  1. Validates that the input is a non-empty string
  2. Converts the string to UTF-8 bytes
  3. Applies Base64 encoding
  4. Prefixes the result with b64: to identify the transformation format

If the conversion throws an exception (for example, due to unexpected binary input), the function falls back to prefixing the original value with plain: to ensure the credential is never lost during the encryption attempt.

String-Level Decoding with decryptString

The decryptString(encoded) function reverses the obfuscation process and handles multiple legacy formats as defined in lines 44-77:

  • plain: prefix → Returns the substring unchanged (lines 48-50)
  • b64: prefix → Strips the prefix and decodes the Base64 payload back to UTF-8 (lines 52-60)
  • enc: prefix → Legacy format from an older safe-storage mechanism; accepted for backward compatibility (lines 62-70)
  • No recognized prefix → Returns the value as-is, preserving data that pre-dated the encoding feature (lines 74-77)

Object-Level Credential Handling

For practical use with plugin configurations, the module provides object-level wrappers that target specific sensitive fields.

Encrypting Plugin Credential Objects

The encryptCredentials(credentials) function creates a shallow copy of the supplied object and applies encryptString only to the token field (lines 84-90). This selective approach ensures that only the sensitive authentication secret is obfuscated while leaving other configuration parameters (such as API endpoints or usernames) in readable form for debugging purposes.

Decrypting Stored Credentials

Conversely, decryptCredentials(credentials) mirrors the encryption step by applying decryptString to the token field of the stored object (lines 96-101). This restores the original plain-text credential for runtime use by plugin implementations such as TelegramPlugin.ts.

Database Integration and Storage Flow

The encryption layer integrates with the persistence tier in src/process/database/index.ts (lines 871-884). When a plugin configuration is saved, the system first passes the credentials object through encryptCredentials before serializing it to JSON and writing to the SQLite plugin_config table. On retrieval, the database layer invokes decryptCredentials to restore the sensitive values before passing the configuration to the plugin constructor.

This architecture ensures that the SQLite database file contains only obfuscated tokens (prefixed with b64:) rather than plain-text secrets, mitigating the risk of credential exposure through casual file inspection or accidental version control commits.

Code Examples

String-Level Encryption and Decryption

import {
  encryptString,
  decryptString,
} from '@/channels/utils/credentialCrypto';

const rawToken = 'my-secret-token-123';

// Encode: produces "b64:bXktc2VjcmV0LXRva2VuLTEyMw=="
const encoded = encryptString(rawToken);
console.log(encoded);

// Decode: restores "my-secret-token-123"
const decoded = decryptString(encoded);
console.log(decoded);

Object-Level Credential Handling

import {
  encryptCredentials,
  decryptCredentials,
} from '@/channels/utils/credentialCrypto';

const credObj = { token: 'my-secret-token-123', apiUrl: 'https://api.example.com' };

// Encrypt only the token field
const stored = encryptCredentials(credObj);
// stored.token === "b64:bXktc2VjcmV0LXRva2VuLTEyMw=="
// stored.apiUrl remains "https://api.example.com"

// Decrypt for runtime use
const restored = decryptCredentials(stored);
// restored.token === "my-secret-token-123"

Database Persistence Flow

import { encryptCredentials, decryptCredentials } from '@/channels/utils/credentialCrypto';
import db from '@/process/database';

// Saving plugin configuration
async function savePluginConfig(pluginType: string, token: string) {
  const encrypted = encryptCredentials({ token });
  await db.run(
    `INSERT INTO plugin_config (type, credentials) VALUES (?, ?)`,
    [pluginType, JSON.stringify(encrypted)]
  );
}

// Loading plugin configuration
async function loadPluginConfig(pluginType: string) {
  const row = await db.get(
    `SELECT credentials FROM plugin_config WHERE type = ?`,
    [pluginType]
  );
  const stored = JSON.parse(row.credentials);
  return decryptCredentials(stored);
}

Summary

  • AionUi stores plugin credentials in SQLite using lightweight Base64 obfuscation rather than plain text.
  • The credentialCrypto.ts module provides encryptString and decryptString functions that prefix encoded values with b64: for identification.
  • Object-level helpers encryptCredentials and decryptCredentials target only the token field, leaving other configuration parameters readable.
  • The system maintains backward compatibility with legacy formats (enc:, plain:, and unprefixed values) to prevent data loss during upgrades.
  • Integration occurs in src/process/database/index.ts, ensuring credentials are obfuscated before persistence and restored before runtime use.

Frequently Asked Questions

Is AionUi's Base64 credential encryption secure?

No, the Base64 encoding used in credentialCrypto.ts is obfuscation, not encryption. It is designed to deter casual inspection of the SQLite database file rather than protect against determined attackers. The implementation explicitly avoids cryptographic algorithms in favor of simple Base64 transformation with format prefixes, making it unsuitable for high-security environments requiring true encryption.

What happens if decryptString encounters an unknown format?

The decryptString function handles unrecognized prefixes gracefully by returning the value unchanged. According to lines 74-77 of credentialCrypto.ts, if the encoded string lacks a recognized prefix (b64:, plain:, or enc:), the function returns the raw string as-is. This ensures that legacy credentials or manually inserted values never cause runtime failures during the decryption process.

Which fields are encrypted in plugin credentials?

The encryptCredentials function encrypts only the token field of the credentials object. As implemented in lines 84-90 of credentialCrypto.ts, the function creates a shallow copy of the input object and applies encryptString exclusively to the token property. Other fields such as apiUrl, username, or custom configuration parameters remain in plain text to facilitate debugging and manual database inspection.

Where does AionUi store encrypted credentials?

AionUi persists encrypted credentials in a local SQLite database managed by the database layer in src/process/database/index.ts. When saving plugin configurations, the system serializes the encrypted credentials object to JSON and stores it in the plugin_config table. The encryption occurs immediately before the database write operation (lines 871-884), ensuring that the SQLite file contains only obfuscated b64: prefixed tokens rather than sensitive plain-text secrets.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →