Skip to content

Commit

Permalink
Update tests and project structure
Browse files Browse the repository at this point in the history
  • Loading branch information
eudj1n committed Oct 13, 2023
1 parent a12fe9b commit 38f86e1
Show file tree
Hide file tree
Showing 25 changed files with 727 additions and 282 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,5 @@ class TestController extends Controller
**Важно** - в тестах используются тестовые сертификаты из [SDK](https://pki.gov.kz/get-sdk/) НУЦ РК, для проверки необходимо запустить NCANode со следующими параметрами:
```shell
NCANODE_DEBUG=true NCANODE_CRL_URL=http://test.pki.gov.kz/crl/nca_gost2022_test.crl NCANODE_CA_URL="http://test.pki.gov.kz/cert/nca_gost2022_test.cer http://test.pki.gov.kz/cert/root_test_gost_2022.cer" NCANODE_OCSP_URL=http://test.pki.gov.kz/ocsp/ NCANODE_TSP_URL=http://test.pki.gov.kz/tsp/ java -jar NCANode.jar
NCANODE_DEBUG=true NCANODE_CRL_URL="http://test.pki.gov.kz/crl/nca_rsa_test.crl http://test.pki.gov.kz/crl/nca_gost_test.crl http://test.pki.gov.kz/crl/nca_gost_test_2022.crl" NCANODE_CRL_DELTA_URL="http://test.pki.gov.kz/crl/nca_d_rsa_test.crl http://test.pki.gov.kz/crl/nca_d_gost_test.crl http://test.pki.gov.kz/crl/nca_d_gost_test_2022.crl" NCANODE_CA_URL="http://test.pki.gov.kz/cert/root_gost_test.cer http://test.pki.gov.kz/cert/root_rsa_test.cer http://test.pki.gov.kz/cert/root_test_gost_2022.cer http://test.pki.gov.kz/cert/nca_gost_test.cer http://test.pki.gov.kz/cert/nca_rsa_test.cer http://test.pki.gov.kz/cert/nca_gost2022_test.cer" NCANODE_OCSP_URL=http://test.pki.gov.kz/ocsp/ NCANODE_TSP_URL=http://test.pki.gov.kz/tsp/ java -jar NCANode-3.2.3.jar
```
8 changes: 7 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@
"laravel/pint": "^1.13",
"orchestra/testbench": "^8.13",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.4"
"phpunit/phpunit": "^10.4",
"symfony/yaml": "^6.3"
},
"autoload": {
"psr-4": {
"Mitwork\\Kalkan\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Mitwork\\Kalkan\\Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
Expand Down
15 changes: 9 additions & 6 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
use Illuminate\Support\Facades\Route;

// Шаг 1 - Сохранение документа
Route::post('/documents', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'store'])->name('store-document');
Route::post('/documents', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'store'])->name('store-document');

// Шаг 1.1 - Генерация QR-кода
Route::get('/documents/generate-qr-code', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateQrCode'])->name('generate-qr-code');
Route::get('/documents/generate-qr-code', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'generateQrCode'])->name('generate-qr-code');

// Щаг 1.2 - Генерация кросс-ссылок
Route::get('/documents/generate-cross-link', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateCrossLink'])->name('generate-cross-link');
Route::get('/documents/generate-cross-link', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'generateCrossLink'])->name('generate-cross-link');

// Щаг 2 - Генерация сервисных данных
Route::get('/documents/generate-link', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateLink'])->name('generate-link');
Route::get('/documents/generate-link', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'generateLink'])->name('generate-link');

// Шаг 3 - Работа с данными - отдача и сохранение
Route::any('/documents/content', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'prepareContent'])->name('prepare-content');
// Шаг 3 - Работа с данными - отдача
Route::get('/documents/content', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'prepareContent'])->name('prepare-content');

// Шаг 4 - Работа с данными - обработка
Route::put('/documents/content', [\Mitwork\Kalkan\Http\Controllers\DocumentsController::class, 'processContent'])->name('process-content');
5 changes: 3 additions & 2 deletions src/Contracts/SignatureService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Mitwork\Kalkan\Contracts;

use Mitwork\Kalkan\Enums\TsaPolicy;
use Mitwork\Kalkan\Exceptions\IncorrectXmlDataException;
use Mitwork\Kalkan\Exceptions\NcanodeUnavailableException;

