guard_kit 0.1.0 copy "guard_kit: ^0.1.0" to clipboard
guard_kit: ^0.1.0 copied to clipboard

Mobile security plugin: root/jailbreak detection, developer mode detection, emulator detection, SSL certificate pinning, and screenshot prevention.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:guard_kit/guard_kit.dart';

void main() => runApp(const GuardKitExampleApp());

class GuardKitExampleApp extends StatelessWidget {
  const GuardKitExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'guard_kit Example',
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
      ),
      // Wrap entire app in ScreenshotBlocker to protect all screens
      home: ScreenshotBlocker(
        guard: GuardKit.create(),
        child: const SecurityDashboard(),
      ),
    );
  }
}

// ── Security Dashboard ────────────────────────────────────────────────────────

class SecurityDashboard extends StatefulWidget {
  const SecurityDashboard({super.key});

  @override
  State<SecurityDashboard> createState() => _SecurityDashboardState();
}

class _SecurityDashboardState extends State<SecurityDashboard> {
  // DI: guard injected; can be replaced with a mock in widget tests
  late final GuardKit _guard;

  SecurityStatus? _status;
  bool _loading = true;
  String? _sslResult;
  bool _screenshotBlocking = true;

  @override
  void initState() {
    super.initState();
    _guard = GuardKit.create();
    _loadSecurityStatus();
  }

  Future<void> _loadSecurityStatus() async {
    setState(() => _loading = true);
    try {
      final status = await _guard.getSecurityStatus();
      if (mounted) setState(() { _status = status; _loading = false; });
    } catch (e) {
      if (mounted) setState(() => _loading = false);
    }
  }

  Future<void> _testSslPinning() async {
    setState(() => _sslResult = 'Testing…');
    try {
      // Example: use a real fingerprint in production
      final client = await _guard.createPinnedClient(
        const FingerprintPinningConfig(sha256Fingerprints: [
          // Replace with the actual SHA-256 fingerprint of your server's cert
          'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
        ]),
      );
      // This will fail with the placeholder fingerprint — expected behaviour
      await client.get(Uri.parse('https://example.com'));
      client.close();
      if (mounted) setState(() => _sslResult = 'Connection succeeded');
    } on GuardKitException catch (e) {
      if (mounted) setState(() => _sslResult = 'Guard error: ${e.message}');
    } catch (e) {
      // HandshakeException expected with wrong fingerprint
      if (mounted) setState(() => _sslResult = 'Pinning active (${e.runtimeType})');
    }
  }

  Future<void> _toggleScreenshotBlocking(bool value) async {
    await _guard.setScreenshotBlocking(enabled: value);
    if (mounted) setState(() => _screenshotBlocking = value);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('guard_kit'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _loadSecurityStatus,
            tooltip: 'Refresh',
          ),
        ],
      ),
      body: _loading
          ? const Center(child: CircularProgressIndicator())
          : ListView(
              padding: const EdgeInsets.all(16),
              children: [
                _RiskBanner(status: _status),
                const SizedBox(height: 16),
                const _SectionHeader('Device Checks'),
                _CheckCard(
                  label: 'Root / Jailbreak',
                  value: _status?.isRooted,
                  dangerWhenTrue: true,
                ),
                _CheckCard(
                  label: 'Developer Mode',
                  value: _status?.isDeveloperModeEnabled,
                  dangerWhenTrue: true,
                ),
                _CheckCard(
                  label: 'Emulator / Simulator',
                  value: _status?.isRunningOnEmulator,
                  dangerWhenTrue: true,
                ),
                const SizedBox(height: 16),
                const _SectionHeader('Screenshot Blocking'),
                SwitchListTile(
                  title: const Text('Block screenshots'),
                  subtitle: const Text('Uses FLAG_SECURE / UITextField layer trick'),
                  value: _screenshotBlocking,
                  onChanged: _toggleScreenshotBlocking,
                ),
                const SizedBox(height: 16),
                const _SectionHeader('SSL Pinning'),
                ListTile(
                  title: const Text('Test SSL pinning'),
                  subtitle: Text(_sslResult ?? 'Tap to test'),
                  trailing: FilledButton(
                    onPressed: _testSslPinning,
                    child: const Text('Test'),
                  ),
                ),
              ],
            ),
    );
  }
}

// ── Reusable UI Components ────────────────────────────────────────────────────

class _RiskBanner extends StatelessWidget {
  final SecurityStatus? status;
  const _RiskBanner({required this.status});

  @override
  Widget build(BuildContext context) {
    if (status == null) return const SizedBox.shrink();

    final (label, color) = switch (status!.riskLevel) {
      SecurityRiskLevel.none   => ('No threats detected', Colors.green),
      SecurityRiskLevel.low    => ('Low risk', Colors.orange),
      SecurityRiskLevel.medium => ('Medium risk', Colors.deepOrange),
      SecurityRiskLevel.high   => ('High risk — multiple threats', Colors.red),
    };

    return Card(
      color: color.withValues(alpha: 0.15),
      child: ListTile(
        leading: Icon(Icons.shield, color: color, size: 32),
        title: Text(
          label,
          style: TextStyle(color: color, fontWeight: FontWeight.bold),
        ),
        subtitle: Text('Risk level: ${status!.riskLevel.name.toUpperCase()}'),
      ),
    );
  }
}

class _SectionHeader extends StatelessWidget {
  final String title;
  const _SectionHeader(this.title);

  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 4),
        child: Text(
          title,
          style: Theme.of(context)
              .textTheme
              .titleSmall
              ?.copyWith(color: Theme.of(context).colorScheme.primary),
        ),
      );
}

class _CheckCard extends StatelessWidget {
  final String label;
  final bool? value;
  final bool dangerWhenTrue;

  const _CheckCard({
    required this.label,
    required this.value,
    this.dangerWhenTrue = false,
  });

  @override
  Widget build(BuildContext context) {
    final isDanger = dangerWhenTrue ? (value ?? false) : !(value ?? true);
    final color = value == null
        ? Colors.grey
        : isDanger
            ? Colors.red
            : Colors.green;
    final icon = value == null
        ? Icons.help_outline
        : isDanger
            ? Icons.warning_amber_rounded
            : Icons.check_circle_outline;
    final valueText = value == null ? '—' : (value! ? 'YES' : 'NO');

    return Card(
      child: ListTile(
        leading: Icon(icon, color: color),
        title: Text(label),
        trailing: Text(
          valueText,
          style: TextStyle(
            fontWeight: FontWeight.bold,
            color: color,
          ),
        ),
      ),
    );
  }
}
4
likes
150
points
22
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Mobile security plugin: root/jailbreak detection, developer mode detection, emulator detection, SSL certificate pinning, and screenshot prevention.

Repository (GitHub)
View/report issues

Topics

#security #root-detection #jailbreak #ssl-pinning #screenshot

License

MIT (license)

Dependencies

crypto, flutter, http

More

Packages that depend on guard_kit

Packages that implement guard_kit