Skip to content

Commit

Permalink
feat: add encrypted storage
Browse files Browse the repository at this point in the history
  • Loading branch information
nesquikm committed Oct 25, 2023
1 parent 61232e9 commit 1aeddfd
Show file tree
Hide file tree
Showing 23 changed files with 1,795 additions and 3 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/features/library/tome_library/tome_library.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

114 changes: 114 additions & 0 deletions packages/encrypted_storage/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 2023-08-30

### Changes

---

Packages with breaking changes:

- There are no breaking changes in this release.

Packages with other changes:

- [`encrypted_storage` - `v0.1.2`](#encrypted_storage---v012)

---

#### `encrypted_storage` - `v0.1.2`

- **FIX**: flutter test concurrency (#6).
- **FEAT**: use flutter templates repository (#9).
- **DOCS**: add package description (#3).

## 0.1.2

- **FIX**: flutter test concurrency (#6).
- **FEAT**: use flutter templates repository (#9).
- **DOCS**: add package description (#3).


## 2023-08-22

### Changes

---

Packages with breaking changes:

- There are no breaking changes in this release.

Packages with other changes:

- [`encrypted_storage` - `v0.1.1`](#encrypted_storage---v011)

---

#### `encrypted_storage` - `v0.1.1`

- **FIX**: flutter test concurrency (#6).
- **FEAT**: use flutter templates repository (#9).
- **DOCS**: add package description (#3).

## 0.1.1

- **FIX**: flutter test concurrency (#6).
- **FEAT**: use flutter templates repository (#9).
- **DOCS**: add package description (#3).


## 2023-07-06

### Changes

---

Packages with breaking changes:

- There are no breaking changes in this release.

Packages with other changes:

- [`encrypted_storage` - `v0.1.0+2`](#encrypted_storage---v0102)

Packages graduated to a stable release (see pre-releases prior to the stable version for changelog entries):

- `encrypted_storage` - `v0.1.0+2`

---

#### `encrypted_storage` - `v0.1.0+2`

## 0.1.0+2

- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.


## 2023-06-15

### Changes

---

Packages with breaking changes:

- There are no breaking changes in this release.

Packages with other changes:

- [`encrypted_storage` - `v0.1.0-dev.0+2`](#encrypted_storage---v010-dev02)

---

#### `encrypted_storage` - `v0.1.0-dev.0+2`

- **DOCS**: add package description (#3).

## 0.1.0-dev.0+2

- **DOCS**: add package description (#3).

102 changes: 102 additions & 0 deletions packages/encrypted_storage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Encrypted Storage

[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link]
[![License: AGPLv3][license_badge]][license_link]

This package provides a fast and simple way to store and retrieve encrypted data usind [sqflite][sqflite_link]. It uses AES encryption via [encrypt][encrypt_link] to encrypt the data and [flutter_secure_storage][flutter_secure_storage_link] to store key and initialization vector.

Check warning on line 6 in packages/encrypted_storage/README.md

View workflow job for this annotation

GitHub Actions / spell-check / build

Unknown word (usind)

Check warning on line 6 in packages/encrypted_storage/README.md

View workflow job for this annotation

GitHub Actions / spell-check / build

Unknown word (sqflite)

## Installation 💻

**❗ In order to start using Encrypted Storage you must have the [Flutter SDK][flutter_install_link] installed on your machine.**

Add [encrypted_storage][pubdev_link] to your `pubspec.yaml`:

```yaml
dependencies:
encrypted_storage:
```
## Melos magic 🪄
Using [melos](https://melos.invertase.dev/) makes it very easy to work with the project, so enjoy.
You can run any job interactively run running `melos run` and selecting needed case or directly (e.g. `melos run test`).

### Bootstrap 🏁

Melos takes care about dependencies of all packages, including managing of local-generated library version. So, just run:

```
melos bs
```

### Codegen 🦾

This thing will run all code generators for all packages:

```
$ melos run codegen
```

### Clean up 🧹

Just run commands below to clean all, including build directories and flutter projects.

```
melos clean
```
### Tests ✔️
You can run all tests at one by running this command.
```
melos run test
```
### Code 📊
You can run code analysis:
```
melos run analyze
```
### Code format 🗃️
`melos run check-format` will check, `melos run format` will fix dart code formatting.
```
melos run check-format
melos run format
```
### Prepare to commit 🤝🏻
`melos run check-all` will ckeck, analyze and run all tests.

Check warning on line 76 in packages/encrypted_storage/README.md

View workflow job for this annotation

GitHub Actions / spell-check / build

Unknown word (ckeck)
```
melos run check-all
```
## Conventional Commits ❤️
[This magic](https://melos.invertase.dev/guides/automated-releases#versioning) will update version and build our library automatically using commit messages and tags. [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) is a lightweight convention on top of commit messages.
## Version 🏷️
Package version control is done by melos. It runs by gh action 'Create version PR' ```melos version -a --yes```.
## Github Secrets 🔑

Check warning on line 90 in packages/encrypted_storage/README.md

View workflow job for this annotation

GitHub Actions / spell-check / build

Unknown word (Github)
`BOT_ACCESS_TOKEN`: Personal access token (PAT) used to fetch the repository. We should use PAT and not default GITHUB_TOKEN because ["When you use the repository's GITHUB_TOKEN to perform tasks, events triggered by the GITHUB_TOKEN, with the exception of workflow_dispatch and repository_dispatch, will not create a new workflow run"](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow). We want to trigger a workflow from the workflow (to run tests), so we need to use PAT. This thing is used in `version` workflow.
[flutter_install_link]: https://docs.flutter.dev/get-started/install
[license_badge]: https://img.shields.io/badge/license-AGPLv3-blue.svg
[license_link]: https://opensource.org/license/agpl-v3/
[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg
[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis
[flutter_secure_storage_link]: https://pub.dev/packages/flutter_secure_storage
[sqflite_link]: https://pub.dev/packages/sqflite
[encrypt_link]: https://pub.dev/packages/encrypt
[pubdev_link]: https://pub.dev/packages/encrypted_storage
1 change: 1 addition & 0 deletions packages/encrypted_storage/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: ../../analysis_options.yaml
5 changes: 5 additions & 0 deletions packages/encrypted_storage/lib/encrypted_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Encrypted storage
library encrypted_storage;

export 'src/abstract_storage.dart';
export 'src/encrypted_storage.dart';
65 changes: 65 additions & 0 deletions packages/encrypted_storage/lib/src/abstract_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import 'dart:async';

/// Default domain name
const String defaultDomain = 'default';

/// {@template storage}
/// AbstractStorage: storage interface
/// {@endtemplate}
abstract class AbstractStorage {
/// Clear storage: all records
Future<void> clearAll();

/// Clear storage: all records in one domain
Future<void> clearDomain([String? domain = defaultDomain]);

/// Write the key-value pair. [value] will be written for the [key] in
/// [domain].
/// If the pair was already existed it will be overwritten if [overwrite]
/// is true (by default)
Future<void> set(
String key,
String value, {
String domain = defaultDomain,
bool overwrite = true,
});

/// Write the key-value pair map. [pairs] will be written in [domain].
/// If the pair was already existed it will be overwritten if [overwrite]
/// is true (by default). Unspecified in [pairs] in db will not be altered
/// or deleted.
Future<void> setDomain(
Map<String, String> pairs, {
String domain = defaultDomain,
bool overwrite = true,
});

/// Delete by [key] from [domain].
Future<void> delete(
String key, {
String domain = defaultDomain,
});

/// Delete by [keys] from [domain].
Future<void> deleteDomain(
List<String> keys, {
String domain = defaultDomain,
});

/// Get value by [key] and [domain]. If not found will return [defaultValue]
Future<String?> get(
String key, {
String? defaultValue,
String domain = defaultDomain,
});

/// Get key-value pair map from [domain].
Future<Map<String, String>> getDomain({
String domain = defaultDomain,
});

/// Get keys from [domain]
Future<List<String>> getDomainKeys({
String domain = defaultDomain,
});
}
69 changes: 69 additions & 0 deletions packages/encrypted_storage/lib/src/cipher_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:encrypt/encrypt.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

const _keyLength = 32;
const _ivLength = 16;

/// {@template ciper_storage}
/// Ciper storage
/// {@endtemplate}
class CipherStorage {
/// {@macro ciper_storage}
CipherStorage();

static const String _keyKey = 'cipher_storage_key';
static const String _ivKey = 'cipher_storage_iv';
late FlutterSecureStorage _storage;
late final Key _key;
late final IV _iv;

/// Init ciper storage
Future<void> init() async {
_storage = FlutterSecureStorage(aOptions: _getAndroidOptions());

final rows = await _storage.readAll();
final key = rows[_keyKey];
final iv = rows[_ivKey];

if (key != null && iv != null) {
_key = keyFromBase64(key);
_iv = ivFromBase64(iv);

return;
}

if ((key == null && iv != null) || (key != null && iv == null)) {
throw StateError(
'key and iv reading error: one of them is null while another is not',
);
}

_key = keyFromSecureRandom();
_iv = ivFromSecureRandom();

await _storage.write(key: _keyKey, value: _key.base64);
await _storage.write(key: _ivKey, value: _iv.base64);
}

/// Get key
Key get key => _key;

/// Get initialization vector
IV get iv => _iv;

AndroidOptions _getAndroidOptions() => const AndroidOptions(
encryptedSharedPreferences: true,
);

/// Generate key from base64
static Key keyFromBase64(String key) => Key.fromBase64(key);

/// Generate initialization vector from base64
static IV ivFromBase64(String iv) => IV.fromBase64(iv);

/// Generate a new key
static Key keyFromSecureRandom() => Key.fromSecureRandom(_keyLength);

/// Generate a new initialization vector
static IV ivFromSecureRandom() => IV.fromSecureRandom(_ivLength);
}
Loading

0 comments on commit 1aeddfd

Please sign in to comment.