Expand Down Expand Up @@ -32,13 +33,13 @@ public function signXml(string $xml, string $key, string $password, string $alia
* @param string $password Пароль ключа
* @param string|null $alias Псевдоним (алиас) (необязательно)
* @param bool $withTsp Метка времени
* @param string $tsaPolicy Политика TSP-запроса
* @param TsaPolicy $tsaPolicy Политика TSP-запроса
* @param bool $detached Открепленная подпись
* @param string|null $cms Исходные (подписанные данные)
* @param bool $raw Возврат подписанной строки, либо ответа
* @return string|array Подписанные данные или ответ сервиса
*
* @throws NcanodeUnavailableException
*/
public function signCms(string $data, string $key, string $password, string $alias = null, bool $withTsp = true, string $tsaPolicy = 'TSA_GOST_POLICY', bool $detached = false, string $cms = null, bool $raw = false): string|array;
public function signCms(string $data, string $key, string $password, string $alias = null, bool $withTsp = true, TsaPolicy $tsaPolicy = TsaPolicy::TSA_GOST_POLICY, bool $detached = false, string $cms = null, bool $raw = false): string|array;
}
9 changes: 9 additions & 0 deletions src/Enums/CertificatePolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Mitwork\Kalkan\Enums;

enum CertificatePolicy: string
{
case SIGN = 'sign';
case AUTH = 'auth';
}
9 changes: 9 additions & 0 deletions src/Enums/ContentType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Mitwork\Kalkan\Enums;

enum ContentType: string
{
case XML = 'xml';
case CMS = 'cms';
}
9 changes: 9 additions & 0 deletions src/Enums/RevocationCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Mitwork\Kalkan\Enums;

enum RevocationCheck: string
{
case OCSP = 'OCSP';
case CRL = 'CRL';
}
10 changes: 10 additions & 0 deletions src/Enums/TsaPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Mitwork\Kalkan\Enums;

