licensify 1.7.1 copy "licensify: ^1.7.1" to clipboard
licensify: ^1.7.1 copied to clipboard

A lightweight yet powerful license management solution for Flutter and Dart applications with cryptographically secure signatures

example/main.dart

import 'dart:convert';
import 'package:licensify/licensify.dart';
import 'package:pointycastle/digests/sha512.dart';

/// Comprehensive example of Licensify package usage
///
/// This file demonstrates all the core functionalities of the Licensify package
/// including key generation, license creation, validation, storage, and more.
void main() {
  print('====== LICENSIFY EXAMPLES ======\n');

  // First, let's create our main example object
  final examples = LicensifyExamples();

  // Run the comprehensive examples
  examples.runAllExamples();
}

/// Main class containing all examples
class LicensifyExamples {
  // Store key pairs for reuse across examples
  late final LicensifyKeyPair rsaKeyPair;
  late final LicensifyKeyPair ecdsaKeyPair;

  // Store licenses for reuse across examples
  late final License rsaLicense;
  late final License ecdsaLicense;

  /// Run all examples in sequence
  void runAllExamples() {
    // 1. Key generation examples
    keyGenerationExamples();

    // 2. License creation examples
    licenseCreationExamples();

    // 3. License validation examples
    licenseValidationExamples();

    // 4. Schema validation examples
    schemaValidationExamples();

    // 5. License storage examples
    licenseStorageExamples();

    // 6. Performance comparison examples
    performanceComparisonExamples();
  }

  /// Examples of generating cryptographic keys
  void keyGenerationExamples() {
    print('\n===== KEY GENERATION EXAMPLES =====');

    // Generate RSA keys (traditional approach)
    print('\n1. Generating RSA keys:');
    final rsaStartTime = DateTime.now();
    rsaKeyPair = RsaKeyGenerator.generateKeyPairAsPem(bitLength: 2048);
    final rsaEndTime = DateTime.now();

    print('RSA private key (excerpt):');
    print(rsaKeyPair.privateKey.content);
    print('RSA public key (excerpt):');
    print(rsaKeyPair.publicKey.content);
    print(
      'Generation time: ${rsaEndTime.difference(rsaStartTime).inMilliseconds}ms',
    );
    print('Private key size: ${rsaKeyPair.privateKey.content.length} bytes');
    print('Public key size: ${rsaKeyPair.publicKey.content.length} bytes');

    // Generate ECDSA keys (modern, more efficient approach)
    print('\n2. Generating ECDSA keys:');
    final ecdsaStartTime = DateTime.now();
    ecdsaKeyPair = EcdsaKeyGenerator.generateKeyPairAsPem(
      curve: EcCurve.p256, // NIST P-256 curve
      randomAlgorithm: SecureRandomAlgorithm.fortuna,
    );
    final ecdsaEndTime = DateTime.now();

    print('ECDSA private key (excerpt):');
    print(ecdsaKeyPair.privateKey.content);
    print('ECDSA public key (excerpt):');
    print(ecdsaKeyPair.publicKey.content);
    print(
      'Generation time: ${ecdsaEndTime.difference(ecdsaStartTime).inMilliseconds}ms',
    );
    print('Private key size: ${ecdsaKeyPair.privateKey.content.length} bytes');
    print('Public key size: ${ecdsaKeyPair.publicKey.content.length} bytes');

    // Show benefits of ECDSA over RSA
    _compareCryptoSystems(
      rsaKeyPair,
      ecdsaKeyPair,
      rsaEndTime.difference(rsaStartTime),
      ecdsaEndTime.difference(ecdsaStartTime),
    );
  }

