Sunday, July 24, 2022

How To Secure Flutter Application



1. Stay up-to-date

Getting your flutter sdk, plugin and packages up to date is the easiest and one the best ways to secure your apps. Google Flutter Team releases security fixes and patches for vulnerabilities found on the Flutter framework.


2. Secure your data

Do not use sharing settings or SQLite to store sensitive user data. This is because it is easy to open on any device. So you will be required to encrypt the stored data. For that, you can use flutter_secure_storage. This package uses Keystore for Android and Keychain for iOS


3.Jailbroken and rooted devices

Rooted Android device and jailbroken iOS device have more privileges compared to regular system. It can introduce malwares to the user's device and bypass the normal behavior of the device. There is package in Flutter that is flutter_jailbreak_detection. You can use this package to detect if your app is running on a jailbroken or rooted device. Use Root Beer on Android and DTT Jailbreak Detection on iOS.


4. Local Auth

To prevent unauthorized access we shall use the local_auth package to provide a gateway to get the access the app content as many times the user closes the app temporarily. This includes authentication with biometrics such as fingerprint or facial recognition.


5. Restrict network traffic

One way to restrict network traffic or connection to an unsecured endpoint is through explicity whitelisting your domain


6. Ceritificate pinning

You can also implement certificate pinning for your apps to restrict the secure connection the particular certificates. This ensures that the connection between your apps and your server is trusted and authentic



7. Obfuscate code

The compiled binaries and code of your apps can be reversed engineered. Some of the things that can be exposed include the strings, method and classes, and API keys. These data are either in their original form or in  plain text.

```

flutter build appbundle --obfuscate --split-debug-info=/<directory>

```

Getting Started with Flutter Bloc Pattern

 Bloc Pattern


1. Why Bloc

- Keep your code clarm organized, clean, and maintainable

- Compatible with flutter declarative programming


2. What's Bloc

- A design pattern created by Google to separate Logic from UI 

- There is many library to implement this design pattern. But IMO, you should use the flutter_bloc of Felix Angelo. It is a state management to easier your life

- For every action inside the application, there will be a relative state from it. For example, when the data is fetching, the app should be in a loading state displaying a loading animation on the screen


3. The Core Concepts

- Stream is the foundation of Bloc


3.1 Stream

- Stream is a sequence of async event. Each event is a data event or error event.

- When a stream has dispatched its event, it will also notify to all listener subscribed to it


3.2 Receive Stream

- async* means asynchronous generation function, it generates async data

- yield pushes the data (integer) through the Stream

- await keyword helps to wait for a process to finish before proceeding to the next step


```

Stream<int> dataStream() async* {

for (int i = 0; i<3; i++) {

await Future.delayed(Duration(seconds:3));

yield i;

}

}


Stream<int> stream = dataStream();


stream.listen((event) {

    print("RECEIVE data ${event.toString()}");

  });


```

- async* means asynchronous generation function, it generates async data

- yield pushes the data (integer) through the Stream

- await keyword helps to wait for a process to finish before proceeding to the next step


3.3 Cubit and Bloc


- Cubit is a minimal version of Bloc

- Cubit only emits a stream of states

- Bloc emits a stream of states and receive a stream of event


4. Flutter BLOC

4.1 BlocProvider

- A widget that creates and provides a Bloc to all of its children. A single instance of it can be provided to multi widgets within a tree hierarchy




4.2 Bloc Builder

- BlocBuilder is a widget that helps rebuild the UI based on some Bloc state 

changes

- Rebuild a large UI is a heavy cpu task to compute. That's why you need to wrap the exact part of the UI you want to rebuild inside BlocBuilder. For example, if a text is nested inside a column or a row, dont build entire the column/ row, rather to rebuild the text widge only by wrapping it inside the BlocBuilder

- If you dont provide exactly the cubit/ Bloc in Blocbuilder, it will search for the nearest parent bloc in the tree

5. Code Implementation


counter_app.dart

```

import 'package:flutter/material.dart';


import 'counter/counter.dart';


class CounterApp extends MaterialApp {

  const CounterApp({Key? key}) : super(key: key, home: const CounterPage());

}

```


counter_page.dart

