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

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

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

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

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

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

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

Так как NativeScript кроссплатформен, вы так же можете писать под . Просто используйте специфичные для него команды. Вместо «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, в котором отображаются имена и зашифрованные кодовые имена каждого президента. При нажатии на президента в списке, отображается расшифрованное кодовое имя.
<StackLayout>
    <StackLayout>
        <Label text="{{header}}"></Label>
        <Button text="Load & save" (tap)="loadSaveData()"></Button>
        <Button text="Delete all" (tap)="deleteData()"></Button>
    </StackLayout>
    <ListView [items]="presidentList" (itemTap)="showCodeName($event)" height="300">
        <template let-item="item">
            <StackLayout style="padding: 10">
                <Label [text]="item.name"></Label>
                <Label [text]="item.codename"></Label>
            </StackLayout>
        </template>
    </ListView>
</StackLayout>


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

Поскольку мы используем Angular, нужно добавить строку в файл references.d.ts. Она добавляет определение типов для этого плагина. Определения типов нужны для проверки типов, автодополнения кода и документации в IDE.
/// <reference path="./node_modules/nativescript-couchbase/couchbase.d.ts" /> 


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
0 комментариев
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.