  /// Examples of creating licenses
  void licenseCreationExamples() {
    print('\n\n===== LICENSE CREATION EXAMPLES =====');

    // Create RSA license
    print('\n1. Creating license with RSA:');
    final rsaGenerator = LicenseGenerator(privateKey: rsaKeyPair.privateKey);

    rsaLicense = rsaGenerator(
      appId: 'com.example.app',
      expirationDate: DateTime.now().add(Duration(days: 365)),
      type: LicenseType.pro,
      features: {
        'maxUsers': 50,
        'modules': ['reporting', 'analytics', 'export'],
        'premium': true,
      },
      metadata: {
        'customerName': 'Acme Corp',
        'contactEmail': 'support@acme.com',
      },
    );

    _printLicenseDetails(rsaLicense, 'RSA');

    // Create ECDSA license
    print('\n2. Creating license with ECDSA:');
    final ecdsaGenerator = LicenseGenerator(
      privateKey: ecdsaKeyPair.privateKey,
      // Optionally specify hash algorithm (defaults to SHA-512)
      digest: SHA512Digest(),
    );

    ecdsaLicense = ecdsaGenerator(
      appId: 'com.example.app',
      expirationDate: DateTime.now().add(Duration(days: 365)),
      type: LicenseType.pro,
      features: {
        'maxUsers': 50,
        'modules': ['reporting', 'analytics', 'export'],
        'premium': true,
      },
      metadata: {
        'customerName': 'Acme Corp',
        'contactEmail': 'support@acme.com',
      },
    );

    _printLicenseDetails(ecdsaLicense, 'ECDSA');

    // Create a license with custom type
    print('\n3. Creating license with custom type:');
    final customLicense = rsaGenerator(
      appId: 'com.example.app',
      expirationDate: DateTime.now().add(Duration(days: 365)),
      type: LicenseType('enterprise'), // Custom license type
      features: {
        'maxUsers': 500,
        'modules': ['reporting', 'analytics', 'export', 'admin'],
        'premium': true,
        'enterpriseSupport': true,
      },
    );

    _printLicenseDetails(customLicense, 'Custom Type');
  }

  /// Examples of validating licenses
  void licenseValidationExamples() {
    print('\n\n===== LICENSE VALIDATION EXAMPLES =====');

    // Validate RSA license
    print('\n1. Validating RSA license:');
    final rsaValidator = LicenseValidator(publicKey: rsaKeyPair.publicKey);

    final rsaValidationResult = rsaValidator.validateLicense(rsaLicense);
    if (rsaValidationResult.isValid) {
      print('✅ RSA license is valid');
    } else {
      print('❌ RSA license is invalid: ${rsaValidationResult.message}');
    }

    // Validate ECDSA license
    print('\n2. Validating ECDSA license:');
    final ecdsaValidator = LicenseValidator(
      publicKey: ecdsaKeyPair.publicKey,
      digest: SHA512Digest(), // Must match the digest used for signing
    );

    final ecdsaValidationResult = ecdsaValidator.validateLicense(ecdsaLicense);
    if (ecdsaValidationResult.isValid) {
      print('✅ ECDSA license is valid');
    } else {
      print('❌ ECDSA license is invalid: ${ecdsaValidationResult.message}');
    }

    // Comprehensive license validation
    print('\n3. Comprehensive license validation:');

    // First check the license expiration separately
    final license = rsaLicense; // Using our sample license

    if (license.isExpired) {
      print(
        '❌ License has expired - expiration date: ${license.expirationDate}',
      );
    } else {
      print(
        '✅ License is not expired - valid until: ${license.expirationDate}',
      );
      print('   Days remaining: ${license.remainingDays}');
    }

    // Then check the signature
    final signatureResult = rsaValidator.validateSignature(license);
    if (signatureResult.isValid) {
      print('✅ Signature is valid');
    } else {
      print('❌ Invalid signature: ${signatureResult.message}');
    }

    // Combined validation
    final validationResult = rsaValidator.validateLicense(license);
    if (validationResult.isValid) {
      print('✅ License is completely valid (signature and expiration)');
    } else {
      print('❌ License validation failed: ${validationResult.message}');
    }

    // Example of validating with schema
    print('\nExample of schema validation:');
    print('''
// Define schema
final schema = LicenseSchema(
  featureSchema: {
    'maxUsers': SchemaField(type: FieldType.integer, required: true),
  },
  metadataSchema: {
    'customerName': SchemaField(type: FieldType.string, required: true),
  }
);

// Validate against schema
final schemaResult = validator.validateSchema(license, schema);
final isFullyValid = validator.validateLicenseWithSchema(license, schema);

if (isFullyValid) {
  print('License is valid with all checks (signature, expiration, schema)');
}
''');

    // Demonstrate tampered license validation
    print('\n4. Validating tampered license:');
    final tamperedLicense = License(
      id: rsaLicense.id,
      appId: rsaLicense.appId,
      expirationDate: rsaLicense.expirationDate.add(
        Duration(days: 365),
      ), // Tampered expiration
      createdAt: rsaLicense.createdAt,
      signature:
          rsaLicense.signature, // Signature doesn't match the modified data
      type: rsaLicense.type,
      features: rsaLicense.features,
      metadata: rsaLicense.metadata,
    );

    final tamperedResult = rsaValidator.validateLicense(tamperedLicense);
    if (tamperedResult.isValid) {
      print('❌ SECURITY ISSUE: Tampered license validated as valid!');
    } else {
      print('✅ Security works: Tampered license detected');
      print('Error: ${tamperedResult.message}');
    }
  }

