secure_env 1.0.1
secure_env: ^1.0.1 copied to clipboard
Encrypt values from `.secure_env` into Rust ciphertext at build time and read them at runtime via `dart:ffi` (AES-256-GCM). Keeps plaintext secrets out of Dart sources and JNI / Apple native binaries [...]
import 'package:flutter/material.dart';
import 'package:secure_env/secure_env.dart';
void main() => runApp(const SecureEnvDemoApp());
/// Sample host listing every outward-facing API from `SecureEnv`.
class SecureEnvDemoApp extends StatelessWidget {
const SecureEnvDemoApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'secure_env Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
useMaterial3: true,
),
home: const SecureEnvHomePage(),
);
}
}
class SecureEnvHomePage extends StatelessWidget {
const SecureEnvHomePage({super.key});
static String _formatException(Object error) =>
'${error.runtimeType}: $error';
@override
Widget build(BuildContext context) {
final available = SecureEnv.availableKeys();
final isReady = SecureEnv.isAvailable;
final abi = SecureEnv.nativeAbiVersion;
final nullableResult = SecureEnv.get('TEST_KEY');
Object? requirementResult = 'resolved';
Object? requirementError;
try {
requirementResult = SecureEnv.require('TEST_KEY');
} catch (error) {
requirementError = error;
}
final missingCatch = SecureEnv.get('DOES_NOT_EXIST');
Object requireMissingError = 'skipped';
try {
SecureEnv.require('DOES_NOT_EXIST');
} catch (error) {
requireMissingError = error;
}
final textTheme = Theme.of(context).textTheme;
Widget sectionTitle(String title) => Padding(
padding: const EdgeInsets.only(bottom: 8, top: 16),
child: Text(title, style: textTheme.titleMedium),
);
return Scaffold(
appBar: AppBar(title: const Text('secure_env example')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Text(
'Demonstrates SecureEnv.availableKeys/get/require/isAvailable/nativeAbiVersion.',
style: textTheme.bodyLarge,
),
const Divider(height: 32),
sectionTitle('Connectivity'),
SelectableText('isAvailable → $isReady'),
SelectableText('nativeAbiVersion → ${abi ?? 'null (FFI inactive)'}'),
sectionTitle('availableKeys()'),
SelectableText(available.join(', '), style: textTheme.titleSmall),
sectionTitle('get(\'TEST_KEY\') nullable read'),
SelectableText('$nullableResult'),
sectionTitle('require(\'TEST_KEY\') strong read'),
if (requirementError != null)
SelectableText(
'threw ${_formatException(requirementError)}',
style: TextStyle(color: Theme.of(context).colorScheme.error),
)
else
SelectableText('value → $requirementResult'),
sectionTitle('require missing key (`DOES_NOT_EXIST`)'),
SelectableText('$requireMissingError'),
SelectableText('get missing → ${missingCatch ?? 'null'}'),
const Divider(height: 32),
Text('Operational checklist', style: textTheme.titleMedium),
const SizedBox(height: 8),
SelectableText(
'1. Maintain `.secure_env` gitignored plaintext.\n'
'2. Run `dart run secure_env:generate` after edits.\n'
'3. Build native payloads (see the README section **Native artifacts**).\n'
'4. `SecureEnvDecryptionException` is reserved — tampering yields `null` from get today.',
style: textTheme.bodySmall,
),
],
),
);
}
}