secure_qr_generator 1.1.0
secure_qr_generator: ^1.1.0 copied to clipboard
A Flutter package for generating secure, auto-regenerating QR codes with encryption, digital signatures, and automatic expiration management.
Secure QR Generator #
A Flutter package for generating secure, auto-regenerating QR codes with encryption, digital signatures, and automatic expiration management.
Features #
- 🔒 Secure by Design: Support for AES encryption and HMAC-SHA256 signatures
- ⏱️ Auto-Expiration: Built-in validity duration management
- 🔄 Auto-Regeneration: Automatic QR code refresh before expiration
- 📦 Compact Payload Format: Optional CBOR + Base45 encoding for smaller, faster-to-scan QR codes
- 📱 Flutter Integration: Ready-to-use Flutter widget
- 🎨 Customizable Styling: Full control over QR code appearance
- ⚡ Performance Optimized: Efficient regeneration with minimal overhead
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
secure_qr_generator: ^1.1.0
Then run:
flutter pub get
Quick Start #
Basic Usage #
import 'package:secure_qr_generator/secure_qr_generator.dart';
// Create a configuration
final config = GeneratorConfig.production(
secretKey: 'your-32-character-secret-key-here!!!',
validityDuration: Duration(minutes: 5),
);
// Initialize the generator
final generator = SecureQRGenerator(config);
// Create QR data
final data = QRData(
payload: {'userId': '123', 'access': 'granted'},
metadata: {'purpose': 'access_control'},
tags: ['entrance', 'visitor'],
);
// Generate a QR code
final result = await generator.generateQR(data);
Using the Auto-Regenerating Widget #
AutoRegeneratingQRView(
data: data,
generator: generator,
size: 200,
style: QrStyle(
eyeStyle: QrEyeStyle(eyeShape: QrEyeShape.square),
dataModuleStyle: QrDataModuleStyle(
dataModuleShape: QrDataModuleShape.circle,
),
),
onRegenerate: (result) {
print('New QR generated: ${result.id}');
},
onError: (error) {
print('Error: $error');
},
)
Payload Format: Legacy vs. Compact #
Since version 1.1.0, the generator can emit two different QR payload formats, selected via GeneratorConfig.payloadFormat:
QrPayloadFormat.legacy (default) |
QrPayloadFormat.compact |
|
|---|---|---|
| Serialization | JSON | CBOR |
| Encoding | Base64 | Base45 |
| Signature placement | Embedded in JSON before encryption | Appended as raw bytes, computed over the encrypted body (encrypt-then-MAC) |
| Typical QR density | Baseline | ~35–40% smaller for equivalent data |
| Understood by | All versions of secure_qr_validator |
secure_qr_validator 1.2.0+ only |
final config = GeneratorConfig(
secretKey: 'your-32-character-secret-key-here!!!',
enableEncryption: true,
enableSignature: true,
payloadFormat: QrPayloadFormat.compact, // opt in to the smaller format
);
Why this matters for scanning speed: Base45 lets the QR encoder use its alphanumeric mode (5.5 bits/character) instead of byte mode (8 bits/character), which Base64 content forces due to its lowercase letters and +///= characters. Combined with CBOR's more compact serialization, this typically produces a QR code with meaningfully fewer modules for the same data — easier and faster for a camera to read.
Staged rollout (recommended for peer-to-peer scanning) #
If your QR codes are scanned by other instances of your own app (rather than only by servers/terminals you control), don't hardcode payloadFormat: compact directly. Instead:
- Ship
secure_qr_validator1.2.0+ everywhere first — it transparently understands both formats, so this step is invisible to users. - Once adoption of that validator version is effectively complete across your user base, drive
payloadFormatfrom a remotely-controlled flag (feature flag / remote config) rather than a code constant, so you can flip it gradually and roll back instantly if needed. - Only after the rollout is complete and confirmed via telemetry should you consider removing the
legacycode path entirely.
Configuration Options #
Development Configuration #
final devConfig = GeneratorConfig.development();
// Uses QrPayloadFormat.compact by default — fine for development,
// since there's no store rollout to coordinate.
Production Configuration #
final prodConfig = GeneratorConfig.production(
secretKey: 'your-secure-production-key-here!!!!!!',
validityDuration: Duration(minutes: 5),
payloadFormat: QrPayloadFormat.legacy, // default — override once ready
);
Custom Configuration #
final customConfig = GeneratorConfig(
secretKey: 'your-secret-key',
validityDuration: Duration(minutes: 10),
enableEncryption: true,
enableSignature: true,
dataVersion: 1,
idPrefix: 'CUSTOM_',
payloadFormat: QrPayloadFormat.legacy,
);
Advanced Features #
Custom QR Code Styling #
QrStyle(
eyeStyle: QrEyeStyle(
eyeShape: QrEyeShape.square,
color: Colors.blue,
),
dataModuleStyle: QrDataModuleStyle(
dataModuleShape: QrDataModuleShape.circle,
color: Colors.black,
),
embeddedImage: AssetImage('assets/logo.png'),
embeddedImageStyle: QrEmbeddedImageStyle(
size: Size(40, 40),
),
)
Custom Regeneration Interval #
AutoRegeneratingQRView(
data: data,
generator: generator,
regenerationInterval: Duration(minutes: 2),
// ... other parameters
)
Custom QR Code Builder #
AutoRegeneratingQRView(
data: data,
generator: generator,
builder: (qrData) => Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
),
child: QrImageView(
data: qrData,
size: 200,
),
),
)
Error Handling #
The package includes comprehensive error handling:
try {
final result = await generator.generateQR(data);
// Use the result
} on GenerationError catch (e) {
switch (e.type) {
case GenerationErrorType.configuration:
print('Configuration error: ${e.message}');
break;
case GenerationErrorType.encryption:
print('Encryption error: ${e.message}');
break;
case GenerationErrorType.payloadTooLarge:
print('Payload too large: ${e.message}');
break;
// Handle other error types...
}
}
canEncodeData and estimateQRSize both take the currently configured payloadFormat into account, so checking data size ahead of generation reflects whichever format you have selected.
Security Considerations #
- Keep your
secretKeysecure and never commit it to version control - Use different keys for development and production environments
- Consider the QR code size limits when adding data
- Choose an appropriate validity duration for your use case
- Regularly rotate encryption keys in production
- When switching
payloadFormattocompactin a peer-to-peer scanning context, sequence the rollout so every reader supports the new format before any writer starts emitting it (see Staged rollout above)
Contributing #
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
License #
This project is licensed under the MIT License - see the LICENSE file for details.