  /// Examples of schema validation
  void schemaValidationExamples() {
    print('\n\n===== SCHEMA VALIDATION EXAMPLES =====');

    // Define a schema for enterprise licenses
    print('\n1. Defining license schema:');
    final schema = LicenseSchema(
      featureSchema: {
        'maxUsers': SchemaField(
          type: FieldType.integer,
          required: true,
          validators: [NumberValidator(minimum: 1, maximum: 1000)],
        ),
        'modules': SchemaField(
          type: FieldType.array,
          required: true,
          validators: [
            ArrayValidator(minItems: 1, itemValidator: StringValidator()),
          ],
        ),
        'premium': SchemaField(type: FieldType.boolean, required: true),
      },
      metadataSchema: {
        'customerName': SchemaField(
          type: FieldType.string,
          required: true,
          validators: [StringValidator(minLength: 3)],
        ),
      },
      allowUnknownFeatures: false,
      allowUnknownMetadata: true,
    );

    print('Schema defined with:');
    print(
      '- Required features: maxUsers (int), modules (array), premium (bool)',
    );
    print('- Required metadata: customerName (string)');
    print('- Unknown features: not allowed');
    print('- Unknown metadata: allowed');

    // Validate license against schema
    print('\n2. Validating license against schema:');
    final rsaValidator = LicenseValidator(publicKey: rsaKeyPair.publicKey);

    final schemaResult = rsaValidator.validateSchema(rsaLicense, schema);
    if (schemaResult.isValid) {
      print('✅ License schema is valid');
    } else {
      print('❌ License schema is invalid:');
      final errors = schemaResult.errors;
      if (errors.isNotEmpty) {
        for (final entry in errors.entries) {
          print('  - ${entry.key}: ${entry.value}');
        }
      } else {
        print('  - Unknown validation errors');
      }
    }

    // Comprehensive validation with schema
    print('\n3. Comprehensive validation with schema:');
    final completeResult = rsaValidator.validateLicenseWithSchema(
      rsaLicense,
      schema,
    );
    print('License valid: $completeResult');

    // Create invalid license to demonstrate schema validation failure
    print('\n4. Validating license with invalid schema:');
    final invalidLicense = LicenseGenerator(privateKey: rsaKeyPair.privateKey)(
      appId: 'com.example.app',
      expirationDate: DateTime.now().add(Duration(days: 365)),
      type: LicenseType.pro,
      features: {
        // Missing required 'maxUsers' field
        'modules': [], // Empty array (will fail minItems validation)
        'premium': 'yes', // Wrong type (string instead of boolean)
      },
      // Missing required 'customerName' field
    );

    final invalidSchemaResult = rsaValidator.validateSchema(
      invalidLicense,
      schema,
    );
    if (invalidSchemaResult.isValid) {
      print('❌ ISSUE: Invalid license schema validated as valid!');
    } else {
      print('✅ Schema validation works: Invalid license detected');
      print('Errors:');
      final errors = invalidSchemaResult.errors;
      if (errors.isNotEmpty) {
        for (final entry in errors.entries) {
          print('  - ${entry.key}: ${entry.value}');
        }
      } else {
        print('  - Unknown validation errors');
      }
    }
  }