enum TsaPolicy: string
{
case TSA_GOST_POLICY = 'TSA_GOST_POLICY';
case TSA_GOSTGT_POLICY = 'TSA_GOSTGT_POLICY';
case TSA_GOST2015_POLICY = 'TSA_GOST2015_POLICY';
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
namespace Mitwork\Kalkan\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\URL;
use Mitwork\Kalkan\Enums\ContentType;
use Mitwork\Kalkan\Http\Requests\FetchDocumentRequest;
use Mitwork\Kalkan\Http\Requests\ProcessDocumentRequest;
use Mitwork\Kalkan\Http\Requests\StoreDocumentRequest;
use Mitwork\Kalkan\Services\DocumentService;
use Mitwork\Kalkan\Services\KalkanValidationService;
use Mitwork\Kalkan\Services\QrCodeGenerationService;

class TestController extends \Illuminate\Routing\Controller
class DocumentsController extends \Illuminate\Routing\Controller
{
public function __construct(
public DocumentService $documentService,
Expand All @@ -25,33 +27,21 @@ public function __construct(
*
* В данном примере содержимое документа сохраняется
* только в кэш, в реально жизни это может быть база
* данных или файлоовое хранилище.
* данных или файловое/облачное хранилище.
*
* Последующие запросы используют этот идентификатор
* для запроса и работы с данными.
*/
public function store(Request $request): JsonResponse
public function store(StoreDocumentRequest $request): JsonResponse
{
$request->validate([
'name' => ['required'],
'content' => ['required'],
'type' => ['required'],
]);

$id = $request->get('id');
$id = $request->input('id', hrtime(true));

if (! $request->has('id')) {
$id = hrtime(true);
if (! $this->documentService->saveDocument($id, $request->validated())) {
return response()->json([
'message' => 'Невозможно сохранить документ',
], 500);
}

Cache::add($id, [
'name' => $request->get('name'),
'content' => $request->get('content'),
'type' => $request->get('type'),
],
config('kalkan.options.ttl')
);

$link = $this->generateSignedLink('generate-link', ['id' => $id]);
$result = $this->qrCodeGenerationService->generate($link);

Expand Down Expand Up @@ -79,13 +69,9 @@ public function store(Request $request): JsonResponse
* необходимо получить QR-код и ссылку для того
* чтобы можно было отобразить ее в интерфейсе.
*/
public function generateQrCode(Request $request): JsonResponse
public function generateQrCode(FetchDocumentRequest $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = $this->generateSignedLink('generate-link', ['id' => $request->get('id')]);
$link = $this->generateSignedLink('generate-link', ['id' => $request->input('id')]);
$result = $this->qrCodeGenerationService->generate($link);

return response()->json([
Expand All @@ -101,12 +87,8 @@ public function generateQrCode(Request $request): JsonResponse
* работы с подписанием через мобильное приложение
* eGov Mobile или eGov business.
*/
public function generateCrossLink(Request $request): JsonResponse
public function generateCrossLink(FetchDocumentRequest $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = $this->generateSignedLink('prepare-content', ['id' => $request->get('id')]);

return response()->json([
Expand All @@ -118,67 +100,72 @@ public function generateCrossLink(Request $request): JsonResponse
/**
* Шаг 2 - генерация сервисных данных
*/
public function generateLink(Request $request): JsonResponse
public function generateLink(FetchDocumentRequest $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = $this->generateSignedLink('prepare-content', ['id' => $request->get('id')]);
$link = $this->generateSignedLink('prepare-content', ['id' => $request->input('id')]);
$data = $this->documentService->prepareServiceData($link);

return response()->json($data);
}

/**
* Шаг 3 - работа с контентом документа
*
* Возврат содержимого документов
*/
public function prepareContent(Request $request): JsonResponse
public function prepareContent(FetchDocumentRequest $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$data = Cache::get($request->get('id'));
$document = $this->documentService->getDocument($request->input('id'));

// Отправка исходных данных
if (! $document) {
return response()->json([
'message' => 'Невозможно получить документ',
], 500);
}

if ($request->isMethod('GET')) {
if (! isset($document['meta'])) {
$document['meta'] = [];
}

if ($data['type'] === 'xml') {
$this->documentService->addXmlDocument($request->get('id'), $data['name'], $data['content']);
if ($document['type'] === ContentType::XML->value) {
$this->documentService->addXmlDocument($request->input('id'), $document['name'], $document['content'], $document['meta']);
$response = $this->documentService->getXmlDocuments($request->input('id'));

return response()->json($this->documentService->getXmlDocuments());
} else {
$this->documentService->addCmsDocument($request->get('id'), $data['name'], $data['content']);

return response()->json($this->documentService->getCmsDocuments());
}
} else {
$this->documentService->addCmsDocument($request->input('id'), $document['name'], $document['content'], $document['meta']);
$response = $this->documentService->getCmsDocuments($request->input('id'));

}

// Обработка подписанных данных
return response()->json($response);
}

/**
* Шаг 4 - получение и обработка подписанных данных
*/
public function processContent(ProcessDocumentRequest $request): JsonResponse
{
$document = $this->documentService->getDocument($request->input('id'));
$documents = $request->input('documentsToSign');

if (request()->isMethod('PUT')) {
foreach ($documents as $signedDocument) {

$documents = $request->get('documentsToSign');
$type = $data['type'];
if ($document['type'] === ContentType::XML->value) {
$result = $this->validationService->verifyXml($signedDocument['documentXml']);
} else {
$result = $this->validationService->verifyCms($signedDocument['documentCms'], $document['content']);
}

foreach ($documents as $document) {
if ($type === 'xml') {
$result = $this->validationService->verifyXml($document['documentXml']);
} else {
$result = $this->validationService->verifyCms($document['documentCms'], $data['content']);
}
if ($result !== true) {
return response()->json(['error' => $this->validationService->getError()], 422);
}

if ($result !== true) {
return response()->json([], 422);
}
if (! $this->documentService->processDocument($request->input('id'))) {
return response()->json(['error' => 'Невозможно обработать документ'], 500);
}
}

return response()->json([]);

}

/**
Expand Down
27 changes: 27 additions & 0 deletions src/Http/Requests/FetchDocumentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Mitwork\Kalkan\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Mitwork\Kalkan\Rules\CacheValueExists;

class FetchDocumentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'id' => ['required', new CacheValueExists],
];
}
}
28 changes: 28 additions & 0 deletions src/Http/Requests/ProcessDocumentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Mitwork\Kalkan\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Mitwork\Kalkan\Rules\CacheValueExists;

class ProcessDocumentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'id' => ['required', new CacheValueExists],
'documentsToSign' => 'required',
];
}
}
Loading

0 comments on commit 38f86e1

Please sign in to comment.