Skip to main content

compliance_integrity 0.1.0-beta.1 copy "compliance_integrity: ^0.1.0-beta.1" to clipboard
compliance_integrity: ^0.1.0-beta.1 copied to clipboard

App and device integrity checks for Flutter - Google Play Integrity on Android and Apple App Attest on iOS, without Firebase.

example/lib/main.dart

import 'dart:convert';
import 'dart:math';

import 'package:compliance_core/compliance_core.dart';
import 'package:compliance_integrity/compliance_integrity.dart';
import 'package:flutter/material.dart';

/// Google Cloud project number, passed at build time:
/// flutter run --dart-define=CLOUD_PROJECT_NUMBER=123456789012
const int _cloudProjectNumber = int.fromEnvironment('CLOUD_PROJECT_NUMBER');

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

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key, this.integrity});

  /// Injected in tests.
  final Integrity? integrity;

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'compliance_integrity example',
    theme: ThemeData(colorSchemeSeed: Colors.teal),
    home: IntegrityScreen(integrity: integrity),
  );
}

class IntegrityScreen extends StatefulWidget {
  const IntegrityScreen({super.key, this.integrity});

  final Integrity? integrity;

  @override
  State<IntegrityScreen> createState() => _IntegrityScreenState();
}

class _IntegrityScreenState extends State<IntegrityScreen> {
  final _audit = InMemoryAuditTrail(maxEvents: 100);
  late final Integrity _integrity =
      widget.integrity ??
      Integrity(
        cloudProjectNumber: _cloudProjectNumber == 0
            ? null
            : _cloudProjectNumber,
        auditTrail: _audit,
      );
  String _status = 'Not checked yet';

  /// DEMO ONLY: a real app must get the request hash from its server, so
  /// the server can check that the token belongs to this exact request.
  String _demoRequestHash() {
    final random = Random.secure();
    final bytes = List<int>.generate(32, (_) => random.nextInt(256));
    return base64Url.encode(bytes).replaceAll('=', '');
  }

  Future<void> _check() async {
    setState(() => _status = 'Checking...');
    final supported = await _integrity.isSupported();
    final result = await _integrity.requestToken(_demoRequestHash());
    if (!mounted) return;
    setState(() {
      _status = switch (result) {
        IntegritySuccess(:final kind, :final token) =>
          'Token received (${kind.name}, ${token.length} chars).\n'
              'Send it to your server for verification.',
        IntegrityUnsupported() => 'Not supported on this device.',
        IntegrityPlayServicesMissing() =>
          'Google Play services or Play Store missing or outdated.',
        IntegrityNetworkError() => 'Network problem. Try again later.',
        IntegrityRateLimited() => 'Rate limited. Try again later.',
        IntegrityConfigurationError(:final message) =>
          'Configuration problem: $message',
        IntegrityPlatformError(:final platformCode, :final message) =>
          'Platform error $platformCode: $message',
      };
      _status = 'isSupported: $supported\n$_status';
    });
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(title: const Text('compliance_integrity example')),
    body: ListView(
      padding: const EdgeInsets.all(16),
      children: [
        FilledButton(
          onPressed: _check,
          child: const Text('Request integrity token'),
        ),
        const SizedBox(height: 8),
        OutlinedButton(
          onPressed: () async {
            await _integrity.reset();
            if (mounted) setState(() => _status = 'Key and provider reset.');
          },
          child: const Text('Reset'),
        ),
        const SizedBox(height: 16),
        Text(_status, key: const ValueKey('status')),
        const SizedBox(height: 16),
        Text('Audit events', style: Theme.of(context).textTheme.titleMedium),
        StreamBuilder<AuditEvent>(
          stream: _audit.events,
          builder: (context, _) => Text(
            [
              for (final e in _audit.history) '${e.type} ${e.metadata}',
            ].join('\n'),
          ),
        ),
      ],
    ),
  );
}
0
likes
160
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

App and device integrity checks for Flutter - Google Play Integrity on Android and Apple App Attest on iOS, without Firebase.

Repository (GitHub)
View/report issues
Contributing

Topics

#security #integrity #attestation #compliance #privacy

License

MIT (license)

Dependencies

compliance_core, flutter, meta

More

Packages that depend on compliance_integrity

Packages that implement compliance_integrity