  /// Examples of license storage
  void licenseStorageExamples() {
    print('\n\n===== LICENSE STORAGE EXAMPLES =====');

    // In-memory storage example
    print('\n1. Using in-memory storage:');
    final storage = InMemoryLicenseStorage();
    final repository = LicenseRepository(storage: storage);

    // Save license
    print('Saving license...');
    repository.saveLicense(rsaLicense);

    // Check if license exists
    storage.hasLicense().then((exists) {
      print('License exists in storage: $exists');
    });

    // Retrieve license
    print('Retrieving license...');
    repository.getCurrentLicense().then((license) {
      if (license != null) {
        print('✅ License retrieved successfully');
        print('License ID: ${license.id}');
      } else {
        print('❌ Failed to retrieve license');
      }
    });

    // Custom storage example
    print('\n2. Implementing custom storage:');
    print('''
// Implement ILicenseStorage to create your own storage mechanism
class FileSystemLicenseStorage implements ILicenseStorage {
  final String filePath;
  
  FileSystemLicenseStorage(this.filePath);
  
  @override
  Future<bool> deleteLicenseData() async {
    // Implementation to delete file
    return true;
  }
  
  @override
  Future<bool> hasLicense() async {
    // Implementation to check if file exists
    return true;
  }
  
  @override
  Future<Uint8List?> loadLicenseData() async {
    // Implementation to read file
    return null;
  }
  
  @override
  Future<bool> saveLicenseData(Uint8List data) async {
    // Implementation to write to file
    return true;
  }
}
''');
  }

  /// Examples comparing performance between RSA and ECDSA
  void performanceComparisonExamples() {
    print('\n\n===== PERFORMANCE COMPARISON EXAMPLES =====');

    // Compare license generation performance
    print('\n1. License generation performance:');
    final rsaGenerator = LicenseGenerator(privateKey: rsaKeyPair.privateKey);
    final ecdsaGenerator = LicenseGenerator(
      privateKey: ecdsaKeyPair.privateKey,
    );

    // RSA license generation time
    final rsaStartTime = DateTime.now();
    for (var i = 0; i < 10; i++) {
      rsaGenerator(
        appId: 'com.example.app',
        expirationDate: DateTime.now().add(Duration(days: 365)),
        type: LicenseType.standard,
      );
    }
    final rsaDuration = DateTime.now().difference(rsaStartTime);
    print('RSA license generation (10x): ${rsaDuration.inMilliseconds}ms');

    // ECDSA license generation time
    final ecdsaStartTime = DateTime.now();
    for (var i = 0; i < 10; i++) {
      ecdsaGenerator(
        appId: 'com.example.app',
        expirationDate: DateTime.now().add(Duration(days: 365)),
        type: LicenseType.standard,
      );
    }
    final ecdsaDuration = DateTime.now().difference(ecdsaStartTime);
    print('ECDSA license generation (10x): ${ecdsaDuration.inMilliseconds}ms');

    // Calculate performance difference
    final generationSpeedup =
        rsaDuration.inMilliseconds / ecdsaDuration.inMilliseconds;
    print(
      'ECDSA is ${generationSpeedup.toStringAsFixed(1)}x faster for generation',
    );

    // Compare validation performance
    print('\n2. License validation performance:');
    final rsaValidator = LicenseValidator(publicKey: rsaKeyPair.publicKey);
    final ecdsaValidator = LicenseValidator(publicKey: ecdsaKeyPair.publicKey);

    // RSA validation time
    final rsaValidationStart = DateTime.now();
    for (var i = 0; i < 100; i++) {
      rsaValidator.validateLicense(rsaLicense);
    }
    final rsaValidationDuration = DateTime.now().difference(rsaValidationStart);
    print(
      'RSA license validation (100x): ${rsaValidationDuration.inMilliseconds}ms',
    );

    // ECDSA validation time
    final ecdsaValidationStart = DateTime.now();
    for (var i = 0; i < 100; i++) {
      ecdsaValidator.validateLicense(ecdsaLicense);
    }
    final ecdsaValidationDuration = DateTime.now().difference(
      ecdsaValidationStart,
    );
    print(
      'ECDSA license validation (100x): ${ecdsaValidationDuration.inMilliseconds}ms',
    );

    // Calculate performance difference
    final validationSpeedup =
        rsaValidationDuration.inMilliseconds /
        ecdsaValidationDuration.inMilliseconds;
    print(
      'ECDSA is ${validationSpeedup.toStringAsFixed(1)}x faster for validation',
    );

    // Compare signature sizes
    print('\n3. Signature size comparison:');
    print('RSA signature size: ${rsaLicense.signature.length} bytes');
    print('ECDSA signature size: ${ecdsaLicense.signature.length} bytes');
    print(
      'ECDSA signatures are ${((rsaLicense.signature.length - ecdsaLicense.signature.length) / rsaLicense.signature.length * 100).toStringAsFixed(1)}% smaller',
    );
  }

