Шифруем данные в приложении 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

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

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

Создание мультиязычного приложения NativeScript

Для недавнего проекта мне понадобилось решение для мгновенного переключения языка с Нидерландского на Английский.

В одном концепте на NativeScript я разработал собственное решение на чистом JavaScript с Jed. Оно работало, но было далеко не идеальным.
После этого я решил создать приложение на NativeScript с Angular (2+) и начал поиск существующих библиотек локализации для Angular. Лучшим решением оказалась библиотека ng-translate от Olivier Combe.

В Angular она завелась с полпинка, а вот заставить её работать в NativeScript стоило мне много крови и пота. Но благодаря сообществу вокруг NativeScript и персонально Nathan Walker, мне удалось это сделать. И, в принципе, это было не так сложно.

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

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

С помощью следующих команд мы создадим новый проект и добавим в него платформы Android и iOS.

tns create projectname --ng
cd projectname
tns platform add android
tns platform add ios

2. Установка ng2-translate

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

3. Создание языковых файлов

Создадим папку i18n в папке app нашего проекта и добавим файлы nl.json и en.json.
nl.json
{
"EXAMPLE": {
"TITLE": "Hallo wereld!",
"TEXT": "Dit is een zin in het Nederlands.",
"BACK": "Terug"
}
}

en.json
{
"EXAMPLE": {
"TITLE": "Hello world!",
"TEXT": "This is a sentence in English.",
"BACK": "Back"
}
}

4. Отредактируем файл app.module.ts

Здесь нам нужно импортировать следующие модули:
import {NativeScriptHttpModule} from "nativescript-angular/http";
import {TranslateModule, TranslateLoader, TranslateStaticLoader} from "ng2-translate";
import {Http} from "@angular/http";

NativeScript использует AOT компиляцию, поэтому нам нужно экспортировать функцию, которая возвращает TranslateStaticLoader.
// for AoT compilation
export function translateLoaderFactory(http: Http) {
return new TranslateStaticLoader(http, "/i18n", ".json");
};

Также нам нужно расширить импорты @NgModule:
NativeScriptHttpModule,
TranslateModule.forRoot([{
provide: TranslateLoader,
deps: [Http],
useFactory: (translateLoaderFactory)}])

5. Отредактируем app.component.html

Замените содержитое файла app.component.html следующей разметкой.
С помощью неё мы привязываем EXAMPLE.TITLE к тексту в ActionBar, компоненту Label и содержимому TextView.
Также у нас есть кнопки для переключения между Нидерландским и Английским языками. Эти кнопки вызывают функцию changeLanguage при нажатии.








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

Сначала нам нужно импортировать следующие модули:
import * as Platform from "platform";
import {TranslateService} from 'ng2-translate';

При инициализации мы установим язык по-умолчанию в Нидерландский.
После этого изменим язык, основываясь на предпочитаемом языке на устройстве. В случае, если для такого языка у нас нет файла локализации, ng2-translate вернёт язык по-умолчанию.
constructor(private translate: TranslateService) {
this.translate.setDefaultLang("nl");
this.translate.use(Platform.device.language);
}

Также нам нужна функция для переключения языков:
public changeLanguage(lang: string) {
this.translate.use(lang);
}

Готово! За шесть простых шагов мы создали мультиязычное приложение на NativeScript!

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

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

Создание мультиязычного приложения NativeScript

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

Автоматическая установка фото профиля в приложении NativeScript Angular

Как превратить просто хорошее мобильное приложение в отличное мобильное приложение? К примеру, что вы выберете: экран входа в приложение с запросом только логина и пароля или лучше добавить туда фото пользователя?
С помощью сервиса Gravatar вы можете получить аватарку по email адресу пользователя, если он загрузил её туда.
Мы увидим как автоматически установить аватарку в приложении на базе NativeScript Angular с помощью API сервиса Gravatar.

Наша цель — сделать приложение более запоминающимся для пользователя.

Создаём новый проект NativeScript Angular

Для лучшего понимания создадим проект приложения NativeScript с нуля для платформ Android и iOS, в котором будем использовать Angular и TypeScript.
В командной строке (в Windows) или в окне терминала (в Linux и Mac) выполните следующие команды (перед этим убедитесь, что у вас установлен NativeScript):
tns create GravatarProject --ng
cd GravatarProject
tns platform add ios
tns platform add android

Для разработки приложений под iOS обязательно нужно иметь Mac с установленным Xcode!
Gravatar API требует хеширования email адреса алгоритмом MD5 перед отправкой их на сервис с помощью HTTP запроса. В JavaScript нет встроенной функции для этого, поэтому установим необходимую библиотеку.
Для этого выполним следующую команду:
npm install blueimp-md5 --save
Этот код установит JavaScript библиотеку blueimp MD5.

Создание логики на TypeScript для использования Gravatar

Цель нашего алгоритма — захешировать email и отправить его в Gravatar в надежде получить от него картинку. Мы не будем делать запросы Angular HTTP из-за формата API.
Пример файла app/app.component.ts:
import { Component } from "@angular/core";
var MD5 = require("blueimp-md5");

@Component({
selector: "my-app",
templateUrl: "app.component.html"
})
export class AppComponent {

public picture: string;
public email: string;

public constructor() {
this.email = "";
this.picture = "https://www.gravatar.com/avatar/00000000000000000000000000000000?s=150";
}

public getProfilePicture(email: any) {
if(this.validateEmail(email)) {
this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
}
}

// Taken from http://stackoverflow.com/a/46181/498479
private validateEmail(email: any) {
let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}

}
Здесь не так много кода, но мы всё равно рассмотрим его более подробно.

