Quixxi Plugin

The Flutter plugin provides the following security enhancements for mobile applications:

SSL Pinning

  • Ensures secure communication between the application and backend servers by validating the server certificate against a pinned public key.

  • Protects against man-in-the-middle (MITM) attacks by preventing connections to unauthorized servers.

Clipboard Protection

  • Prevents copy and paste actions inside the application to safeguard sensitive information such as passwords, tokens, or personal data.

  • Reduces the risk of data leakage through clipboard monitoring or malicious apps.

API Attestation

  • Protects backend APIs from misuse by validating requests through Secure HashKey attestation.

  • Ensures that only genuine, untampered applications can communicate with the server.

  • Helps prevent unauthorized API calls and mitigates replay or injection attacks.

Integration Notes

Important

Quixxi Security Shield must be applied after integrating this plugin into your application.

SSL Pinning

  • Debug Builds

    • SSL certificate validation is not enforced.

    • This is intentional to simplify development and testing.

  • Release Builds

    • Quixxi Shield must be applied.

    • Enforces SSL Pinning and strong runtime protections.

API Attestation

  • In Debug Mode, a default hardcoded hash key is used:
MNaiMYHqVH3ZLVfGVc4nqFcd7Gf8Avr6JePPUJZYfrCA7A00GiRSFTPC981P7Vpe1gDUh9YQaKEE2ihGp04GfW7EB2HJx8JVkwv5k1fvDhaQNMetvaFACAw70gP61KYK
  • Use this key only for development and testing.

  • In Production Builds, configure and use SecureHash Key generated on Quixxi portal to protect against API misuse.

Getting Started

Add quixxi as a dependency in your pubspec.yaml:

dependencies:
  quixxi: 1.0.0

Usage example

SSL Pinning

Using Dio

import 'package:quixxi/services.dart';

Dio dioClient = getDioClient('https://gorest.co.in',enableSSLPinning: true);

void apiCall() async {
    var header = {'Content-type': 'application/json; charset=utf-8'};

    try {
      final response = await dio.get("https://yourdomain.com/yourapi",
          options: Options(headers: header));
      if (response.statusCode == 200) {
        apiResponse.value = response.data.toString();
      } else {
        print('${response.statusCode} : ${response.data.toString()}');
        apiResponse.value = response.data.toString();
      }
    } catch (error) {
      apiResponse.value = error.toString();
    }
  }

Using Http

import 'package:quixxi/services.dart';

SecureHttpClient secureHttpClient = getSecureHttpClient(enableSSLPinning: true);

void apiCall2() async{
     var header = {'Content-type': 'application/json; charset=utf-8'};

    try {
        Uri uri = Uri.parse("https://gorest.co.in/public/v2/todos");
        final response = await secureHttpClient.get(uri, headers: header);
        if (response.statusCode == 200) {
          apiResponse.value = response.body.toString();
        }else{
            print('${response.statusCode} : ${response.body.toString()}');
            apiResponse.value = response.body.toString();
        }
    } catch (error) {
      apiResponse.value = error.toString();
    }
}

Custom Implementation

import 'package:quixxi/services.dart';

Future myCustomImplementation(String url, Map<String,String> headers) async {
  try{
    final secure = await SSLCertificatePinning().check(
      serverURL: url,
      headerHttp: headers,
      timeout : 50
    );

    if(secure.contains("CONNECTION_SECURE")){
      return true;
    }else{
      return false;
    }
  }catch(e){
    return false;
  }
}

API Attestation

You can enable API Attestation to automatically send a secure hash (from Quixxi) either in the request header or payload.

With SSLPinning

Using Dio
import 'package:quixxi/services.dart';

// Enable App Attestation and configure hash injection
Dio dioClient = getDioClient(
  'https://gorest.co.in',
  enableSSLPinning: true,
  enableAppAttestation: true,
  sendHashInHeader: true,   // or false
  sendHashInPayload: false, // or true
);

void apicall_dio_app_attestation() async {
  var header = {'Content-type': 'application/json; charset=utf-8'};
  try {
    final response = await dioClient.get(
      urlTextEditingController.text,
      options: Options(headers: header),
    );
    apiResponse.value = response.data.toString();
  } catch (error) {
    apiResponse.value = error.toString();
  }
}
Using Http
import 'package:quixxi/services.dart';

SecureHttpClient secureHttpClient = getSecureHttpClient(
  enableSSLPinning: true,
  enableAppAttestation: true,
  sendHashInPayload: true, // or sendHashInHeader: true
);

void apicall_http_app_attestation() async {
  var header = {'Content-type': 'application/json; charset=utf-8'};
  try {
    Uri uri = Uri.parse(urlTextEditingController.text);
    final response = await secureHttpClient.get(uri, headers: header);
    apiResponse.value = response.body.toString();
  } catch (error) {
    apiResponse.value = error.toString();
  }
}

