smart_dev_pinning_plugin 2.5.0
smart_dev_pinning_plugin: ^2.5.0 copied to clipboard
This plugin creates a secure native TLS connection to execute HTTP requests with certificate pinning.
example/lib/main.dart
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:smart_dev_pinning_plugin/smart_dev_pinning_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String response = "";
String benchmarkResults = "";
bool isBenchmarkRunning = false;
bool isRequestRunning = false;
// Benchmark data for visualization
double? avgStandard;
double? avgSecure;
int? minStandard;
int? maxStandard;
int? minSecure;
int? maxSecure;
double? stdDevStandard;
double? stdDevSecure;
double? performanceImpact;
String? performanceVerdict;
String? verdictEmoji;
String? performanceAnalysis;
@override
void initState() {
super.initState();
}
/// Makes an HTTP request using Dart's native HTTP client
Future<String> makeStandardHttpRequest() async {
final httpClient = HttpClient();
try {
final request = await httpClient.getUrl(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
);
request.headers.set('Content-type', 'application/json; charset=UTF-8');
final response = await request.close();
final responseBody = await response.transform(utf8.decoder).join();
return responseBody;
} finally {
httpClient.close();
}
}
/// Makes an HTTP request using the secure client with SSL Pinning
Future<String> makeSecureHttpRequest() async {
final client = SecureClient();
return await client.httpRequest(
certificateHash: "wU4etiecTiVY14FrC0sdWSSb3PjlifzvqMMqU87T0CU=",
method: 'GET',
url: 'https://jsonplaceholder.typicode.com/posts/1',
headers: {'Content-type': 'application/json; charset=UTF-8'},
pinningMethod: PinningMethod.certificate,
);
}
/// Executes benchmark comparing both clients
Future<void> runBenchmark() async {
setState(() {
isBenchmarkRunning = true;
benchmarkResults = "Running benchmark tests...";
// Reset previous data
avgStandard = null;
avgSecure = null;
});
const int iterations = 15;
final List<Duration> standardTimes = [];
final List<Duration> secureTimes = [];
try {
// Benchmark standard client
for (int i = 0; i < iterations; i++) {
final stopwatch = Stopwatch()..start();
await makeStandardHttpRequest();
stopwatch.stop();
standardTimes.add(stopwatch.elapsed);
setState(() {
benchmarkResults =
"Testing Standard HTTP Client: ${i + 1}/$iterations";
});
await Future.delayed(const Duration(milliseconds: 50));
}
// Benchmark secure client
for (int i = 0; i < iterations; i++) {
final stopwatch = Stopwatch()..start();
try {
await makeSecureHttpRequest();
} catch (e) {
// Continue even with pinning errors
}
stopwatch.stop();
secureTimes.add(stopwatch.elapsed);
setState(() {
benchmarkResults =
"Testing Secure SSL Pinning Client: ${i + 1}/$iterations";
});
await Future.delayed(const Duration(milliseconds: 50));
}
// Calculate comprehensive statistics
final avgStandardCalc =
standardTimes.map((d) => d.inMilliseconds).reduce((a, b) => a + b) /
iterations;
final avgSecureCalc =
secureTimes.map((d) => d.inMilliseconds).reduce((a, b) => a + b) /
iterations;
final minStandardCalc = standardTimes
.map((d) => d.inMilliseconds)
.reduce((a, b) => a < b ? a : b);
final maxStandardCalc = standardTimes
.map((d) => d.inMilliseconds)
.reduce((a, b) => a > b ? a : b);
final minSecureCalc = secureTimes
.map((d) => d.inMilliseconds)
.reduce((a, b) => a < b ? a : b);
final maxSecureCalc = secureTimes
.map((d) => d.inMilliseconds)
.reduce((a, b) => a > b ? a : b);
// Calculate standard deviation
final stdDevStandardCalc = _calculateStandardDeviation(
standardTimes,
avgStandardCalc,
);
final stdDevSecureCalc = _calculateStandardDeviation(
secureTimes,
avgSecureCalc,
);
final performanceImpactCalc =
((avgSecureCalc - avgStandardCalc) / avgStandardCalc * 100);
String performanceVerdictCalc;
String verdictEmojiCalc;
String performanceAnalysisCalc;
if (performanceImpactCalc < -10) {
performanceVerdictCalc =
"Outstanding - Secure client is significantly faster!";
verdictEmojiCalc = "🚀";
performanceAnalysisCalc =
"The secure client outperforms standard HTTP by ${(-performanceImpactCalc).toStringAsFixed(1)}%. This could be due to connection reuse, optimized TLS handshakes, or efficient certificate validation caching.";
} else if (performanceImpactCalc < 0) {
performanceVerdictCalc =
"Excellent - Secure client is faster than standard!";
verdictEmojiCalc = "⚡";
performanceAnalysisCalc =
"Surprisingly, the secure client is ${(-performanceImpactCalc).toStringAsFixed(1)}% faster. SSL pinning optimizations and connection pooling may be contributing to better performance.";
} else if (performanceImpactCalc < 5) {
performanceVerdictCalc = "Excellent - Minimal performance impact";
verdictEmojiCalc = "🟢";
performanceAnalysisCalc =
"SSL Certificate Pinning adds only ${performanceImpactCalc.toStringAsFixed(1)}% overhead while providing critical security benefits. This is within acceptable performance bounds.";
} else if (performanceImpactCalc < 15) {
performanceVerdictCalc = "Good - Acceptable performance impact";
verdictEmojiCalc = "🟡";
performanceAnalysisCalc =
"The ${performanceImpactCalc.toStringAsFixed(1)}% performance impact is reasonable considering the enhanced security provided by certificate pinning.";
} else if (performanceImpactCalc < 30) {
performanceVerdictCalc = "Fair - Moderate performance impact";
verdictEmojiCalc = "🟠";
performanceAnalysisCalc =
"There's a ${performanceImpactCalc.toStringAsFixed(1)}% performance overhead. Consider optimizing certificate validation or implementing connection pooling.";
} else {
performanceVerdictCalc = "Poor - Significant performance impact";
verdictEmojiCalc = "🔴";
performanceAnalysisCalc =
"The ${performanceImpactCalc.toStringAsFixed(1)}% performance impact is concerning. Review implementation for potential optimizations.";
}
// Store data for visualization and update state
setState(() {
avgStandard = avgStandardCalc;
avgSecure = avgSecureCalc;
minStandard = minStandardCalc;
maxStandard = maxStandardCalc;
minSecure = minSecureCalc;
maxSecure = maxSecureCalc;
stdDevStandard = stdDevStandardCalc;
stdDevSecure = stdDevSecureCalc;
performanceImpact = performanceImpactCalc;
performanceVerdict = performanceVerdictCalc;
verdictEmoji = verdictEmojiCalc;
performanceAnalysis = performanceAnalysisCalc;
benchmarkResults =
"Benchmark completed successfully with $iterations iterations";
});
} catch (e) {
setState(() {
benchmarkResults = "❌ Benchmark Error: $e";
});
} finally {
setState(() {
isBenchmarkRunning = false;
});
}
}
double _calculateStandardDeviation(List<Duration> times, double mean) {
final sumSquaredDiffs = times
.map((time) => time.inMilliseconds - mean)
.map((diff) => diff * diff)
.reduce((a, b) => a + b);
return sqrt(sumSquaredDiffs / times.length);
}
Widget _buildBenchmarkVisualization() {
if (avgStandard == null || avgSecure == null) {
return Container(
padding: const EdgeInsets.all(20),
child: Text(
benchmarkResults,
style: const TextStyle(fontSize: 14, fontFamily: 'monospace'),
),
);
}
final isSecureFaster = performanceImpact! < 0;
final absoluteDiff = (avgSecure! - avgStandard!).abs();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Performance Comparison Chart
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.primaryContainer.withOpacity(0.3),
Theme.of(
context,
).colorScheme.secondaryContainer.withOpacity(0.3),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
),
),
child: Column(
children: [
// Title
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
verdictEmoji ?? '',
style: const TextStyle(fontSize: 24),
),
const SizedBox(width: 8),
Expanded(
child: Text(
performanceVerdict ?? 'Performance Analysis',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color:
isSecureFaster
? Colors.green[700]
: (performanceImpact! < 15
? Colors.orange[700]
: Colors.red[700]),
),
textAlign: TextAlign.center,
),
),
],
),
const SizedBox(height: 20),
// Performance Bars
Row(
children: [
Expanded(
child: _buildPerformanceBar(
'Standard HTTP',
avgStandard!,
avgStandard! > avgSecure! ? avgStandard! : avgSecure!,
Colors.blue[400]!,
Icons.http,
),
),
const SizedBox(width: 16),
Expanded(
child: _buildPerformanceBar(
'Secure SSL Pinning',
avgSecure!,
avgStandard! > avgSecure! ? avgStandard! : avgSecure!,
isSecureFaster ? Colors.green[400]! : Colors.orange[400]!,
Icons.security,
),
),
],
),
const SizedBox(height: 20),
// Performance Impact Summary
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color:
isSecureFaster
? Colors.green[50]
: (performanceImpact! < 15
? Colors.orange[50]
: Colors.red[50]),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color:
isSecureFaster
? Colors.green[200]!
: (performanceImpact! < 15
? Colors.orange[200]!
: Colors.red[200]!),
),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildMetric(
'Impact',
'${performanceImpact! >= 0 ? '+' : ''}${performanceImpact!.toStringAsFixed(1)}%',
isSecureFaster
? Colors.green[700]!
: (performanceImpact! < 15
? Colors.orange[700]!
: Colors.red[700]!),
),
_buildMetric(
'Difference',
'${performanceImpact! >= 0 ? '+' : '-'}${absoluteDiff.toStringAsFixed(1)}ms',
Colors.grey[700]!,
),
_buildMetric(
'Std Dev',
'${((stdDevStandard! + stdDevSecure!) / 2).toStringAsFixed(1)}ms',
Colors.grey[700]!,
),
],
),
],
),
),
],
),
),
const SizedBox(height: 16),
// Detailed Statistics
Row(
children: [
Expanded(
child: _buildStatCard(
'Standard HTTP Client',
avgStandard!,
minStandard!,
maxStandard!,
stdDevStandard!,
Colors.blue,
Icons.public,
),
),
const SizedBox(width: 12),
Expanded(
child: _buildStatCard(
'SSL Pinning Client',
avgSecure!,
minSecure!,
maxSecure!,
stdDevSecure!,
isSecureFaster ? Colors.green : Colors.orange,
Icons.verified_user,
),
),
],
),
const SizedBox(height: 16),
// Analysis Text
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[200]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.lightbulb_outline,
color: Colors.amber[700],
size: 20,
),
const SizedBox(width: 8),
Text(
'Analysis & Insights',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
Text(
performanceAnalysis ?? 'Performance analysis not available.',
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(height: 1.4),
),
],
),
),
],
);
}
Widget _buildPerformanceBar(
String title,
double value,
double maxValue,
Color color,
IconData icon,
) {
final percentage = (value / maxValue).clamp(0.0, 1.0);
return Column(
children: [
Row(
children: [
Icon(icon, size: 16, color: color),
const SizedBox(width: 4),
Expanded(
child: Text(
title,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(6),
),
child: FractionallySizedBox(
widthFactor: percentage,
alignment: Alignment.centerLeft,
child: Container(
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
child: Center(
child: Text(
'${value.toStringAsFixed(1)}ms',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
);
}
Widget _buildMetric(String label, String value, Color color) {
return Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: color,
),
),
Text(label, style: TextStyle(fontSize: 12, color: Colors.grey[600])),
],
);
}
Widget _buildStatCard(
String title,
double avg,
int min,
int max,
double stdDev,
MaterialColor color,
IconData icon,
) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: color[200]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, size: 16, color: color[700]),
const SizedBox(width: 6),
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: color[700],
),
),
),
],
),
const SizedBox(height: 8),
_buildStatRow('Avg', '${avg.toStringAsFixed(1)}ms'),
_buildStatRow('Min', '${min}ms'),
_buildStatRow('Max', '${max}ms'),
_buildStatRow('Std', '${stdDev.toStringAsFixed(1)}ms'),
],
),
);
}
Widget _buildStatRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontSize: 11, color: Colors.grey)),
Text(
value,
style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SSL Pinning Benchmark',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF2196F3),
brightness: Brightness.light,
),
cardTheme: const CardThemeData(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
),
),
home: Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
title: const Text(
'SSL Pinning Performance Benchmark',
style: TextStyle(fontWeight: FontWeight.w600),
),
centerTitle: true,
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Colors.white,
elevation: 0,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header Card
Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Icon(
Icons.security,
size: 48,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 12),
Text(
'Smart Dev SSL Pinning Plugin',
style: Theme.of(context).textTheme.headlineSmall
?.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
'Test and benchmark SSL certificate pinning performance',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey[600],
),
textAlign: TextAlign.center,
),
],
),
),
),
const SizedBox(height: 24),
// Action Buttons
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed:
isRequestRunning
? null
: () async {
setState(() {
isRequestRunning = true;
response = "";
});
try {
final result = await makeSecureHttpRequest();
setState(() {
response = result;
});
} catch (e) {
setState(() {
response = "Error: $e";
});
} finally {
setState(() {
isRequestRunning = false;
});
}
},
icon:
isRequestRunning
? SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.onPrimary,
),
),
)
: const Icon(Icons.lock),
label: Text(
isRequestRunning
? 'Connecting...'
: 'Test Secure Request',
),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton.icon(
onPressed: isBenchmarkRunning ? null : runBenchmark,
icon:
isBenchmarkRunning
? SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.onSecondary,
),
),
)
: const Icon(Icons.speed),
label: Text(
isBenchmarkRunning ? 'Running...' : 'Run Benchmark',
),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor:
Theme.of(context).colorScheme.secondary,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
],
),
const SizedBox(height: 24),
// Results Section
if (response.isNotEmpty) ...[
Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.http,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(width: 8),
Text(
'Secure Request Response',
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
],
),
const SizedBox(height: 16),
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[300]!),
),
child: Text(
response,
style: const TextStyle(
fontSize: 13,
fontFamily: 'monospace',
height: 1.4,
),
),
),
],
),
),
),
const SizedBox(height: 16),
],
// Benchmark Results
if (benchmarkResults.isNotEmpty) ...[
Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.analytics,
color: Theme.of(context).colorScheme.secondary,
),
const SizedBox(width: 8),
Text(
'Performance Benchmark Results',
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
],
),
const SizedBox(height: 20),
_buildBenchmarkVisualization(),
],
),
),
),
],
const SizedBox(height: 24),
// Information Card
Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.info_outline,
color: Theme.of(context).colorScheme.tertiary,
),
const SizedBox(width: 8),
Text(
'About SSL Pinning',
style: Theme.of(context).textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.w600),
),
],
),
const SizedBox(height: 12),
Text(
'SSL Certificate Pinning provides enhanced security by validating server certificates against pre-defined values, preventing man-in-the-middle attacks. The benchmark compares performance between standard HTTPS requests and pinned certificate validation.',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey[700],
height: 1.5,
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue[200]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🤔 Why might the secure client be faster?',
style: Theme.of(
context,
).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.blue[800],
),
),
const SizedBox(height: 8),
Text(
'• Connection reuse and pooling optimizations\n'
'• Cached certificate validation results\n'
'• Optimized TLS handshake implementations\n'
'• Native code performance benefits\n'
'• Reduced overhead in HTTP client implementation',
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(
color: Colors.blue[700],
height: 1.4,
),
),
],
),
),
],
),
),
),
],
),
),
),
);
}
}