После импорта компонентов Angular и MD5, мы создаём класс AppComponent. В этом классе есть две public переменных, одна из которых будет содержать ссылку на изображение из Gravatar, будь это реальная картинка или картинка по-умолчанию, а в другой будем хранить текущий email адрес.
В методе constructor мы инициализируем эти переменные. В переменной picture сначала будет ссылка на шаблон изображения Gravatar.
Обратите внимание на метод validateEmail. Я взял его на Stack Overflow. Он проверяет валидность email адреса с помощью регулярного выражения. С помощью этого метода мы уменьшим трафик и будем посылать в Gravatar только корректные адреса почты.
public getProfilePicture(email: any) {
if(this.validateEmail(email)) {
this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
}
}

В методе getProfilePicture мы передаём валидный email, хешированный алгоритмом MD5 в Gravatar. Если такого адреса в базе не существует, мы получим обратно картинку по-умолчанию, в противном случае нам вернётся реальная аватарка.
В этом проекте мы используем форму ввода для email адреса, но по-умолчанию к ней нет привязок в Angular. Нам необходимо подключить модуль форм, чтобы сделать привязку.
Откроем файл проекта app/app.module.ts и вставим в него следующий код:
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/platform";
import { NativeScriptFormsModule } from "nativescript-angular/forms";

import { AppComponent } from "./app.component";

@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
imports: [NativeScriptModule, NativeScriptFormsModule],
schemas: [NO_ERRORS_SCHEMA]
})
export class AppModule { }

В нём мы импортируем модуль NativeScriptFormsModule и добавляем в массив imports в блоке @NgModule.
Код не очень простой, зато хорошо работает. Ещё бы добавить немного анимации.

Включение анимационных переходов и состояний Angular

Есть несколько способов добавить анимацию в приложение NativeScript, но для лучшего контроля мы будем использовать анимации Angular. Эти анимации пропишем в нашем коде на TypeScript.
Откроем файл проекта app/app.component.ts и добавим следующий код в блок @Component:
@Component({
selector: "my-app",
templateUrl: "app.component.html",
animations: [
trigger("state", [
transition("void => *", [
animate(200, style({
transform: 'scale(2, 2)'
})),
]),
transition("* => *", [
animate(500, keyframes([
style({ transform: 'scale(2, 2)' }),
style({ transform: 'scale(0, 0)' }),
style({ transform: 'scale(2, 2)' }),
]))
]),
])
]
})

В нём мы прописываем набор анимаций, называем его state хотя состояний в нём нет, только инструкции анимационных переходов.
Если компонент — void, или, другими словами, не отображается на экране, а состояние компонента меняется, то он будет увеличен на 200% в течение 200 миллисекунд. Если состояние изменится на что-то другое, нежели void, мы увидим keyframe-анимацию. В ней элемент масштабируется с 200% до 0% и обратно до 200% в течение 500 миллимекунд. Анимация будет выглядеть как пульсация.
Чтобы изменить первоначальные состояния, нам нужно создать булеву или любую другую переменную для представления текущего состояния:
public currentState: boolean;
С помощью метода constructor мы можем инициализировать и установить эту переменную в false. А когда будет введён корректный email, мы изменим состояние и тип анимации.
Файл app/app.component.ts полностью будет таким:
import { Component, trigger, state, transition, animate, style, keyframes } from "@angular/core";
var MD5 = require("blueimp-md5");

@Component({
selector: "my-app",
templateUrl: "app.component.html",
animations: [
trigger("state", [
transition("void => *", [
animate(200, style({
transform: 'scale(2, 2)'
})),
]),
transition("* => *", [
animate(500, keyframes([
style({ transform: 'scale(2, 2)' }),
style({ transform: 'scale(0, 0)' }),
style({ transform: 'scale(2, 2)' }),
]))
]),
])
]
})
export class AppComponent {

public picture: any;
public email: string;
public currentState: boolean;

public constructor() {
this.email = "";
this.picture = "https://www.gravatar.com/avatar/00000000000000000000000000000000?s=150";
this.currentState = false;
}

public getProfilePicture(email: any) {
if(this.validateEmail(email)) {
this.currentState = !this.currentState;
this.picture = "https://www.gravatar.com/avatar/" + MD5(email) + "?s=150";
}
}

// Taken from http://stackoverflow.com/a/46181/498479
private validateEmail(email: any) {
let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}

}
Нам остаётся создать представление на XML и CSS.

Создание приятного интерфейса в NativeScript

Основным интерфейсом будет экран с двумя секциями по вертикали. В верхней секции будет аватарка, а в нижней — форма ввода адреса.
Откроем файл app/app.component.html и вставим в него такую разметку XML:













GridLayout позволяет нам разделить экран на две одинаковые секции.
В первом ряду будет наше изображение в переменной picture на языке TypeScript. Чанк [@state] это состояние state анимации и содержит текущее её состояние. Как только это состояние меняется, переклчается и анимация.
Во втором ряду расположена форма с несколькими полями ввода. Первое поле привязано к нашей переменной email и как только меняется её содержимое, данные передаются в метод getProfilePicture.
Зададим свои стили для полей ввода в файле app/app.css:
.form .input-field .input {
padding: 5;
background-color: #F0F0F0;
}

@import 'nativescript-theme-core/css/core.light.css';
В этом CSS добавлен отступ и фон для всех полей ввода текста.

Готово! Мы сделали простое приложение с автоматической подгрузкой аватарки пользователя и её анимацией.

*Оригинал взят у Nic Raboy

Автоматическая установка фото профиля в приложении NativeScript Angular

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

Adblock detector