  /// Helper method to compare RSA and ECDSA crypto systems
  void _compareCryptoSystems(
    LicensifyKeyPair rsaKeyPair,
    LicensifyKeyPair ecdsaKeyPair,
    Duration rsaGenerationTime,
    Duration ecdsaGenerationTime,
  ) {
    print('\n3. Comparing RSA vs ECDSA:');

    // Key size comparison
    final rsaPrivateKeySize = rsaKeyPair.privateKey.content.length;
    final rsaPublicKeySize = rsaKeyPair.publicKey.content.length;
    final ecdsaPrivateKeySize = ecdsaKeyPair.privateKey.content.length;
    final ecdsaPublicKeySize = ecdsaKeyPair.publicKey.content.length;

    print('RSA private key: $rsaPrivateKeySize bytes');
    print('RSA public key: $rsaPublicKeySize bytes');
    print(
      'ECDSA private key: $ecdsaPrivateKeySize bytes (${(100 - ecdsaPrivateKeySize * 100 / rsaPrivateKeySize).toStringAsFixed(0)}% smaller)',
    );
    print(
      'ECDSA public key: $ecdsaPublicKeySize bytes (${(100 - ecdsaPublicKeySize * 100 / rsaPublicKeySize).toStringAsFixed(0)}% smaller)',
    );

    // Generation time comparison
    print('RSA generation time: ${rsaGenerationTime.inMilliseconds}ms');
    print('ECDSA generation time: ${ecdsaGenerationTime.inMilliseconds}ms');
    print(
      'ECDSA is ${(rsaGenerationTime.inMilliseconds / ecdsaGenerationTime.inMilliseconds).toStringAsFixed(1)}x faster',
    );

    // Security level comparison
    print('\nSecurity level comparison:');
    print('RSA-2048: ~112-bit security level');
    print('ECDSA P-256: ~128-bit security level');
    print('ECDSA is more secure with smaller keys!');
  }

  /// Helper method to print license details
  void _printLicenseDetails(License license, String type) {
    print('$type License details:');
    print('- ID: ${license.id}');
    print('- App ID: ${license.appId}');
    print('- Type: ${license.type.name}');
    print('- Created: ${license.createdAt}');
    print(
      '- Expires: ${license.expirationDate} (${license.remainingDays} days remaining)',
    );

    // Безопасный вывод features с проверкой
    try {
      final featuresJson = jsonEncode(license.features);
      print('- Features: $featuresJson');
    } catch (e) {
      print('- Features: ${license.features} (not encodable to JSON)');
    }

    // Безопасный вывод metadata с проверкой
    if (license.metadata != null) {
      try {
        final metadataJson = jsonEncode(license.metadata);
        print('- Metadata: $metadataJson');
      } catch (e) {
        print('- Metadata: ${license.metadata} (not encodable to JSON)');
      }
    } else {
      print('- Metadata: none');
    }

    print(
      '- Signature (${license.signature.length} bytes): ${license.signature}',
    );
  }
}
copied to clipboard
4
likes
160
points
415
downloads

Publisher

verified publisherdart.nogipx.dev

Weekly Downloads

2024.09.16 - 2025.03.31

A lightweight yet powerful license management solution for Flutter and Dart applications with cryptographically secure signatures

Repository (GitHub)
View/report issues

Topics

#license #security #validation #cryptography #web

Documentation

Documentation
API reference

License

LGPL-3.0 (license)

Dependencies

basic_utils, pointycastle, uuid

More

Packages that depend on licensify