```

import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';


import '../counter.dart';

import 'counter_view.dart';


class CounterPage extends StatelessWidget {

  const CounterPage({Key? key}) : super(key: key);


  @override

  Widget build(BuildContext context) {

    return BlocProvider(

      create: (_) => CounterCubit(),

      child: CounterView(),

    );

  }

}

```


counter_cubit.dart

```

import 'package:bloc/bloc.dart';


class CounterCubit extends Cubit<int> {

  CounterCubit() : super(0);


  /// Add 1 to the current state.

  void increment() => emit(state + 1);


  /// Subtract 1 from the current state.

  void decrement() => emit(state - 1);

}

```


counter_view.dart

```

import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';


import '../counter.dart';


class CounterView extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    final textTheme = Theme.of(context).textTheme;

    return Scaffold(

      appBar: AppBar(title: const Text('Counter')),

      body: Center(

        child: BlocBuilder<CounterCubit, int>(

          builder: (context, state) {

            return Text('$state', style: textTheme.headline2);

          },

        ),

      ),

      floatingActionButton: Column(

        mainAxisAlignment: MainAxisAlignment.end,

        crossAxisAlignment: CrossAxisAlignment.end,

        children: <Widget>[

          FloatingActionButton(

            key: const Key('counterView_increment_floatingActionButton'),

            child: const Icon(Icons.add),

            onPressed: () => context.read<CounterCubit>().increment(),

          ),

          const SizedBox(height: 8),

          FloatingActionButton(

            key: const Key('counterView_decrement_floatingActionButton'),

            child: const Icon(Icons.remove),

            onPressed: () => context.read<CounterCubit>().decrement(),

          ),

        ],

      ),

    );

  }

}

```

6. Summary

- Bloc is a good pattern to improve the code quality and help easier the state management in app

- Must familiar with stream and reactive programming

- Much of boilerplate code


Reference link:

- https://bloclibrary.dev/#/gettingstarted

Thursday, July 21, 2022

How to get your app rejection on App Store (and how to fix it)



App Content Is Inappropriate

  • Apps related to sensitive content, such as porn and gambling, are automatically rejected. They will also not approve content about terrorism, racism, violence, substance abuse. Generally, if your app offends people or encourages them to break the law, you will probably get a rejection approval
  • In this case, either you modify the content or not launch it into the Apple Store.


You Have No Privacy Policy

  • Apple requires the application to take the user privacy data seriously to comply the GDPR in Europe and various FTC rules in the US.
  • To avoid rejection, make sure that users have been aware of the Term Of Use, Privacy Policy.
  • It should explain how you use the specific data that you collect: how it’s stored, and whether or not you share it with other third-party entities.
  • Lastly, the user has full permission for his own data, even asking to remove it: making a function for request to remove data is a reasonable choice. 


Missing Sign in with Apple for third party sign up

  • Apps that exclusively use a third-party or social login service (such as Facebook Login, Google Sign-In, Sign in with Twitter, Sign In with LinkedIn, Login with Amazon, or WeChat Login) to set up or authenticate the user’s primary account with the app must also offer Sign in with Apple as an equivalent option


App Wants to Share Personal User Data

  • In general, users must have control over their data at all times. Users must notice how and why the application would like to use their data and privacy: photos, location, notification...
  • The key is being declaration right and enough permission will avoid you to be rejected in this section.


The App Is a Copy of Another App

  • Apps that are cloned from another app on the Apple Store will get rejection. You should come up with a unique app concept.
  • Another case is spamming, the same app but multiple variants. For example: same app feature and UI but different theme, data...


Hardware and Software Are Not Compatible

  • App can not only run on iPhone but also on iPad as well and vice versa


You’re Using Private API

  • Private APIs are the API used internally by Apple. They are undocumented or  don't officially documented by Apple. The APIs are not stable and can be changed anytime, so they're less guarantee
  • Make sure your code base and even the external libraries don't mess with these or wait for a brutal rejection.


Bugs and Crashes Occur During the Review Process

  • If any crash or significant bug or performance issue (ex: http 500, no network, lagging...) appears during the process, the app will be rejected immediately. Those who perform the review process are human and they test on the physical device (not on an  emulator).
  •  To avoid this, please take the QA step seriously.


