Skip to content

Commit

Permalink
Merge pull request #6 from mitwork/dev
Browse files Browse the repository at this point in the history
Provide check action for document service
  • Loading branch information
eudj1n committed Oct 13, 2023
2 parents 13a43e9 + 8277d86 commit 31dd8fd
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 18 deletions.
1 change: 0 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
push:
branches:
- main
- dev

jobs:
tests:
Expand Down
92 changes: 81 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,82 @@
# MITWORK Kalkan Laravel Package

---

![License:MIT](https://img.shields.io/badge/license-MIT-green.svg)
![Downloads](https://img.shields.io/github/downloads/mitwork/kalkan/total.svg)
[![Build Tests](https://github.com/mitwork/kalkan/actions/workflows/tests.yml/badge.svg)](https://github.com/mitwork/kalkan/actions/workflows/tests.yml/badge.svg)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/mitwork/kalkan)

---

Данная библиотека реализует следующие возможности:

- Подписание XML данных;
- Подписание бинарных данных (CMS);
- Проверка подписанных данных;
- QR-подписание.
- QR, cross-подписание.

Внешние зависимости:

- [NCALayer](https://ncl.pki.gov.kz/) - подписание данных на стороне клиента в браузере;
- [NCANode](https://v3.ncanode.kz/) - проверка, валидация и извлечение подписанных данных.

Для возможности QR и cross-подписания ваша информационная система должна быть подключена к услуге [Cервис QR подписания посредством приложения Egov Mobile](https://sb.egov.kz/smart-bridge/services/passport/NITEC-S-5096),
и внешний адрес (адреса) должны быть добавлены на стороне оператора услуги.

На этапе тестирования может понадобиться установить тестовые сборки приложений egov Mobile, egov Business - напрямую для OS Android,
либо с помощью [TestFlight](https://developer.apple.com/testflight/) по ссылке-приглашению оператора сервиса.

## Установка

Данный пакет устанавливается с помощью composer в существующий или новый [Laravel](https://laravel.com/)-проект командой:

```shell
composer require mitwork/kalkan
```

## Поддерживаемые версии

- PHP - 8.1, 8.2, 8.3;
- Laravel - 10.

## Настройка

Параметры `config/kalkan.php`:
Параметры задаются и/или переопределяются в файле `config/kalkan.php`:

```php
return [
'ncanode' => [
'host' => env('NCANODE_HOST', 'http://localhost:14579') // Хост для подключения к NCANode
'host' => env('NCANODE_HOST', 'http://localhost:14579'),
],
'links' => [
'prefix' => 'mobileSign:%s',
'person' => 'https://mgovsign.page.link/?link=%s&isi=1476128386&ibi=kz.egov.mobile&apn=kz.mobile.mgov',
'legal' => 'https://egovbusiness.page.link/?link=%s&isi=1597880144&ibi=kz.mobile.mgov.business&apn=kz.mobile.mgov.business'
]
'prefix' => 'mobileSign:',
'mobile' => 'https://mgovsign.page.link/?link=%s&isi=1476128386&ibi=kz.egov.mobile&apn=kz.mobile.mgov',
'business' => 'https://egovbusiness.page.link/?link=%s&isi=1597880144&ibi=kz.mobile.mgov.business&apn=kz.mobile.mgov.business',
],
'options' => [
'description' => 'Test',
'organisation' => [
'nameRu' => 'АО "ТЕСТ"',
'nameKz' => '"ТЕСТ" ЖК',
'nameEn' => 'OP "TEST"',
'bin' => '123456789012',
],
'ttl' => 180,
],
];
```

где:

- `ncanode.host` - адрес и порт для подключения к NCANode;
- `links.prefix` - префикс для формирования ссылки в QR-code;
- `links.mobile` - шаблон для формирования кросс-ссылки при подписании в приложении Egov Mobile;
- `links.business` - шаблон для формирования кросс-ссылки при подписании в приложении Egov Business;
- `options.description` - название информационной системы;
- `options.organisation` - сведения об организации;
- `options.ttl` - время жизни одноразовых ссылок (в секундах).

## Использование

### Подписание и проверка XML данных
Expand All @@ -43,7 +85,7 @@ return [
use \Mitwork\Kalkan\Services\KalkanSignatureService;
use \Mitwork\Kalkan\Services\KalkanValidationService;

class TestController extends Controller
class TestXmlController extends Controller
{
function __construct(
public KalkanSignatureService $signatureService,
Expand Down Expand Up @@ -88,7 +130,7 @@ use \Mitwork\Kalkan\Services\KalkanSignatureService;
use \Mitwork\Kalkan\Services\KalkanValidationService;
use \Mitwork\Kalkan\Services\KalkanExtractionService;
class TestController extends Controller
class TestCmsController extends Controller
{
function __construct(
public KalkanSignatureService $signatureService,
Expand All @@ -101,11 +143,11 @@ class TestController extends Controller
function testCmsSign(): string
{
$xml = 'base64...';
$data = 'base64...';
$key = 'base64...';
$password = 'password';
$result = $this->signatureService->signCms($xml, $key, $password);
$result = $this->signatureService->signCms($data, $key, $password);
// dd($result);
// base64...
Expand Down Expand Up @@ -140,6 +182,34 @@ class TestController extends Controller
}
```
### QR-подписание
Данный механизм позволяет подписывать данные с помощью смартфона с использованием приложений egov Mobile или egovBusiness,
когда проект открыт в браузере компьютера или планшета.
Основные шаги:
1) Подготовка документа - документ может быть считан из файловой системы, облачного хранилища или базы данных. В случае работы с бинарными (CMS) данными, файл необходимо преобразовать в текст с помощью функции `base64_encode`;
2) Формирование QR-кода;
3) Считывание QR-кода, подписание и возврат подписанных данных;
4) Обработка подписанных данных.
Пример реализации и использования можно посмотреть в [файле](tests/ApplicationTestingTest.php) теста.
### Кросс-подписание
Данный механизм позволяет подписывать данные с помощью смартфона с использованием приложений egov Mobile или egovBusiness,
когда проект (сайт) открыт на самом смартфоне.
Основные шаги:
1) Подготовка документа - документ может быть считан из файловой системы, облачного хранилища или базы данных. В случае работы с бинарными (CMS) данными, файл необходимо преобразовать в текст с помощью функции `base64_encode`;
2) Формирование кросс-ссылок для клиента;
3) Переход по кросс-ссылки, подписание и возврат подписанных данных;
4) Обработка подписанных данных.
Пример реализации и использования можно посмотреть в [файле](tests/ApplicationTestingTest.php) теста.
## Тестирование
Для запуска тестов необходимо выполнить команду:
Expand Down
3 changes: 3 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@

// Шаг 4 - Работа с данными - обработка
Route::put('/documents/content', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'processContent'])->name('process-content');

// Шаг 5 - Проверка статуса подписания документа
Route::get('/documents/check/{id}', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'check'])->name('check-document');
17 changes: 16 additions & 1 deletion src/Http/Controllers/DocumentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ public function store(StoreDocumentRequest $request): JsonResponse
],
],
]);

}

/**
Expand Down Expand Up @@ -168,6 +167,22 @@ public function processContent(ProcessDocumentRequest $request): JsonResponse
return response()->json([]);
}

/**
* Шаг 5 - Проверка статуса подписания документа
*
* @param int|string $id Идентификатор
*/
public function check(int|string $id): JsonResponse
{
$status = $this->documentService->checkDocument($id);

if (is_null($status)) {
return response()->json(['error' => 'Документ не найден', 'status' => $status], 404);
}

return response()->json(['status' => $status]);
}

/**
* Генерация временных ссылок
*
Expand Down
30 changes: 29 additions & 1 deletion src/Services/DocumentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,28 @@ public function getDocument(string|int $id): ?array
return Cache::get($id);
}

/**
* Проверка статус подписания документа
*
* @param string|int $id Идентификатор
* @return bool|null Результат
*/
public function checkDocument(string|int $id): ?bool
{
$document = Cache::get($id);

if (! $document) {
return null;
}

return isset($document['status']) && $document['status'] === true;
}

/**
* Обработка документа
*
* @param string|int $id Идентификатор
* @return bool Статус обработки
*/
public function processDocument(string|int $id): bool
{
Expand All @@ -193,6 +213,14 @@ public function processDocument(string|int $id): bool
unset($this->documents['xml'][$id]);
}

return Cache::forget($id);
$document = Cache::get($id);

if (! $document) {
return false;
}

$document['status'] = true;

return Cache::put($id, $document);
}
}
46 changes: 42 additions & 4 deletions tests/ApplicationTestingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ public function testSingleCmsSigning(): void
];

$response = $this->prepareDocument($data, $certificate['title']);

$message = $response['message'];
$id = $response['id'];

$signatureService = new \Mitwork\Kalkan\Services\KalkanSignatureService();

Expand All @@ -54,11 +56,19 @@ public function testSingleCmsSigning(): void
}
}

// Send signed data
// Отправка подписанных данных

$response = $this->put($response['link'], $message);

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка обработки подписанных документов: %s', $certificate['title'], $response->getContent()));

// Проверка статуса после подписания

$response = $this->get(route('check-document', $id));

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка получения статуса документа %s: %s', $id, $certificate['title'], $response->getContent()));
$this->assertArrayHasKey('status', $response, sprintf('[%s] Ответ не содержит статус документа %s: %s', $id, $certificate['title'], $response->getContent()));
$this->assertTrue($response['status'], sprintf('[%s] Некорректный статус для подписанного документа %s: %s', $id, $certificate['title'], $response->getContent()));
}
}

Expand All @@ -79,7 +89,9 @@ public function testMultiCmsSigning(): void
];

$response = $this->prepareDocument($data, 'CMS Multi');

$message = $response['message'];
$id = $response['id'];

$signatureService = new \Mitwork\Kalkan\Services\KalkanSignatureService();

Expand All @@ -94,12 +106,19 @@ public function testMultiCmsSigning(): void
}
}

// Send signed data
// Отправка подписанных данных

$response = $this->put($response['link'], $message);

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка обработки подписанных документов: %s', 'CMS Multi', $response->getContent()));

// Проверка статуса после подписания

$response = $this->get(route('check-document', $id));

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка получения статуса документа %s: %s', $id, 'CMS Multi', $response->getContent()));
$this->assertArrayHasKey('status', $response, sprintf('[%s] Ответ не содержит статус документа %s: %s', $id, 'CMS Multi', $response->getContent()));
$this->assertTrue($response['status'], sprintf('[%s] Некорректный статус для подписанного документа %s: %s', $id, 'CMS Multi', $response->getContent()));

}

public function testSingleXmlSigning(): void
Expand All @@ -126,7 +145,9 @@ public function testSingleXmlSigning(): void
];

$response = $this->prepareDocument($data, $certificate['title']);

$message = $response['message'];
$id = $response['id'];

$signatureService = new \Mitwork\Kalkan\Services\KalkanSignatureService();

Expand All @@ -139,11 +160,19 @@ public function testSingleXmlSigning(): void
}
}

// Send signed data
// Отправка подписанных данных

$response = $this->put($response['link'], $message);

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка обработки подписанных документов: %s', $certificate['title'], $response->getContent()));

// Проверка статуса после подписания

$response = $this->get(route('check-document', $id));

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка получения статуса документа %s: %s', $id, $certificate['title'], $response->getContent()));
$this->assertArrayHasKey('status', $response, sprintf('[%s] Ответ не содержит статус документа %s: %s', $id, $certificate['title'], $response->getContent()));
$this->assertTrue($response['status'], sprintf('[%s] Некорректный статус для подписанного документа %s: %s', $id, $certificate['title'], $response->getContent()));
}
}

Expand All @@ -163,6 +192,14 @@ private function prepareDocument(array $data, string $prefix): array

$id = $response['id'];

// Проверка статуса после подписания

$response = $this->get(route('check-document', $id));

$this->assertTrue($response->isOk(), sprintf('[%s] Ошибка получения статуса документа %s: %s', $id, $prefix, $response->getContent()));
$this->assertArrayHasKey('status', $response, sprintf('[%s] Ответ не содержит статус документа %s: %s', $id, $prefix, $response->getContent()));
$this->assertFalse($response['status'], sprintf('[%s] Некорректный статус для неподписанного документа %s: %s', $id, $prefix, $response->getContent()));

$response = $this->get(route('generate-cross-link', ['id' => $id]));

$this->assertTrue($response->isOk(), sprintf('[%s] Некорректный ответ при формировании cross-ссылок', $prefix));
Expand All @@ -186,6 +223,7 @@ private function prepareDocument(array $data, string $prefix): array
$this->assertTrue($response->isOk(), sprintf('[%s] Отсутствует ссылка на документ', $prefix));

return [
'id' => $id,
'message' => (array) $response->original,
'link' => $link,
];
Expand Down

0 comments on commit 31dd8fd

Please sign in to comment.