Skip to content

Commit

Permalink
Update dependencies, provide full application test with controller
Browse files Browse the repository at this point in the history
  • Loading branch information
eudj1n committed Oct 12, 2023
1 parent 085289e commit 409b674
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 53 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- main
- dev

jobs:
tests:
Expand All @@ -13,7 +14,7 @@ jobs:
fail-fast: true
matrix:
php: [ 8.1, 8.2, 8.3 ]
laravel: [ 10 ]
laravel: [ 8, 9, 10 ]

name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}

Expand Down Expand Up @@ -43,7 +44,7 @@ jobs:
ncanode:
image: malikzh/ncanode
env:
NCANODE_CRL_URL: http://test.pki.gov.kz/crl/nca_gost2022_test.crl
NCANODE_CRL_URL: http://test.pki.gov.kz/crl/nca_gost_test_2022.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/
Expand All @@ -58,7 +59,7 @@ jobs:
fail-fast: true
matrix:
stack: [ kalkan ]
laravel: [ 10 ]
laravel: [ 8, 9, 10 ]

name: Test Stubs - Laravel ${{ matrix.laravel }} - ${{ matrix.stack }}

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"ext-gd": "*",
"ext-json": "*",
"ext-xml": "*",
"illuminate/support": "^10.28",
"illuminate/support": "^8.0|^9.0|^10.0",
"illuminate/events": "^8.0|^9.0|^10.0",
"guzzlehttp/guzzle": "^7.8",
"endroid/qr-code": "^5.0"
},
Expand Down
4 changes: 2 additions & 2 deletions config/kalkan.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
],
'links' => [
'prefix' => 'mobileSign:',
'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',
'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',
Expand Down
18 changes: 13 additions & 5 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@

use Illuminate\Support\Facades\Route;

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

Route::get('/document/generate-qr-code', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateQrCode'])->name('generate-qr-code');
Route::get('/document/generate-cross-link', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateCrossLink'])->name('generate-cross-link');
Route::get('/document/generate-link', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'generateLink'])->name('generate-link');
// Шаг 1.1 - Генерация QR-кода
Route::get('/documents/generate-qr-code', [\Mitwork\Kalkan\Http\Controllers\TestController::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');

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

// Шаг 3 - Работа с данными - отдача и сохранение
Route::any('/documents/content', [\Mitwork\Kalkan\Http\Controllers\TestController::class, 'prepareContent'])->name('prepare-content');
114 changes: 76 additions & 38 deletions src/Http/Controllers/TestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,30 @@
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\URL;
use Mitwork\Kalkan\Services\DocumentService;
use Mitwork\Kalkan\Services\KalkanValidationService;
use Mitwork\Kalkan\Services\QrCodeGenerationService;

class TestController extends \Illuminate\Routing\Controller
{
public function __construct(
public DocumentService $documentService,
public QrCodeGenerationService $qrCodeGenerationService,
public KalkanValidationService $validationService,
) {
//
}

/**
* Шаг 1 - отправка документа, для последующей работы
* Шаг 1 - отправка документа для последующей работы
*
* В данном примере содержимое документа сохраняется
* только в кэш, в реально жизни это может быть база
* данных или файлоовое хранилище.
*
* Последующие запросы используют этот идентификатор
* для запроса и работы с данными.
*/
public function prepareDocument(Request $request): JsonResponse
public function store(Request $request): JsonResponse
{
$request->validate([
'name' => ['required'],
Expand All @@ -32,7 +41,7 @@ public function prepareDocument(Request $request): JsonResponse
$id = $request->get('id');

if (! $request->has('id')) {
$id = time();
$id = hrtime(true);
}

Cache::add($id, [
Expand All @@ -43,29 +52,40 @@ public function prepareDocument(Request $request): JsonResponse
config('kalkan.options.ttl')
);

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

return response()->json([
'id' => $id,
'url' => $link,
'links' => [
'qr' => [
'uri' => $result->getDataUri(),
//'raw' => $generateResult->getString(),
],
'app' => [
'mobile' => sprintf(config('kalkan.links.mobile'), urlencode($link)),
'business' => sprintf(config('kalkan.links.business'), urlencode($link)),
],
],
]);

}

/**
* Шаг 2 - Генерация QR-кода
* Шаг 1.1 - Генерация QR-кода
*
* После получения ID документа из прошлого шага
* необходимо получить QR-код и ссылку для того
* чтобы можно было отобразить ее в интерфейсе.
*/
public function generateQrCode(Request $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = URL::temporarySignedRoute(
'generate-link',
config('kalkan.options.ttl'),
[
'id' => $request->get('id'),
]
);

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

return response()->json([
Expand All @@ -75,52 +95,43 @@ public function generateQrCode(Request $request): JsonResponse
}

/**
* Шаг 3 - генерация ссылки
* Шаг 1.2 - генерация кросс-ссылок
*
* Данные ссылки генерируются для возможности
* работы с подписанием через мобильное приложение
* eGov Mobile или eGov business.
*/
public function generateLink(Request $request): JsonResponse
public function generateCrossLink(Request $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = URL::temporarySignedRoute(
'prepare-content',
config('kalkan.options.ttl'),
[
'id' => $request->get('id'),
]
);

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

return response()->json($data);
return response()->json([
'person' => sprintf(config('kalkan.links.mobile'), urlencode($link)),
'legal' => sprintf(config('kalkan.links.business'), urlencode($link))]
);
}

/**
* Шаг 4 - генерация кросс-ссылок
* Шаг 2 - генерация сервисных данных
*/
public function generateCrossLink(Request $request): JsonResponse
public function generateLink(Request $request): JsonResponse
{
$request->validate([
'id' => ['required'],
]);

$link = URL::temporarySignedRoute(
'prepare-content',
config('kalkan.options.ttl'),
[
'id' => $request->get('id'),
]
);
$link = $this->generateSignedLink('prepare-content', ['id' => $request->get('id')]);
$data = $this->documentService->prepareServiceData($link);

return response()->json([
'person' => sprintf(config('kalkan.links.person'), urlencode($link)),
'legal' => sprintf(config('kalkan.links.legal'), urlencode($link))]
);
return response()->json($data);
}

/**
* Шаг 5 - работа с контентом документа
* Шаг 3 - работа с контентом документа
*/
public function prepareContent(Request $request): JsonResponse
{
Expand Down Expand Up @@ -150,9 +161,36 @@ public function prepareContent(Request $request): JsonResponse

if (request()->isMethod('PUT')) {

$documents = $request->get('documentsToSign');
$type = $data['type'];

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([], 422);
}
}
}

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

}

/**
* Генерация временных ссылок
*
* @param string $route Роут
* @param array $params Параметры
* @param int $ttl Время жизни
* @return string Ссылка
*/
private function generateSignedLink(string $route, array $params = [], int $ttl = 30): string
{
return URL::temporarySignedRoute($route, $ttl ?: config('kalkan.options.ttl'), $params);
}
}
48 changes: 44 additions & 4 deletions tests/ApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,45 @@ final class ApplicationTest extends TestCase
{
use WithWorkbench;

private string $testKey = <<<'CER'
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
CER;

private string $testPassword = 'Qwerty12';

public function testApplicationCmsSigning(): void
{
$data = [
'name' => 'hello cms',
'content' => 'hello cms',
'content' => 'base64',
'type' => 'cms',
];

// $this->app['config']->set('kalkan.options.ttl', '1');

$response = $this->post(route('prepare-document'), $data);
$response = $this->post(route('store-document'), $data);

sleep(2);
// dd($response);

$this->assertTrue($response->isOk());
$this->assertArrayHasKey('id', $response);
Expand All @@ -46,7 +72,21 @@ public function testApplicationCmsSigning(): void
$link = $response['document']['uri'];

$response = $this->get($link);
$this->assertTrue($response->isOk());

// Emulate singing

$message = (array) $response->original;

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

foreach ($message['documentsToSign'] as &$document) {
$document['documentCms'] = $signatureService->signCms($document['documentCms'], $this->testKey, $this->testPassword);
}

// Send signed data

$response = $this->put($link, $message);
$this->assertTrue($response->isOk());

$response = $this->get(route('generate-cross-link', ['id' => $id]));
Expand All @@ -62,7 +102,7 @@ public function testApplicationXmlSigning(): void
'type' => 'xml',
];

$response = $this->post(route('prepare-document'), $data);
$response = $this->post(route('store-document'), $data);

$this->assertTrue($response->isOk());
$this->assertArrayHasKey('id', $response);
Expand Down

0 comments on commit 409b674

Please sign in to comment.