Unusually Long Load Times

  • Apps that take long loading times may cause poor user experience, therefore, could be rejected. To prevent this kind of issue, simplify the user interface and optimize your code to make it run faster, compressing images and assets to reduce load times.
  • For apps that need to connect to a server, you only fetch required data and utilize the caching mechanism.
  • For cold startup, it's a good idea to add a splash screen


Placeholder Content Is Still in the App

  • A placeholder or dummy content is a sign of an uncompleted app. A not yet complete app violates the App Store rules, so the app will be rejected.
  • Inspecting every corner of your app ensures that you catch these simple mistakes before submission.


Broken Links in the App

  • Broken links in apps will also be rejected by Apple. For reviewers, it's a sign of poor performance application may affect to user. Thoroughly check all your app links before submit the app.


App Appears to Be Unfinished

  • Even if the app is complete, the mistake in app name (app beta, app dev, app demo...) or build version (0.x) may get your app violate the incomplete app case. The app to submit to stores are considered ready for distribution.
  • Be aware.


Incomplete or Inaccurate Metadata

  • This is about the meta data you put on the App Store Dashboard: app descriptions, screenshots, age ratings, payment options, and privacy information. The key is honest, sincere and transparent. Do not cheat.
  • Remember to upload screenshots for every screen size on the iPhone/ iPad. Do not use any other exotic template device (ex: Android) but an iPhone/iPad.
  • Do not mention any keywords about different platforms (ex: Android)


Low-Quality UI

  • Apple has provided a detailed description of how an app should be designed to comply with their platform (Human Interface Guidelines). 
  • A poor UI design that fails to meet standards may get rejected. 
  • Please make sure your app looks fantastic and consistent across all Apple devices.

Saturday, July 9, 2022

How to prevent wifi sleep after suspend for Ubuntu Linux

 1. Change power state of the wifi card to 3

```

$cat /etc/NetworkManager/conf.d/default-wifi-powersave-on.conf

[connection]

wifi.powersave = 3

# Slow sleep fix: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1670041

#wifi.powersave = 2

```

2. After saving the file run `sudo systemctl restart NetworkManager`

3. Make a reset bash script and name it `iwlwifi-reset`

```

#!/bin/sh


# NAME: /lib/systemd/system-sleep/iwlwifi-reset

# DESC: Resets Intel WiFi which can be flakey after a long suspend.

# DATE: Apr 1, 2017. Modified August 30, 2017.


MYNAME=$0


restart_wifi() {

    /usr/bin/logger $MYNAME 'restart_wifi BEGIN'

    /sbin/modprobe -v -r iwldvm # This removes iwlwifi too

    /sbin/modprobe -v iwlwifi   # This starts iwldvm too

#    systemctl restart NetworkManager.service

    /usr/bin/logger 'systemctl restart NetworkManager.service (SUPPRESSED)'

    /usr/bin/logger $MYNAME 'restart_wifi END'

}

/usr/bin/logger $MYNAME 'case=[' ${1}' ]'

case "${1}/${2}" in

    hibernate|suspend|pre*)

      ;;

    resume|thaw|post*)

      restart_wifi;;

esac

```

4. Copy the iwlwifi-reset script to systemd folder

```

sudo cp -r /path-to-iwlwifi/script /lib/systemd/system-sleep/

```

5. Set excute permission for the script

```

chmod a+x /lib/systemd/system-sleep/iwlwifi-reset

```

Sunday, July 3, 2022

Configure VPN L2TP/IPSec on Ubuntu for Ubuntu Linux


1. sudo apt-get install network-manager-l2tp

2. sudo apt-get install network-manager-l2tp-gnome

3. Settings > Network > Click on "+" > Then choose "Layer 2 Tunneling Protocol (L2TP)"

4. Input VPN name into "Name" textbox.

5. Input host name into "Gateway" textbox.

6. Input user name into "Username" textbox. 

7. Input password into "Username" textbox. 

8. Choose "IPSec Settings".

9. Tick "Enable IPsec tunnel to L2TP host" checkbox

10. Input shared secret into "Pre-shared key". textbox


Bonus:

sudo service xl2tpd stop

sudo systemctl disable xl2tpd