Шифруем данные в приложении NativeScript и храним их в Couchbase

Сегодня мы рассмотрим как шифровать важные данные с помощью CryptoJS и сохранить их в
базу Couchbase Mobile на устройстве.

Couchbase Mobile это встраиваемая NoSQL база данных для мобильных устройств. Она часто используется как замена SQLite.

Программа в примере чисто гипотетически может даже быть использована Секретной Службой США, так как она безопасно хранит кодовые имена [бывших] американских президентов.

Чтобы работать с базой данных Couchbase Mobile, мы будем использовать плагин NativeScript Couchbase, созданный Nic Raboy.

С CryptoJS возможна работа с различными алгоритмами шифрования. Мы будем использовать алгоритм шифрования AES-256, используемый АНБ для суперсекретной информации.

Разрабатывать приложение будем с помощью NativeScript и Angular под iOS, это мой любимый инструментарий разработки {N} приложений.

Так как NativeScript кроссплатформен, вы так же можете писать под Android. Просто используйте специфичные для него команды. Вместо «ios» пишите «android» и у вас всё получится! 😉

Вы можете выполнить описанное ниже или же просто скачать готовый пример NSNL_Couchbase с GitHub.

1. Создание приложения на NativeScript и Angular

С помощью следующих команд мы создадим новый проект и добавим в него платформу iOS:
tns create projectname --ng
cd projectname
tns platform add ios

2. Установка crypto-js

crypto-js это пакет npm, поэтому он устанавливается стандартно:
npm install crypto-js --save

3. Установка плагина couchbase

Couchbase Mobile это плагин NativeScript, поэтому он устанавливается стандартно:
tns plugin add nativescript-couchbase

4. Сборка проекта

После установки плагина обязательно пересобирайте проект:
tns build ios

5. Запуск приложения

Давайте запустим наше приложение и проверим возможные ошибки:
tns run ios
Если у вас будут подобные ошибки, перезапустите компьютер и вернитесь к шагу 4:
Error: Uncaught (in promise): ReferenceError: Can't find variable: CBLManager

6. Редактируем app.component.ts

Давайте заменим стандартный код на наш.
Сверху у нас будет label, показывающий сколько документов хранится в нашей базе данных.
Ниже идут две кнопки: одна для загрузки нескольких президентов в программу с сохранением их в базу и другая для удаления всех из программы и базы данных.
И, наконец, идёт список list-view, в котором отображаются имена и зашифрованные кодовые имена каждого президента. При нажатии на президента в списке, отображается расшифрованное кодовое имя.









7. Редактируем references.d.ts

Поскольку мы используем Angular, нужно добавить строку в файл references.d.ts. Она добавляет определение типов для этого плагина. Определения типов нужны для проверки типов, автодополнения кода и документации в IDE.
///

8. Редактируем app.component.ts

Нам нужно импортировать модуль Couchbase и библиотеку CryptoJS:
import {Couchbase} from "nativescript-couchbase";
let CryptoJS = require("crypto-js");

Теперь удалим переменную-счётчик и функции message() и onTap() из класса AppComponent и заменим их следующим кодом:
private database: Couchbase;
private header: string = 'No documents found!';
private presidentList = [];
readonly VERY_SECRET_CODE: string = 'My very secret code';

Мы задали базу данных, заголовок с текстом, массив для показа президентов в списке и VERY_SECRET_CODE как ключ шифрования.

Внимание:
В настоящей программе никогда не храните в коде ключ шифрования. Более грамотно будет дать пользователю возможность вводить свою фразу или цифровой код (но не забудьте его преобразовать в строку методом .toString(), потому как фраза должна быть строкой!). Затем вы будете использовать эту фразу или код каждый раз при шифровании/дешифровке данных.

А теперь добавим конструктор класса, в нём прокомментирована каждая строка:
public constructor() {
// откроем или создадаим базу данных
this.database = new Couchbase("sampledb");
// нам необходим view для хранения и извлечения данных
this.database.createView("sampledata", "1", function (document, emitter) {
emitter.emit(document._id, document);
});

// извлечём документы в этот view
let documents = this.database.executeQuery("sampledata");
// первый документ доступен?
if (documents[0]) {
// показать количество документов в заголовке
this.header = 'Found ' + (documents.length) + ' documents!';
// пройдёмся по всем документам
for (let i = 0; i < documents.length; i++) { // и добавим каждый документ в список this.presidentList.push(documents[i]); } } }

Добавим два частных метода для шифрования и расшифровки данных:
private _encryptData(data: string): string {
// используем шифрование AES-256 -> очень безопасное
let cipherText = CryptoJS.AES.encrypt(data, this.VERY_SECRET_CODE);
return cipherText;
}

private _decryptData(data: string): string {
// сначала расшифруем в байты
let bytes = CryptoJS.AES.decrypt(data.toString(), this.VERY_SECRET_CODE);
// преобразуем байты в текст
let plainText = bytes.toString(CryptoJS.enc.Utf8);
return plainText;
}

И добавим метод loadSaveData() для кнопки "Load & save":
public loadSaveData() {
// зашифруем кодовое имя
let encryptedCodeName: string = this._encryptData('Renegade');
// создадим строку JSON
let president:string = '{"name": "Barack Obama", "codename": "' + encryptedCodeName + '"}';
// сконвертируем в объект JSON
let presidentObj: any = JSON.parse(president);
// создадим новый документ
this.database.createDocument(presidentObj);

// создадим документ для каждого президента
this.database.createDocument(JSON.parse('{"name": "George W. Bush", "codename": "' + this._encryptData('Trailblazer') + '"}'));
this.database.createDocument(JSON.parse('{"name": "Bill Clinton", "codename": "' + this._encryptData('Eagle') + '"}'));
this.database.createDocument(JSON.parse('{"name": "Ronald Reagan", "codename": "' + this._encryptData('Rawhide') + '"}'));

// извлечём документы в наш view
let documents = this.database.executeQuery("sampledata");

// отобразим количество документов в заголовке
this.header = 'Found ' + (documents.length) + ' documents!';

// цикл по всем документам
for (let i = 0; i < documents.length; i++) { // добавим каждый документ в список this.presidentList.push(documents[i]); } }

Внимание:
В настоящей программе никогда так не загружайте данные в базу, здесь кодовые имена жестко прописаны в коде программы. Лучше всего создать форму для ввода данных пользователем или создать безопасный REST API для загрузки данных с доверенного сервера.

Теперь добавим метод deleteData() для кнопки "Delete all":
public deleteData() {
// извлечём документы в этот view
let documents = this.database.executeQuery("sampledata");

// цикл по всем документам
for (let i = 0; i < documents.length; i++) { // удалим каждый документ // couchbase присвоит id (_id) документу при создании this.database.deleteDocument(documents[i]._id); } // очистим массив с президентами, это удалит их из listview this.presidentList = []; // изменим заголовок this.header = 'All documents are deleted!'; }

И, наконец, удостоверимся, что показываем расшифрованное кодовое имя для выбранного президента.
public showCodeName(event) {
// event содержит индекс нажатого элемента
// по этому индексу мы извлекаем зашифрованное кодовое имя и расшифровываем его
alert(this._decryptData(this.presidentList[event.index].codename));
}

Рекомендую посмотреть более расширенный пример NSNL_Couchbase на GitHub, в котором также используется Angular routing.

* Оригинал взят у NativeScript.nl

Leave a Comment