Without SSLPinning

Same usage, but dont pass enableSSLPinning. it is set to false by default.

SOAP API Support

App Attestation also works with SOAP requests. Just set "Content-Type": "text/xml; charset=utf-8" in headers and provide your envelope.

Using Dio

String soapEnvelope({String? bodyContent}) => '''
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    ${bodyContent ?? ''}
  </soap:Body>
</soap:Envelope>
''';

// Enable App Attestation and configure hash injection
Dio dioClient = getDioClient(
  'https://httpbin.org',
  enableAppAttestation: true,
  sendHashInHeader: true,   // or false
  sendHashInPayload: false, // or true
);

void apicall_dio_soap_with_header() async {
  try {
    isLoading.value = true;

    String envelope = soapEnvelope(bodyContent: '<Test>Hello</Test>');

    final response = await dioClient.post(
      "https://httpbin.org/post",
      data: envelope,
      options: Options(
        headers: {
          'Content-Type': 'text/xml; charset=utf-8',
          'SOAPAction': 'urn:TestAction'
        },
      ),
    );

    isLoading.value = false;
    apiResponse.value = response.data.toString();
  } catch (error) {
    isLoading.value = false;
    apiResponse.value = error.toString();
  }
}
Using Http
  String soapEnvelope({String? bodyContent}) => '''
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    ${bodyContent ?? ''}
  </soap:Body>
</soap:Envelope>
''';

// Enable App Attestation and configure hash injection
SecureHttpClient secureHttpClient = getSecureHttpClient(
  enableAppAttestation: true,
  sendHashInPayload: true, // or sendHashInHeader: true
);

void apicall_http_soap_with_payload() async {
  try {
    isLoading.value = true;

    // Inject SecureHash inside <soap:Body>
    String envelope = soapEnvelope(
      bodyContent: '<Test>Hello</Test>',
    );

    Uri uri = Uri.parse("${urlTextEditingController.text}/post");

    final response = await secureHttpClientWithHashInPayload.post(
      uri,
      headers: {
        'Content-Type': 'text/xml; charset=utf-8',
        'SOAPAction': 'urn:TestAction',
      },
      body: envelope,
    );

    isLoading.value = false;
    apiResponse.value = response.body;
  } catch (error) {
    isLoading.value = false;
    apiResponse.value = error.toString();
  }
}

Copy & Paste Prevention

Secure Text Field


import 'package:flutter/material.dart';
import 'package:quixxi/text_field/quixxi_text_form_field.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Quixxi Example')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Quixxi Textfield'),
            Container(
              padding: const EdgeInsets.symmetric(vertical: 15),
              Container(
                padding: const EdgeInsets.symmetric(vertical: 15),
                child: QuixxiTextField(
                  decoration: const InputDecoration(
                    border: UnderlineInputBorder(),
                    hintText: 'https://yourdomain.com',
                  ),
                  keyboardType: TextInputType.url,
                  textInputAction: TextInputAction.next,
                  controller: TextEditingController(
                          text: "https://yourdomain.com"),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Secure Text Form Field


import 'package:flutter/material.dart';
import 'package:your_package/quixxi_text_form_field.dart'; // adjust the import

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Quixxi Example')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Quixxi TextFormfield'),
            Container(
              padding: const EdgeInsets.symmetric(vertical: 15),
              child: QuixxiTextFormField(
                decoration: const InputDecoration(
                  border: UnderlineInputBorder(),
                  hintText: 'https://yourdomain.com',
                ),
                keyboardType: TextInputType.url,
                textInputAction: TextInputAction.next,
                controller: TextEditingController(
                  text: "https://yourdomain.com",
                ),
                onSaved: (value) {},
                validator: (value) {},
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Configuration Parameters

When creating a Dio client with getDioClient or an Http client with getSecureHttpClient, you can configure the following options:

Parameter Type Default Description
enableSSLPinning bool false Enables SSL certificate pinning (requires Quixxi Shield in release build).
enableAppAttestation bool false Enables App Attestation, which sends a secure hash from Quixxi.
sendHashInHeader bool false If true, the secure hash is sent in the HTTP/SOAP headers.
sendHashInPayload bool false If true, the secure hash is injected into the request payload (JSON or SOAP <soap:Body>).
baseUrl (Dio only) String Base URL for all API calls made with Dio client.

Adding Quixxi Shield to application

  • Create an account in https://portal.quixxi.com
  • Create application container in your account.
  • Upload your application to portal for app protection.
  • For SSL Pinning, choose the option SSL certificate validation via SSLPinning in Shield configuration
  • For API Attestation, choose the option API attestation in Shield configuration
  • After applying shield configurations, wait for Shielding to complete
  • Download protected application from portal.