├── .gitignore ├── Dockerfile ├── README-PHP.md ├── README.md ├── assets ├── cacer.gif ├── license.gif ├── my-cert.gif ├── rest.gif ├── show-certs.gif ├── sign.gif ├── unsign.gif └── verify.gif ├── certificates ├── .gitkeep ├── bundle-cert-only.zip ├── bundle-cosign.zip ├── bundle-cyrillic.zip ├── bundle-no-pin.zip ├── bundle-pin.zip └── bundle-private-key-only.zip ├── demo-cli.sh ├── demo-php.sh ├── demo-rest.sh ├── devel ├── attach.sh ├── build.sh ├── install-certs.sh ├── reflection.php └── rest.sh ├── scripts ├── lib │ ├── colors.sh │ ├── functions.sh │ └── root.exp ├── my ├── root ├── sign ├── unsign └── verify └── www ├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── app ├── Certificate │ ├── Finder.php │ └── Info.php ├── Controller.php └── Exception.php ├── composer.json ├── composer.lock ├── docker-compose.yml ├── logs └── README.md ├── phpunit.xml ├── public ├── dependencies.php ├── index.php ├── routes.php └── settings.php ├── templates └── index.phtml ├── test_extension.php └── tests └── Functional ├── BaseTestCase.php └── HomepageTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /certificates 2 | /dist 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Базовый образ с КриптоПро 2 | FROM debian:stretch-slim as cryptopro-generic 3 | 4 | # Устанавливаем timezone 5 | ENV TZ="Europe/Moscow" \ 6 | docker="1" 7 | 8 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ 9 | echo $TZ > /etc/timezone 10 | 11 | # необходимо скачать со страницы https://www.cryptopro.ru/products/csp/downloads 12 | # `КриптоПро CSP 4.0 для Linux (x64, deb)` и скопировать `linux-amd64_deb.tgz` в каталог `dist` 13 | 14 | ADD dist /tmp/src 15 | RUN cd /tmp/src && \ 16 | tar -xf linux-amd64_deb.tgz && \ 17 | linux-amd64_deb/install.sh && \ 18 | # делаем симлинки 19 | cd /bin && \ 20 | ln -s /opt/cprocsp/bin/amd64/certmgr && \ 21 | ln -s /opt/cprocsp/bin/amd64/cpverify && \ 22 | ln -s /opt/cprocsp/bin/amd64/cryptcp && \ 23 | ln -s /opt/cprocsp/bin/amd64/csptest && \ 24 | ln -s /opt/cprocsp/bin/amd64/csptestf && \ 25 | ln -s /opt/cprocsp/bin/amd64/der2xer && \ 26 | ln -s /opt/cprocsp/bin/amd64/inittst && \ 27 | ln -s /opt/cprocsp/bin/amd64/wipefile && \ 28 | ln -s /opt/cprocsp/sbin/amd64/cpconfig && \ 29 | # прибираемся 30 | rm -rf /tmp/src 31 | 32 | # Образ с PHP cli и скриптами 33 | FROM cryptopro-generic 34 | ADD dist /tmp/src 35 | 36 | RUN apt-get update && \ 37 | apt-get install -y --no-install-recommends expect alien php7.0-cli php7.0-dev libboost-dev unzip g++ curl && \ 38 | cd /tmp/src && \ 39 | tar -xf cades_linux_amd64.tar.gz && \ 40 | alien -kci lsb-cprocsp-devel-4.0.9921-5.noarch.rpm && \ 41 | alien -kci cprocsp-pki-2.0.0-amd64-phpcades.rpm && \ 42 | alien -kci cprocsp-pki-2.0.0-amd64-cades.rpm && \ 43 | # меняем Makefile.unix 44 | PHP_BUILD=`php -i | grep 'PHP Extension => ' | awk '{print $4}'` && \ 45 | EXT_DIR=`php -i | grep 'extension_dir => ' | awk '{print $3}'` && \ 46 | # /usr/include/php/20151012/ 47 | sed -i "s#PHPDIR=/php#PHPDIR=/usr/include/php/$PHP_BUILD#g" /opt/cprocsp/src/phpcades/Makefile.unix && \ 48 | # копируем недостающую библиотеку 49 | ln -s /opt/cprocsp/lib/amd64/libcppcades.so.2 /opt/cprocsp/lib/amd64/libcppcades.so && \ 50 | # начинаем сборку 51 | cd /opt/cprocsp/src/phpcades && \ 52 | # применяем патч 53 | unzip /tmp/src/php7_support.patch.zip && \ 54 | patch < php7_support.patch && \ 55 | # собираем 56 | eval `/opt/cprocsp/src/doxygen/CSP/../setenv.sh --64`; make -f Makefile.unix && \ 57 | # делаем симлинк собранной библиотеки 58 | mv libphpcades.so "$EXT_DIR" && \ 59 | # включаем расширение 60 | echo "extension=libphpcades.so" > /etc/php/7.0/cli/conf.d/20-libphpcades.ini && \ 61 | # проверяем наличие класса CPStore 62 | php -r "var_dump(class_exists('CPStore'));" | grep -q 'bool(true)' && \ 63 | # прибираемся 64 | cd / && \ 65 | apt-get purge -y php7.0-dev cprocsp-pki-phpcades lsb-cprocsp-devel g++ && \ 66 | apt-get autoremove -y && \ 67 | rm -rf /opt/cprocsp/src/phpcades && \ 68 | rm -rf /tmp/src && \ 69 | rm -rf /var/lib/apt/lists/ 70 | 71 | ADD scripts /scripts 72 | ADD www /www 73 | 74 | # composer 75 | # RUN apt-get update && \ 76 | # apt-get install -y --no-install-recommends curl ca-certificates && \ 77 | # # composer 78 | # curl "https://getcomposer.org/installer" > composer-setup.php && \ 79 | # php composer-setup.php && \ 80 | # rm -f composer-setup.php && \ 81 | # chmod +x composer.phar && \ 82 | # mv composer.phar /bin/composer && \ 83 | # # прибираемся 84 | # cd / && \ 85 | # apt-get purge -y curl ca-certificates && \ 86 | 87 | HEALTHCHECK --interval=60s --timeout=5s CMD ["curl", "-m5", "-f", "http://localhost:8080/healthcheck"] 88 | 89 | CMD ["php", "-S", "0.0.0.0:8080", "-t", "/www/public/"] 90 | -------------------------------------------------------------------------------- /README-PHP.md: -------------------------------------------------------------------------------- 1 | # PHP КриптоПро 2 | 3 | Документация по использованию PHP КриптоПро скудна. 4 | 5 | Попытки достать параметры методов через [Reflection API](http://php.net/manual/ru/book.reflection.php) не приводят к успеху: 6 | 7 | ```PHP 8 | // Работает 9 | $r = new \ReflectionMethod('DateTime', '__construct'); 10 | var_dump($r->getParameters()); 11 | 12 | // Возвращает пустой массив 13 | $r = new \ReflectionMethod('CPSignedData', 'get_Content'); 14 | var_export($r->getParameters()); 15 | ``` 16 | 17 | ## Список классов и методов 18 | 19 | ### Через Reflection API 20 | 21 | С помощью `devel/reflection.php` получен такой список классов и методов: 22 | 23 | ``` 24 | CPStore 25 | Open() 26 | Close() 27 | get_Certificates() 28 | get_Location() 29 | get_Name() 30 | 31 | CPCertificates 32 | Find() 33 | Item() 34 | Count() 35 | 36 | CPCertificate 37 | GetInfo() 38 | FindPrivateKey() 39 | HasPrivateKey() 40 | IsValid() 41 | ExtendedKeyUsage() 42 | KeyUsage() 43 | Export() 44 | Import() 45 | get_SerialNumber() 46 | get_Thumbprint() 47 | get_SubjectName() 48 | get_IssuerName() 49 | get_Version() 50 | get_ValidToDate() 51 | get_ValidFromDate() 52 | BasicConstraints() 53 | PublicKey() 54 | PrivateKey() 55 | 56 | CPKeyUsage 57 | get_IsPresent() 58 | get_IsCritical() 59 | get_IsDigitalSignatureEnabled() 60 | get_IsNonRepudiationEnabled() 61 | get_IsKeyEnciphermentEnabled() 62 | get_IsDataEnciphermentEnabled() 63 | get_IsKeyAgreementEnabled() 64 | get_IsKeyCertSignEnabled() 65 | get_IsCRLSignEnabled() 66 | get_IsEncipherOnlyEnabled() 67 | get_IsDecipherOnlyEnabled() 68 | 69 | CPExtendedKeyUsage 70 | get_IsPresent() 71 | get_IsCritical() 72 | get_EKUs() 73 | 74 | CPEKU 75 | get_Name() 76 | set_Name() 77 | get_OID() 78 | set_OID() 79 | 80 | CPAlgorithm 81 | get_Name() 82 | set_Name() 83 | get_KeyLength() 84 | set_KeyLength() 85 | 86 | CPPrivateKey 87 | get_ContainerName() 88 | get_UniqueContainerName() 89 | get_ProviderName() 90 | get_ProviderType() 91 | get_KeySpec() 92 | 93 | CPEncodedData 94 | Format() 95 | get_Value() 96 | 97 | CPPublicKey 98 | get_Algorithm() 99 | get_Length() 100 | get_EncodedKey() 101 | get_EncodedParameters() 102 | 103 | CPOID 104 | get_Value() 105 | set_Value() 106 | get_FriendlyName() 107 | 108 | CPAttribute 109 | set_OID() 110 | get_OID() 111 | set_Value() 112 | get_Value() 113 | set_Name() 114 | get_Name() 115 | set_ValueEncoding() 116 | get_ValueEncoding() 117 | 118 | CPBasicConstraints 119 | set_IsPresent() 120 | get_IsPresent() 121 | set_IsCritical() 122 | get_IsCritical() 123 | get_IsCertificateAuthority() 124 | get_IsPathLenConstraintPresent() 125 | get_PathLenConstraint() 126 | 127 | CPCertificateStatus 128 | get_Result() 129 | get_CheckFlag() 130 | set_CheckFlag() 131 | EKU() 132 | get_VerificationTime() 133 | set_VerificationTime() 134 | get_UrlRetrievalTimeout() 135 | set_UrlRetrievalTimeout() 136 | CertificatePolicies() 137 | ApplicationPolicies() 138 | get_ValidationCertificates() 139 | 140 | CPEnvelopedData 141 | get_Content() 142 | set_Content() 143 | get_ContentEncoding() 144 | set_ContentEncoding() 145 | Encrypt() 146 | Decrypt() 147 | get_Recipients() 148 | 149 | CPSigner 150 | get_Certificate() 151 | set_Certificate() 152 | get_Options() 153 | set_Options() 154 | get_AuthenticatedAttributes() 155 | get_UnauthenticatedAttributes() 156 | get_TSAAddress() 157 | set_TSAAddress() 158 | get_CRLs() 159 | get_OCSPResponses() 160 | get_SigningTime() 161 | get_SignatureTimeStampTime() 162 | set_KeyPin() 163 | 164 | CPEKUs 165 | Add() 166 | get_Count() 167 | get_Item() 168 | Clear() 169 | Remove() 170 | 171 | CPAttributes 172 | Add() 173 | get_Count() 174 | get_Item() 175 | Clear() 176 | Remove() 177 | Assign() 178 | 179 | CPSigners 180 | get_Count() 181 | get_Item() 182 | 183 | CPRecipients 184 | Add() 185 | get_Count() 186 | get_Item() 187 | Clear() 188 | 189 | CPSignedData 190 | SignCades() 191 | SignHash() 192 | Sign() 193 | CoSign() 194 | CoSignCades() 195 | CoSignHash() 196 | EnhanceCades() 197 | VerifyCades() 198 | VerifyHash() 199 | Verify() 200 | set_ContentEncoding() 201 | get_ContentEncoding() 202 | set_Content() 203 | get_Content() 204 | get_Signers() 205 | get_Certificates() 206 | 207 | CPHashedData 208 | Hash() 209 | SetHashValue() 210 | get_Value() 211 | set_Algorithm() 212 | get_Algorithm() 213 | set_DataEncoding() 214 | get_DataEncoding() 215 | 216 | CPRawSignature 217 | VerifyHash() 218 | SignHash() 219 | 220 | CPSignedXML 221 | set_Content() 222 | get_Content() 223 | set_SignatureType() 224 | set_DigestMethod() 225 | set_SignatureMethod() 226 | get_Signers() 227 | Sign() 228 | Verify() 229 | ``` 230 | 231 | Константы `php_CPCSP`: 232 | 233 | ``` 234 | MEMORY_STORE = 0 235 | LOCAL_MACHINE_STORE = 1 236 | CURRENT_USER_STORE = 2 237 | ACTIVE_DIRECTORY_USER_STORE = 3 238 | SMART_CARD_USER_STORE = 4 239 | STORE_OPEN_READ_ONLY = 0 240 | STORE_OPEN_READ_WRITE = 1 241 | STORE_OPEN_MAXIMUM_ALLOWED = 2 242 | STORE_OPEN_EXISTING_ONLY = 128 243 | STORE_OPEN_INCLUDE_ARCHIVED = 256 244 | CERTIFICATE_FIND_SHA1_HASH = 0 245 | CERTIFICATE_FIND_SUBJECT_NAME = 1 246 | CERTIFICATE_FIND_ISSUER_NAME = 2 247 | CERTIFICATE_FIND_ROOT_NAME = 3 248 | CERTIFICATE_FIND_TEMPLATE_NAME = 4 249 | CERTIFICATE_FIND_EXTENSION = 5 250 | CERTIFICATE_FIND_EXTENDED_PROPERTY = 6 251 | CERTIFICATE_FIND_APPLICATION_POLICY = 7 252 | CERTIFICATE_FIND_CERTIFICATE_POLICY = 8 253 | CERTIFICATE_FIND_TIME_VALID = 9 254 | CERTIFICATE_FIND_TIME_NOT_YET_VALID = 10 255 | CERTIFICATE_FIND_TIME_EXPIRED = 11 256 | CERTIFICATE_FIND_KEY_USAGE = 12 257 | CERT_INFO_SUBJECT_SIMPLE_NAME = 0 258 | CERT_INFO_ISSUER_SIMPLE_NAME = 1 259 | CERT_INFO_SUBJECT_EMAIL_NAME = 2 260 | CERT_INFO_ISSUER_EMAIL_NAME = 3 261 | CERT_INFO_SUBJECT_UPN = 4 262 | CERT_INFO_ISSUER_UPN = 5 263 | CERT_INFO_SUBJECT_DNS_NAME = 6 264 | CERT_INFO_ISSUER_DNS_NAME = 7 265 | DIGITAL_SIGNATURE_KEY_USAGE = 128 266 | NON_REPUDIATION_KEY_USAGE = 64 267 | KEY_ENCIPHERMENT_KEY_USAGE = 32 268 | DATA_ENCIPHERMENT_KEY_USAGE = 16 269 | KEY_AGREEMENT_KEY_USAGE = 8 270 | KEY_CERT_SIGN_KEY_USAGE = 4 271 | OFFLINE_CRL_SIGN_KEY_USAGE = 2 272 | CRL_SIGN_KEY_USAGE = 2 273 | ENCIPHER_ONLY_KEY_USAGE = 1 274 | DECIPHER_ONLY_KEY_USAGE = 32768 275 | ENCODE_BASE64 = 0 276 | ENCODE_BINARY = 1 277 | ENCODE_ANY = 4294967295 278 | CADESCOM_ENCRYPTION_ALGORITHM_RC2 = 0 279 | CADESCOM_ENCRYPTION_ALGORITHM_RC4 = 1 280 | CADESCOM_ENCRYPTION_ALGORITHM_DES = 2 281 | CADESCOM_ENCRYPTION_ALGORITHM_3DES = 3 282 | CADESCOM_ENCRYPTION_ALGORITHM_AES = 4 283 | CADESCOM_ENCRYPTION_ALGORITHM_GOST_28147_89 = 25 284 | ENCRYPTION_KEY_LENGTH_MAXIMUM = 0 285 | ENCRYPTION_KEY_LENGTH_40_BITS = 1 286 | ENCRYPTION_KEY_LENGTH_56_BITS = 2 287 | ENCRYPTION_KEY_LENGTH_128_BITS = 3 288 | ENCRYPTION_KEY_LENGTH_192_BITS = 4 289 | ENCRYPTION_KEY_LENGTH_256_BITS = 5 290 | EKU_OTHER = 0 291 | EKU_SERVER_AUTH = 1 292 | EKU_CLIENT_AUTH = 2 293 | EKU_CODE_SIGNING = 3 294 | EKU_EMAIL_PROTECTION = 4 295 | EKU_SMARTCARD_LOGON = 5 296 | EKU_ENCRYPTING_FILE_SYSTEM = 6 297 | SEX_NOT_KNOWN = 0 298 | SEX_MALE = 1 299 | SEX_FEMALE = 2 300 | SEX_NOT_APPLICABLE = 9 301 | PROV_RSA_FULL = 1 302 | PROV_RSA_SIG = 2 303 | PROV_DSS = 3 304 | PROV_FORTEZZA = 4 305 | PROV_MS_EXCHANGE = 5 306 | PROV_SSL = 6 307 | PROV_RSA_SCHANNEL = 12 308 | PROV_DSS_DH = 13 309 | PROV_EC_ECDSA_SIG = 14 310 | PROV_EC_ECNRA_SIG = 15 311 | PROV_EC_ECDSA_FULL = 16 312 | PROV_EC_ECNRA_FULL = 17 313 | PROV_DH_SCHANNEL = 18 314 | PROV_SPYRUS_LYNKS = 20 315 | PROV_RNG = 21 316 | PROV_INTEL_SEC = 22 317 | PROV_REPLACE_OWF = 23 318 | PROV_RSA_AES = 24 319 | KEY_SPEC_KEYEXCHANGE = 1 320 | KEY_SPEC_SIGNATURE = 2 321 | OID_OTHER = 0 322 | OID_AUTHORITY_KEY_IDENTIFIER_EXTENSION = 1 323 | OID_KEY_ATTRIBUTES_EXTENSION = 2 324 | OID_CERT_POLICIES_95_EXTENSION = 3 325 | OID_KEY_USAGE_RESTRICTION_EXTENSION = 4 326 | OID_LEGACY_POLICY_MAPPINGS_EXTENSION = 5 327 | OID_SUBJECT_ALT_NAME_EXTENSION = 6 328 | OID_ISSUER_ALT_NAME_EXTENSION = 7 329 | OID_BASIC_CONSTRAINTS_EXTENSION = 8 330 | OID_SUBJECT_KEY_IDENTIFIER_EXTENSION = 9 331 | OID_KEY_USAGE_EXTENSION = 10 332 | OID_PRIVATEKEY_USAGE_PERIOD_EXTENSION = 11 333 | OID_SUBJECT_ALT_NAME2_EXTENSION = 12 334 | OID_ISSUER_ALT_NAME2_EXTENSION = 13 335 | OID_BASIC_CONSTRAINTS2_EXTENSION = 14 336 | OID_NAME_CONSTRAINTS_EXTENSION = 15 337 | OID_CRL_DIST_POINTS_EXTENSION = 16 338 | OID_CERT_POLICIES_EXTENSION = 17 339 | OID_POLICY_MAPPINGS_EXTENSION = 18 340 | OID_AUTHORITY_KEY_IDENTIFIER2_EXTENSION = 19 341 | OID_POLICY_CONSTRAINTS_EXTENSION = 20 342 | OID_ENHANCED_KEY_USAGE_EXTENSION = 21 343 | OID_CERTIFICATE_TEMPLATE_EXTENSION = 22 344 | OID_APPLICATION_CERT_POLICIES_EXTENSION = 23 345 | OID_APPLICATION_POLICY_MAPPINGS_EXTENSION = 24 346 | OID_APPLICATION_POLICY_CONSTRAINTS_EXTENSION = 25 347 | OID_AUTHORITY_INFO_ACCESS_EXTENSION = 26 348 | OID_SERVER_AUTH_eku = 100 349 | OID_CLIENT_AUTH_eku = 101 350 | OID_CODE_SIGNING_eku = 102 351 | OID_EMAIL_PROTECTION_eku = 103 352 | OID_IPSEC_END_SYSTEM_eku = 104 353 | OID_IPSEC_TUNNEL_eku = 105 354 | OID_IPSEC_USER_eku = 106 355 | OID_TIME_STAMPING_eku = 107 356 | OID_CTL_USAGE_SIGNING_eku = 108 357 | OID_TIME_STAMP_SIGNING_eku = 109 358 | OID_SERVER_GATED_CRYPTO_eku = 110 359 | OID_ENCRYPTING_FILE_SYSTEM_eku = 111 360 | OID_EFS_RECOVERY_eku = 112 361 | OID_WHQL_CRYPTO_eku = 113 362 | OID_NT5_CRYPTO_eku = 114 363 | OID_OEM_WHQL_CRYPTO_eku = 115 364 | OID_EMBEDED_NT_CRYPTO_eku = 116 365 | OID_ROOT_LIST_SIGNER_eku = 117 366 | OID_QUALIFIED_SUBORDINATION_eku = 118 367 | OID_KEY_RECOVERY_eku = 119 368 | OID_DIGITAL_RIGHTS_eku = 120 369 | OID_LICENSES_eku = 121 370 | OID_LICENSE_SERVER_eku = 122 371 | OID_SMART_CARD_LOGON_eku = 123 372 | OID_PKIX_POLICY_QUALIFIER_CPS = 124 373 | OID_PKIX_POLICY_QUALIFIER_USERNOTICE = 125 374 | AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0 375 | AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME = 1 376 | AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2 377 | ATTRIBUTE_OTHER = 4294967295 378 | CHECK_NONE = 0 379 | CHECK_TRUSTED_ROOT = 1 380 | CHECK_TIME_VALIDITY = 2 381 | CHECK_SIGNATURE_VALIDITY = 4 382 | CHECK_ONLINE_REVOCATION_STATUS = 8 383 | CHECK_OFFLINE_REVOCATION_STATUS = 16 384 | CHECK_COMPLETE_CHAIN = 32 385 | CHECK_NAME_CONSTRAINTS = 64 386 | CHECK_BASIC_CONSTRAINTS = 128 387 | CHECK_NESTED_VALIDITY_PERIOD = 256 388 | CHECK_ONLINE_ALL = 495 389 | CHECK_OFFLINE_ALL = 503 390 | STRING_TO_UCS2LE = 0 391 | BASE64_TO_BINARY = 1 392 | CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0 393 | CERTIFICATE_INCLUDE_WHOLE_CHAIN = 1 394 | CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2 395 | CADES_DEFAULT = 0 396 | CADES_BES = 1 397 | CADES_X_LONG_TYPE_1 = 93 398 | CADES_T = 5 399 | VERIFY_SIGNATURE_ONLY = 0 400 | VERIFY_SIGNATURE_AND_CERTIFICATE = 1 401 | HASH_ALGORITHM_SHA1 = 0 402 | HASH_ALGORITHM_MD2 = 1 403 | HASH_ALGORITHM_MD4 = 2 404 | HASH_ALGORITHM_MD5 = 3 405 | HASH_ALGORITHM_SHA_256 = 4 406 | HASH_ALGORITHM_SHA_384 = 5 407 | HASH_ALGORITHM_SHA_512 = 6 408 | HASH_ALGORITHM_GOSTR_3411 = 100 409 | CADESCOM_HASH_ALGORITHM_CP_GOST_3411 = 100 410 | CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256 = 101 411 | CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_512 = 102 412 | XML_SIGNATURE_TYPE_ENVELOPED = 0 413 | XML_SIGNATURE_TYPE_ENVELOPING = 1 414 | XML_SIGNATURE_TYPE_TEMPLATE = 2 415 | ``` 416 | 417 | ### Через исходные коды 418 | 419 | В скачаном с официального сайта архиве `cades_linux_amd64.tar.gz` есть RPM пакет `cprocsp-pki-2.0.0-amd64-phpcades.rpm`, в котором находятся исходные тексты расширения, в том числе `test_extension.php` (скопирован в `devel/test_extension.php`). 420 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # КриптоПро 4.0 в докер контейнере 2 | 3 | Содержимое контейнера: 4 | 5 | * PHP7 с установленным расширением `libphpcades` (`CPStore`, `CPSigner`, `CPSignedData`) 6 | * инструменты КриптоПро: `certmgr`, `cpverify`, `cryptcp`, `csptest`, `csptestf`, `der2xer`, `inittst`, `wipefile`, `cpconfig` 7 | * вспомогательные скрипты командой строки 8 | * HTTP REST-сервер 9 | 10 | Есть 3 варианта использования контейнера: 11 | 12 | * [через интерфейс командной строки](#cli) (и ssh-клиент для удаленных машин) 13 | * [через HTTP REST-сервер](#http) 14 | * добавить свои обработчики внутрь контейнера 15 | 16 | # Структура проекта 17 | 18 | ``` 19 | ├── assets - материалы для README.md 20 | ├── devel - devel скрипты 21 | ├── certificates - тестовые сертификаты 22 | ├── dist - пакеты КриптоПро (необходимо скачать с официального сайта) 23 | ├── Dockerfile - файл сборки образа 24 | ├── README.md - этот файл 25 | └── scripts - вспомогательные скрипты командой строки 26 | └── www - HTTP REST-сервер 27 | ```` 28 | 29 | # Создание образа из исходного кода 30 | 31 | Скачать с официального сайта в `dist/` (необходимо быть залогиненым в системе): 32 | 33 | * [КриптоПро CSP 4.0 для Linux (x64, deb)](https://www.cryptopro.ru/products/csp/downloads) => `dist/linux-amd64_deb.tgz` 34 | * Browser plug-in [версия 2.0 для пользователей](https://www.cryptopro.ru/products/cades/plugin) => `dist/cades_linux_amd64.tar.gz` - Linux версию 35 | * [Патч для PHP7](https://www.cryptopro.ru/forum2/default.aspx?g=posts&m=79589#post79589) => `dist/php7_support.patch.zip` 36 | 37 | Запустить: 38 | 39 | ``` 40 | docker build --tag required/cryptopro . 41 | ``` 42 | 43 | ## Возможные проблемы 44 | 45 | В `Dockerfile` содержатся названия пакетов, например `lsb-cprocsp-devel-4.0.9921-5.noarch.rpm`, которые могут заменить новой версией. Следует поправить названия пакетов в `Dockerfile`. 46 | 47 | # Запуск контейнера 48 | 49 | Запустим контейнер под именем `cryptopro`, к которому будем обращаться в примерах: 50 | 51 | ``` 52 | docker run -it --rm -p 8095:80 --name cryptopro required/cryptopro 53 | ``` 54 | 55 | # Работа с контейнером через интерфейс командной строки 56 | 57 | ## Лицензия 58 | 59 | Установка серийного номера: 60 | 61 | ``` 62 | docker exec -i cryptopro cpconfig -license -set <серийный_номер> 63 | ``` 64 | 65 | Просмотр: 66 | 67 | ``` 68 | docker exec -i cryptopro cpconfig -license -view 69 | ``` 70 | 71 | ![license](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/license.gif) 72 | 73 | 74 | ## Установка корневых сертификатов 75 | 76 | Для установки корневых сертификатов нужно на `stdin` скрипта `/scripts/root` передать файл с сертификатами. Если в файле несколько сертификатов, все они будут установлены. 77 | 78 | ### Через скачивание на диск 79 | 80 | Скачаем сертификат на диск с помощью `curl` и передадим полученный файл на `stdin` с запуском команды его установки: 81 | 82 | ``` 83 | curl -sS http://cpca.cryptopro.ru/cacer.p7b > certificates/cacer.p7b 84 | cat certificates/cacer.p7b | docker exec -i cryptopro /scripts/root 85 | ``` 86 | 87 | ### Без скачивания на диск 88 | 89 | ``` 90 | # сертификаты УЦ 91 | curl -sS http://cpca.cryptopro.ru/cacer.p7b | docker exec -i cryptopro /scripts/root 92 | # сертификаты тестового УЦ 93 | curl -sS http://testca2012.cryptopro.ru/cert/rootca.cer | docker exec -i cryptopro /scripts/root 94 | curl -sS http://testca2012.cryptopro.ru/cert/subca.cer | docker exec -i cryptopro /scripts/root 95 | ``` 96 | 97 | ![cacer](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/cacer.gif) 98 | 99 | Примечание: по какой-то причине иногда "заедает", но при повторном запуске - срабатывает. 100 | 101 | ## Установка сертификатов пользователя для проверки и подписания 102 | 103 | Необходимо специальным образом сформировать zip-архив `bundle.zip` и отправить его на `stdin` скрипта `/scripts/my`. Пример такого zip-файла: 104 | 105 | ``` 106 | ├── certificate.cer - файл сертификата (не обязательно) 107 | └── le-09650.000 - каталог с файлами закрытого ключа (не обязательно) 108 | ├── header.key 109 | ├── masks2.key 110 | ├── masks.key 111 | ├── name.key 112 | ├── primary2.key 113 | └── primary.key 114 | ``` 115 | 116 | [Как получить сертификат КриптоПро](http://pushorigin.ru/cryptopro/real-cert-crypto-pro-linux). 117 | 118 | Первый найденный файл в корне архива будет воспринят как сертификат, а первый найденный каталог - как связка файлов закрытого ключа. Пароль от контейнера, если есть, передается первым параметром командной строки. 119 | 120 | В каталоге `certificates/` содержатся различные комбинации тестового сертификата и закрытого ключа, с PIN кодом и без: 121 | 122 | ``` 123 | ├── bundle-cert-only.zip - только сертификат 124 | ├── bundle-cosign.zip - сертификат + закрытый ключ БЕЗ пин-кода (для добавления второй подписи) 125 | ├── bundle-cyrillic.zip - сертификат + закрытый ключ, название контейнера "тестовое название контейнера" (кириллица) 126 | ├── bundle-no-pin.zip - сертификат + закрытый ключ БЕЗ пин-кода 127 | ├── bundle-pin.zip - сертификат + закрытый ключ с пин-кодом 12345678 128 | └── bundle-private-key-only.zip - только закрытый ключ 129 | ``` 130 | 131 | Примеры: 132 | 133 | ``` 134 | # сертификат + закрытый ключ с пин-кодом 135 | cat certificates/bundle-pin.zip | docker exec -i cryptopro /scripts/my 12345678 136 | 137 | # сертификат + закрытый ключ БЕЗ пин-кода 138 | cat certificates/bundle-no-pin.zip | docker exec -i cryptopro /scripts/my 139 | 140 | # только сертификат 141 | cat certificates/bundle-cert-only.zip | docker exec -i cryptopro /scripts/my 142 | 143 | # только закрытый ключ 144 | cat certificates/bundle-private-key-only.zip | docker exec -i cryptopro /scripts/my 145 | 146 | # сертификат + закрытый ключ, название контейнера "тестовое название контейнера" (кириллица) 147 | cat certificates/bundle-cyrillic.zip | docker exec -i cryptopro /scripts/my 148 | ``` 149 | 150 | ![my-cert](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/my-cert.gif) 151 | 152 | ## Просмотр установленных сертификатов 153 | 154 | Сертификаты пользователя: 155 | 156 | ``` 157 | docker exec -i cryptopro certmgr -list 158 | ``` 159 | 160 | ![show-certs](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/show-certs.gif) 161 | 162 | Корневые сертификаты: 163 | 164 | ``` 165 | docker exec -i cryptopro certmgr -list -store root 166 | ``` 167 | 168 | ## Подписание документа 169 | 170 | Для примера установим этот тестовый сертификат: 171 | 172 | ``` 173 | # сертификат + закрытый ключ с пин-кодом 174 | cat certificates/bundle-pin.zip | docker exec -i cryptopro /scripts/my 12345678 175 | ``` 176 | 177 | Его SHA1 Hash равен `dd45247ab9db600dca42cc36c1141262fa60e3fe` (узнать: `certmgr -list`), который будем использовать как указатель нужного сертификата. 178 | 179 | Теперь передадим на `stdin` файл, в качестве команды - последовательность действий, и на `stdout` получим подписанный файл: 180 | 181 | ``` 182 | cat README.md | docker exec -i cryptopro sh -c 'tmp=`mktemp`; cat - > "$tmp"; cryptcp -sign -thumbprint dd45247ab9db600dca42cc36c1141262fa60e3fe -nochain -pin 12345678 "$tmp" "$tmp.sig" > /dev/null 2>&1; cat "$tmp.sig"; rm -f "$tmp" "$tmp.sig"' 183 | ``` 184 | 185 | Получилось довольно неудобно. Скрипт `scripts/sign` делает то же самое, теперь команда подписания будет выглядеть так: 186 | 187 | ``` 188 | cat README.md | docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678 189 | ``` 190 | 191 | ![sign](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/sign.gif) 192 | 193 | Об ошибке можно узнать через стандартный `$?`. 194 | 195 | ## Проверка подписи 196 | 197 | Подпишем файл из примера выше и сохраним его на диск: 198 | 199 | ``` 200 | cat README.md | docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678 > certificates/README.md.sig 201 | ``` 202 | 203 | Тогда проверка подписанного файла будет выглядеть так: 204 | 205 | ``` 206 | cat certificates/README.md.sig | docker exec -i cryptopro sh -c 'tmp=`mktemp`; cat - > "$tmp"; cryptcp -verify -norev -f "$tmp" "$tmp"; rm -f "$tmp"' 207 | ``` 208 | 209 | То же самое, но с использованием скрипта: 210 | 211 | ``` 212 | cat certificates/README.md.sig | docker exec -i cryptopro scripts/verify 213 | ``` 214 | 215 | ![verify](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/verify.gif) 216 | 217 | ## Получение исходного файла из sig-файла 218 | 219 | Возьмем файл из примера выше: 220 | 221 | ``` 222 | cat certificates/README.md.sig | docker exec -i cryptopro sh -c 'tmp=`mktemp`; cat - > "$tmp"; cryptcp -verify -nochain "$tmp" "$tmp.origin" > /dev/null 2>&1; cat "$tmp.origin"; rm -f "$tmp" "$tmp.origin"' 223 | ``` 224 | 225 | То же самое, но с использованием скрипта: 226 | 227 | ``` 228 | cat certificates/README.md.sig | docker exec -i cryptopro scripts/unsign 229 | ``` 230 | 231 | ![unsign](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/unsign.gif) 232 | 233 | ## Использование контейнера на удаленной машине 234 | 235 | В примерах выше команды выглядят так: `cat ... | docker ...` или `curl ... | docker ...`, то есть контейнер запущен на локальной машине. Если же докер контейнер запущен на удаленной машине, то команды нужно отправлять через ssh клиент. Например, команда подписания: 236 | 237 | ``` 238 | cat README.md | ssh -q user@host 'docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678' 239 | ``` 240 | 241 | Опция `-q` отключает приветствие из файла `/etc/banner` (хотя оно все равно пишется в `stderr`). А `/etc/motd` при выполнении команды по ssh не выводится. 242 | 243 | В качестве эксперимента можно отправить по ssh на свою же машину так: 244 | 245 | ``` 246 | # копируем публичный ключ на "удаленную машину" (на самом деле - localhost) 247 | ssh-copy-id $(whoami)@localhost 248 | # пробуем подписать 249 | cat README.md | ssh -q $(whoami)@localhost 'docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678' 250 | ``` 251 | 252 | # Работа с контейнером через HTTP REST-сервер 253 | 254 | Установка сертификатов осуществляется через командую строку. Все остальные действия доступны по HTTP. 255 | 256 | * `/healthcheck` - проверка работоспособности (`GET`) 257 | * `/certificates` - все установленные сертификаты пользователя (`GET`) 258 | * `/sign` - подписание документов (`POST`) 259 | * `/cosign` - добавление еще одной подписи к документу (`POST`) 260 | * `/verify` - проверка подписанного документа (`POST`) 261 | * `/unsign` - получение исходного файла без подписей (`POST`) 262 | 263 | ![rest](https://raw.githubusercontent.com/dbfun/cryptopro/master/assets/rest.gif) 264 | 265 | ## Формат данных 266 | 267 | Для `POST` данные должны поступать в теле запроса в формате `x-www-form-urlencoded`. 268 | 269 | Возвращаются данные в формате `JSON`. 270 | 271 | ## Обработка ошибок 272 | 273 | Успешные действия возвращают код `200` и `"status": "ok"`. 274 | 275 | Действия с ошибками возвращают `4xx` и `5xx` коды и `"status": "fail"`, в полях `errMsg` содержится описание ошибки, в `errCode` - ее код. 276 | 277 | Например, обращение с неправильным методом 278 | 279 | ```sh 280 | curl -sS -X POST --data-binary "bindata" http://localhost:8095/healthchecks 281 | ``` 282 | 283 | выведет такую ошибку: 284 | 285 | ```JSON 286 | {"status":"fail","errMsg":"Method must be one of: GET","errCode":405} 287 | ``` 288 | 289 | ## `/healthcheck` - проверка работоспособности 290 | 291 | Используется, чтобы убедиться в работоспособности сервиса. Например, так: `docker ps -f name=cryptopro` или `curl http://localhost:8095/healthcheck`. 292 | 293 | ## `/certificates` - все установленные сертификаты пользователя 294 | 295 | ``` 296 | curl -sS http://localhost:8095/certificates 297 | ``` 298 | 299 | Если сертификатов нет: 300 | 301 | ```JSON 302 | {"status":"fail","errMsg":"No certificates in store 'My'","errCode":404} 303 | ``` 304 | 305 | Если сертификаты есть: 306 | 307 | ```JSON 308 | { 309 | "certificates": [ 310 | { 311 | "privateKey": { 312 | "providerName": "Crypto-Pro GOST R 34.10-2012 KC1 CSP", 313 | "uniqueContainerName": "HDIMAGE\\\\eb5f6857.000\\D160", 314 | "containerName": "eb5f6857-a08a-4510-8a96-df2f75b6d65a" 315 | }, 316 | "algorithm": { 317 | "name": "ГОСТ Р 34.10-2012", 318 | "val": "1.2.643.7.1.1.1.1" 319 | }, 320 | "valid": { 321 | "to": "24.05.2019 08:13:16", 322 | "from": "24.02.2019 08:03:16" 323 | }, 324 | "issuer": { 325 | "E": "support@cryptopro.ru", 326 | "C": "RU", 327 | "L": "Moscow", 328 | "O": "CRYPTO-PRO LLC", 329 | "CN": "CRYPTO-PRO Test Center 2", 330 | "raw": "CN=CRYPTO-PRO Test Center 2, O=CRYPTO-PRO LLC, L=Moscow, C=RU, E=support@cryptopro.ru" 331 | }, 332 | "subject": { 333 | "C": "RU", 334 | "L": "Test", 335 | "O": "Test", 336 | "OU": "Test", 337 | "CN": "Test", 338 | "E": "test@test.ru", 339 | "raw": "E=test@test.ru, CN=Test, OU=Test, O=Test, L=Test, S=Test, C=RU" 340 | }, 341 | "thumbprint": "982AA9E713A2F99B10DAA07DCDC94A4BC32A1027", 342 | "serialNumber": "120032C3567443029CC358FCDF00000032C356", 343 | "hasPrivateKey": true 344 | } 345 | ], 346 | "status": "ok" 347 | } 348 | ``` 349 | 350 | ## `/sign` - подписание документов 351 | 352 | Для выбора сертификата для подписания нужно указать один критерии поиска `find_type`: 353 | 354 | * `sha1` - по SHA1 сертификата 355 | * `subject` - по `subject` подписанта 356 | 357 | В `query` - параметры поиска, в `pin` - пин-код (если он установлен): 358 | 359 | ```sh 360 | CERT_QUERY="find_type=sha1&query=82028260efc03eedc88dcb61c0f6a02e788e26e2&pin=12345678" 361 | curl -sS -X POST --data-binary @- "http://localhost:8095/sign?$CERT_QUERY" < README.md 362 | ``` 363 | 364 | Вернется `JSON` - документ, в `signedContent` будет содержаться подписанный файл. 365 | 366 | ## `/cosign` - добавление еще одной подписи к документу 367 | 368 | Не реализовано, столкнулся с проблемой: не получается заставить работать функцию `CPSignedData::CoSignCades()`. 369 | 370 | ## `/verify` - проверка подписанного документа 371 | 372 | Подпишем файл и проверим его: 373 | 374 | ```sh 375 | # подпишем файл 376 | CERT_QUERY="find_type=sha1&query=82028260efc03eedc88dcb61c0f6a02e788e26e2&pin=12345678" 377 | curl -sS -X POST --data-binary @- "http://localhost:8095/sign?$CERT_QUERY" < README.md > /tmp/file.json 378 | # извлечем подписанный файл из "signedContent" 379 | jq ".signedContent" --raw-output /tmp/file.json > /tmp/file.sig 380 | # проверим подписанный файл 381 | curl -sS -X POST --data-binary @- "http://localhost:8095/verify" < /tmp/file.sig 382 | ``` 383 | 384 | Если файл прошел проверку, вернется список подписантов `signers`. 385 | 386 | 387 | ## `/unsign` - получение исходного файла без подписей 388 | 389 | Исходный файл вернется в поле `content`. 390 | 391 | ```sh 392 | # получим из подписанного файла /tmp/file.sig оригинальный файл, он будет в "content" файла /tmp/unsig.json 393 | curl -sS -X POST --data-binary @- "http://localhost:8095/unsign" < /tmp/file.sig > /tmp/unsig.json 394 | # выведем на экран первые несколько строк 395 | jq ".content" --raw-output /tmp/unsig.json | base64 -d | head 396 | ``` 397 | 398 | 399 | ## Проблемы 400 | 401 | Если pin-код не подходит, то в терминал выводится: 402 | 403 | ``` 404 | Wrong pin, 2 tries left. 405 | 406 | CryptoPro CSP: Type password for container "eb5f6857-a08a-4510-8a96-df2f75b6d65a" 407 | Password: 408 | ``` 409 | 410 | И подписание останавливается. 411 | 412 | 413 | # Ссылки 414 | 415 | * [Страница расширения для PHP](http://cpdn.cryptopro.ru/default.asp?url=content/cades/phpcades.html) 416 | * [Тестовый УЦ](http://testca2012.cryptopro.ru/ui/), его сертификаты: [корневой](http://testca2012.cryptopro.ru/cert/rootca.cer), [промежуточный](http://testca2012.cryptopro.ru/cert/subca.cer) 417 | 418 | 419 | # Аналоги 420 | 421 | Существует аналогичный пакет [CryptoProCSP](https://github.com/taigasys/CryptoProCSP), он классный, но: 422 | 423 | * давно не обновлялся, используется версия `PHP5.6` 424 | * для запуска пришлось подредактировать `Dockerfile` 425 | -------------------------------------------------------------------------------- /assets/cacer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/cacer.gif -------------------------------------------------------------------------------- /assets/license.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/license.gif -------------------------------------------------------------------------------- /assets/my-cert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/my-cert.gif -------------------------------------------------------------------------------- /assets/rest.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/rest.gif -------------------------------------------------------------------------------- /assets/show-certs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/show-certs.gif -------------------------------------------------------------------------------- /assets/sign.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/sign.gif -------------------------------------------------------------------------------- /assets/unsign.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/unsign.gif -------------------------------------------------------------------------------- /assets/verify.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/assets/verify.gif -------------------------------------------------------------------------------- /certificates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/.gitkeep -------------------------------------------------------------------------------- /certificates/bundle-cert-only.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-cert-only.zip -------------------------------------------------------------------------------- /certificates/bundle-cosign.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-cosign.zip -------------------------------------------------------------------------------- /certificates/bundle-cyrillic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-cyrillic.zip -------------------------------------------------------------------------------- /certificates/bundle-no-pin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-no-pin.zip -------------------------------------------------------------------------------- /certificates/bundle-pin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-pin.zip -------------------------------------------------------------------------------- /certificates/bundle-private-key-only.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dbfun/cryptopro/769a880d9757da563e46858e2dd765463db71e0f/certificates/bundle-private-key-only.zip -------------------------------------------------------------------------------- /demo-cli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Демонстрация основных возможностей командной строки 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | source scripts/lib/colors.sh 9 | source scripts/lib/functions.sh 10 | 11 | warning 'Установка корневого сертификата' 12 | info 'curl -sS http://testca2012.cryptopro.ru/cert/rootca.cer | docker exec -i cryptopro /scripts/root' 13 | sleep 5 14 | echo 15 | curl -sS http://testca2012.cryptopro.ru/cert/rootca.cer | docker exec -i cryptopro /scripts/root 16 | 17 | echo 18 | sleep 2 19 | 20 | warning 'Установка сертификата + закрытый ключ' 21 | info 'cat certificates/bundle-pin.zip | docker exec -i cryptopro /scripts/my 12345678' 22 | sleep 5 23 | echo 24 | cat certificates/bundle-pin.zip | docker exec -i cryptopro /scripts/my 12345678 25 | 26 | echo 27 | sleep 2 28 | 29 | warning 'Подписание документа' 30 | info 'cat README.md | docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678' 31 | sleep 5 32 | echo 33 | cat README.md | docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678 34 | 35 | echo 36 | sleep 2 37 | 38 | warning 'Проверка подписи документа' 39 | info 'cat /tmp/README.md.sig | docker exec -i cryptopro scripts/verify' 40 | cat README.md | docker exec -i cryptopro /scripts/sign dd45247ab9db600dca42cc36c1141262fa60e3fe 12345678 > /tmp/README.md.sig 41 | sleep 5 42 | echo 43 | cat /tmp/README.md.sig | docker exec -i cryptopro scripts/verify 44 | -------------------------------------------------------------------------------- /demo-php.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Демонстрация работы PHP 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | source scripts/lib/colors.sh 9 | source scripts/lib/functions.sh 10 | 11 | warning 'Установка корневого сертификата' 12 | info 'curl -sS http://testca.cryptopro.ru/CertEnroll/test-ca-2014_CRYPTO-PRO%20Test%20Center%202.crt | docker exec -i cryptopro /scripts/root' 13 | sleep 5 14 | echo 15 | curl -sS http://testca.cryptopro.ru/CertEnroll/test-ca-2014_CRYPTO-PRO%20Test%20Center%202.crt | docker exec -i cryptopro /scripts/root 16 | 17 | echo 18 | sleep 2 19 | 20 | warning 'Установка сертификата + закрытый ключ' 21 | info 'cat certificates/bundle-Test.zip | docker exec -i cryptopro /scripts/my' 22 | sleep 5 23 | echo 24 | cat certificates/bundle-Test.zip | docker exec -i cryptopro /scripts/my 25 | 26 | echo 27 | sleep 2 28 | 29 | warning 'Проверка cryptopro в PHP' 30 | info 'docker exec -i cryptopro php /www/test_extension.php' 31 | sleep 5 32 | echo 33 | docker exec -i cryptopro php /www/test_extension.php 34 | -------------------------------------------------------------------------------- /demo-rest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Демонстрация работы REST сервера 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | source scripts/lib/colors.sh 9 | source scripts/lib/functions.sh 10 | 11 | REST_URI="http://localhost:8095" 12 | FILE_TO_SIGN="README.md" 13 | CERT_QUERY="find_type=sha1&query=82028260efc03eedc88dcb61c0f6a02e788e26e2&pin=12345678" 14 | 15 | # warning 'Установка корневого сертификата' 16 | curl -sS http://testca.cryptopro.ru/CertEnroll/test-ca-2014_CRYPTO-PRO%20Test%20Center%202.crt | docker exec -i cryptopro /scripts/root > /dev/null 17 | 18 | # warning 'Установка сертификатов пользователя' 19 | cat certificates/bundle-Test.zip | docker exec -i cryptopro /scripts/my > /dev/null 20 | cat certificates/bundle-cosign.zip | docker exec -i cryptopro /scripts/my 12345678 > /dev/null 21 | 22 | warning "Подписание файла $FILE_TO_SIGN" 23 | info "curl -sS -X POST --data-binary @- "$REST_URI/sign?$CERT_QUERY" < "$FILE_TO_SIGN" > /tmp/file.json" 24 | curl -sS -X POST --data-binary @- "$REST_URI/sign?$CERT_QUERY" < "$FILE_TO_SIGN" > /tmp/file.json 25 | 26 | jq .status "/tmp/file.json" 27 | 28 | echo 29 | sleep 3 30 | 31 | warning "Проверка подписи" 32 | jq ".signedContent" --raw-output /tmp/file.json > /tmp/file.sig 33 | info "curl -sS -X POST --data-binary @- "$REST_URI/verify" < /tmp/file.sig | jq .status" 34 | curl -sS -X POST --data-binary @- "$REST_URI/verify" < /tmp/file.sig | jq .status 35 | 36 | echo 37 | sleep 3 38 | 39 | warning "Получение исходного файла" 40 | info "curl -sS -X POST --data-binary @- "$REST_URI/unsign" < /tmp/file.sig > /tmp/unsig.json" 41 | curl -sS -X POST --data-binary @- "$REST_URI/unsign" < /tmp/file.sig > /tmp/unsig.json 42 | jq .status "/tmp/unsig.json" 43 | 44 | echo 45 | sleep 3 46 | 47 | warning "Первые несколько строк исходного файла" 48 | jq ".content" --raw-output /tmp/unsig.json | base64 -d | head -n5 49 | -------------------------------------------------------------------------------- /devel/attach.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # подключение к запущенному контейнеру 5 | # 6 | 7 | docker exec -it cryptopro sh -c "/bin/bash" 8 | -------------------------------------------------------------------------------- /devel/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # сборка образа 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | 9 | docker build --tag required/cryptopro ./../ 10 | -------------------------------------------------------------------------------- /devel/install-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Установка сертификатов для разработки 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | 9 | echo 'Установка корневого сертификата' 10 | # curl -sS http://testca2012.cryptopro.ru/cert/rootca.cer | docker exec -i cryptopro /scripts/root 11 | curl -sS http://testca.cryptopro.ru/CertEnroll/test-ca-2014_CRYPTO-PRO%20Test%20Center%202.crt | docker exec -i cryptopro /scripts/root 12 | 13 | echo 'Установка сертификатов' 14 | cat ../certificates/bundle-cosign.zip | docker exec -i cryptopro /scripts/my 12345678 15 | cat ../certificates/bundle-Test.zip | docker exec -i cryptopro /scripts/my 16 | -------------------------------------------------------------------------------- /devel/reflection.php: -------------------------------------------------------------------------------- 1 | showClasses(); 9 | echo '# Constants' . PHP_EOL . PHP_EOL; 10 | $this->showConstants(); 11 | } 12 | 13 | private function showClasses() 14 | { 15 | $classes = get_declared_classes(); 16 | 17 | $classes = array_filter($classes, function($name){ 18 | return preg_match('~^CP~i', $name); 19 | }); 20 | 21 | foreach($classes as $class) 22 | { 23 | echo $class . PHP_EOL; 24 | 25 | $reflectionClass = new \ReflectionClass($class); 26 | $methodsList = $reflectionClass->getMethods(); 27 | array_walk($methodsList, function($m){ 28 | if($m->name == '__construct') return; 29 | echo " " . $m->name . '()' . PHP_EOL; 30 | }); 31 | 32 | echo PHP_EOL; 33 | } 34 | } 35 | 36 | private function showConstants() { 37 | $constants = get_defined_constants(true); 38 | 39 | foreach ($constants['php_CPCSP'] as $k => $v) { 40 | echo $k . ' = ' . $v . PHP_EOL; 41 | } 42 | } 43 | 44 | 45 | 46 | } 47 | 48 | $e = new Explorer; 49 | $e->run(); 50 | -------------------------------------------------------------------------------- /devel/rest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # REST 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | source ../scripts/lib/colors.sh 9 | source ../scripts/lib/functions.sh 10 | 11 | REST_URI="http://localhost:8095" 12 | FILE_TO_SIGN="../README.md" 13 | 14 | CERT_QUERY="find_type=sha1&query=82028260efc03eedc88dcb61c0f6a02e788e26e2&pin=12345678" 15 | 16 | # Неверный метод 17 | # curl -sS -X POST --data-binary "bindata" "$REST_URI/healthcheck" 18 | 19 | # подписание документа 20 | curl -sS -X POST --data-binary @- "$REST_URI/sign?$CERT_QUERY" < "$FILE_TO_SIGN" > /tmp/file.json 21 | 22 | # проверка подписи 23 | jq ".signedContent" --raw-output /tmp/file.json > /tmp/file.sig 24 | 25 | # Не подходящий формат 26 | # curl -sS -X POST --data-binary @- "$REST_URI/verify" < /tmp/file.json 27 | 28 | # корректная проверка 29 | curl -sS -X POST --data-binary @- "$REST_URI/verify" < /tmp/file.sig 30 | 31 | # исходный файл 32 | curl -sS -X POST --data-binary @- "$REST_URI/unsign" < /tmp/file.sig > /tmp/unsig.json 33 | jq ".content" --raw-output /tmp/unsig.json | base64 -d | head 34 | 35 | # добавление еще одной подписи 36 | # CERT_QUERY="find_type=subject&query=Test" 37 | # curl -sS -X POST --data-binary @- "$REST_URI/cosign?$CERT_QUERY" < /tmp/file.sig 38 | -------------------------------------------------------------------------------- /scripts/lib/colors.sh: -------------------------------------------------------------------------------- 1 | # Библиотека цветов 2 | # Сброс 3 | Color_Off='\e[0m' # Text Reset 4 | Red='\e[1;31m' # Red 5 | Green='\e[1;32m' # Green 6 | Yellow='\e[1;33m' # Yellow 7 | Blue='\e[1;34m' # Blue 8 | Purple='\e[1;35m' # Purple 9 | Cyan='\e[1;36m' # Cyan 10 | White='\e[1;37m' # White 11 | UCyan='\e[4;36m' # Cyan 12 | -------------------------------------------------------------------------------- /scripts/lib/functions.sh: -------------------------------------------------------------------------------- 1 | function assert 2 | { 3 | SUBSTR=`echo "$1" | grep -q "$2"` 4 | if [ $? != 0 ]; then 5 | error "$3; Expected: $2" 6 | exit 1 7 | fi 8 | } 9 | 10 | function info 11 | { 12 | echo -e $Blue"$1"$Color_Off 13 | } 14 | 15 | function ok 16 | { 17 | echo -e $Green"$1"$Color_Off 18 | } 19 | 20 | function warning 21 | { 22 | echo -e $Yellow"$1"$Color_Off 23 | } 24 | 25 | function error 26 | { 27 | echo -e $Red"$1"$Color_Off 28 | } 29 | -------------------------------------------------------------------------------- /scripts/lib/root.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | 3 | set file [lindex $argv 0] 4 | 5 | spawn certmgr -inst -all -store uroot -file $file 6 | 7 | # Иногда "заедает" на '(o)OK, (c)Cancel', пауза должна решить проблему 8 | sleep 1 9 | 10 | while { 1 } { 11 | 12 | expect { 13 | "(o)OK, (c)Cancel" { 14 | send -- "o\r" 15 | sleep 1 16 | } 17 | eof { exit 0 } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /scripts/my: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Установка сертификатов пользователя для проверки и подписания 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | source lib/colors.sh 9 | source lib/functions.sh 10 | 11 | dir=`mktemp -d` 12 | cd "$dir" 13 | cat - > "bundle.zip" 14 | unzip -q bundle.zip 15 | rm bundle.zip 16 | 17 | # info "Temp dir: $dir" 18 | 19 | # проверка всех необходимых файлов в закрытом ключе 20 | function testprivk { 21 | [ ! -f "$contShortName/header.key" ] && error "File header.key not found in $contShortName" && exit 1 22 | [ ! -f "$contShortName/masks.key" ] && error "File masks.key not found in $contShortName" && exit 1 23 | [ ! -f "$contShortName/masks2.key" ] && error "File masks2.key not found in $contShortName" && exit 1 24 | [ ! -f "$contShortName/name.key" ] && error "File name.key not found in $contShortName" && exit 1 25 | [ ! -f "$contShortName/primary.key" ] && error "File primary.key not found in $contShortName" && exit 1 26 | [ ! -f "$contShortName/primary2.key" ] && error "File primary2.key not found in $contShortName" && exit 1 27 | } 28 | 29 | # для связки закрытого ключа с сертификатом необходимо указать полное наименование контейнера, которое находится в name.key 30 | # таким способо также можно выяснить название, но с cp1251 работает не устойчиво 31 | # function findContFullName { 32 | # contFullName=`csptest -keyset -enum_cont -verifycontext -unique | grep --fixed-strings "$contShortName" | cut -d '|' -f1` 33 | # if [ ! -n "$contFullName" ]; then 34 | # error "Proper container not found by short name: $contShortName" 35 | # exit 1 36 | # fi 37 | # } 38 | 39 | # xargs удаляет `./` из названия файла 40 | certFileName=`find -maxdepth 1 -type f \! -name . | head -n1 | xargs -I{} basename {}` 41 | contShortName=`find -maxdepth 1 -type d \! -name . | head -n1 | xargs -I{} basename {}` 42 | contFullName=`tail -c+5 "$contShortName/name.key"` 43 | 44 | # Есть контейнер, устанавливаем 45 | if [ -n "$contShortName" ]; then 46 | info "Key container short name: $contShortName" 47 | testprivk 48 | cp -R "$contShortName" /var/opt/cprocsp/keys/root/ 49 | if [ "$?" -eq "0" ]; then 50 | ok "Key container installed" 51 | fi 52 | fi 53 | 54 | # Есть сертификат 55 | if [ -n "$certFileName" ]; then 56 | 57 | if [ ! -n "$contShortName" ]; then 58 | # устанавливается только сертификат 59 | certmgr -inst -file "$certFileName" 60 | 61 | if [ "$?" -eq "0" ]; then 62 | ok "Certificate installed" 63 | warning "No PrivateKey Link" 64 | fi 65 | 66 | else 67 | 68 | # устанавливается сертификат + контейнер, нужно их связать ('PrivateKey Link') 69 | 70 | info "Key container full name: $contFullName" | iconv -fcp1251 -tutf-8 71 | 72 | if [ -z "$1" ]; then 73 | # нет PIN 74 | certmgr -inst -file "$certFileName" -cont '\\.\HDIMAGE\'"$contFullName" 75 | else 76 | # есть PIN 77 | certmgr -inst -file "$certFileName" -pin "$1" -cont '\\.\HDIMAGE\'"$contFullName" 78 | fi 79 | 80 | if [ "$?" -eq "0" ]; then 81 | ok "Certificate installed with PrivateKey Link" 82 | fi 83 | 84 | fi 85 | 86 | 87 | fi 88 | 89 | rm -rf "$dir" 90 | 91 | # certmgr -list 92 | -------------------------------------------------------------------------------- /scripts/root: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Установка корневых сертификатов 5 | # 6 | 7 | cd "$(dirname "$0")" 8 | 9 | file=`mktemp` 10 | cat - > "$file" 11 | 12 | ./lib/root.exp "$file" 13 | rm -f "$file" 14 | -------------------------------------------------------------------------------- /scripts/sign: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Подписание документа 5 | # 6 | 7 | tmp=`mktemp` 8 | cat - > "$tmp" 9 | cryptcp -sign -thumbprint "$1" -nochain -pin "$2" "$tmp" "$tmp.sig" > /dev/null 2>&1 10 | signResult=$? 11 | if [ "$signResult" != "0" ]; then 12 | rm -f "$tmp" "$tmp.sig" 13 | exit $signResult 14 | fi 15 | cat "$tmp.sig" 16 | rm -f "$tmp" "$tmp.sig" 17 | -------------------------------------------------------------------------------- /scripts/unsign: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Получение исходного файла из sig-файла 5 | # 6 | 7 | tmp=`mktemp` 8 | cat - > "$tmp" 9 | cryptcp -verify -nochain "$tmp" "$tmp.origin" > /dev/null 2>&1 10 | signResult=$? 11 | if [ "$signResult" != "0" ]; then 12 | rm -f "$tmp" "$tmp.origin" 13 | exit $signResult 14 | fi 15 | cat "$tmp.origin" 16 | rm -f "$tmp" "$tmp.origin" 17 | -------------------------------------------------------------------------------- /scripts/verify: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Проверка подписи 5 | # 6 | 7 | tmp=`mktemp` 8 | cat - > "$tmp" 9 | cryptcp -verify -norev -f "$tmp" "$tmp" 10 | signResult=$? 11 | rm -f "$tmp" 12 | if [ "$signResult" != "0" ]; then 13 | exit $signResult 14 | fi 15 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /logs/* 3 | !/logs/README.md 4 | -------------------------------------------------------------------------------- /www/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | ## Pull Requests 4 | 5 | 1. Fork the Slim Skeleton repository 6 | 2. Create a new branch for each feature or improvement 7 | 3. Send a pull request from each feature branch to the **3.x** branch 8 | 9 | It is very important to separate new features or improvements into separate feature branches, and to send a 10 | pull request for each branch. This allows us to review and pull in new features or improvements individually. 11 | 12 | ## Style Guide 13 | 14 | All pull requests must adhere to the [PSR-2 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). 15 | -------------------------------------------------------------------------------- /www/README.md: -------------------------------------------------------------------------------- 1 | # Slim Framework 3 Skeleton Application 2 | 3 | Use this skeleton application to quickly setup and start working on a new Slim Framework 3 application. This application uses the latest Slim 3 with the PHP-View template renderer. It also uses the Monolog logger. 4 | 5 | This skeleton application was built for Composer. This makes setting up a new Slim Framework application quick and easy. 6 | 7 | ## Install the Application 8 | 9 | Run this command from the directory in which you want to install your new Slim Framework application. 10 | 11 | php composer.phar create-project slim/slim-skeleton [my-app-name] 12 | 13 | Replace `[my-app-name]` with the desired directory name for your new application. You'll want to: 14 | 15 | * Point your virtual host document root to your new application's `public/` directory. 16 | * Ensure `logs/` is web writeable. 17 | 18 | To run the application in development, you can run these commands 19 | 20 | cd [my-app-name] 21 | php composer.phar start 22 | 23 | Run this command in the application directory to run the test suite 24 | 25 | php composer.phar test 26 | 27 | That's it! Now go build something cool. 28 | -------------------------------------------------------------------------------- /www/app/Certificate/Finder.php: -------------------------------------------------------------------------------- 1 | CERTIFICATE_FIND_SHA1_HASH, 10 | 'subject' => CERTIFICATE_FIND_SUBJECT_NAME 11 | ]; 12 | 13 | public function findType($find_type) 14 | { 15 | $this->findType =& self::$findTypeMap[$find_type]; 16 | if(!isset($this->findType)) 17 | { 18 | throw new \App\Exception("No such find_type", 404); 19 | } 20 | return $this; 21 | } 22 | 23 | public function query($query) 24 | { 25 | $this->query = $query; 26 | return $this; 27 | } 28 | 29 | public function fetch() 30 | { 31 | $store = new \CPStore(); 32 | $store->Open(CURRENT_USER_STORE, 'My', STORE_OPEN_READ_ONLY); 33 | $this->certs = $store->get_Certificates(); 34 | if($this->certs->Count() === 0) 35 | { 36 | throw new \App\Exception("No certificates in store 'My'", 404); 37 | } 38 | 39 | if(isset($this->findType)) 40 | { 41 | // 3 парамет - $valid_only 42 | $this->certs = $this->certs->Find($this->findType, $this->query, false); 43 | } 44 | 45 | return $this; 46 | } 47 | 48 | public function count() { 49 | return $this->certs->Count(); 50 | } 51 | 52 | public function get() 53 | { 54 | return $this->certs; 55 | } 56 | 57 | public function first() 58 | { 59 | return $this->certs->Item(1); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /www/app/Certificate/Info.php: -------------------------------------------------------------------------------- 1 | CAPICOM_CERT_INFO_*_EMAIL_NAME и CAPICOM_CERT_INFO_*_UPN и CAPICOM_CERT_INFO_*_DNS_NAME не поддерживаются криптопровайдером на Unix платформах. 10 | > Если email в RDN то можно получить всю строку с subject и достать email оттуда. 11 | 12 | @see https://www.cryptopro.ru/forum2/default.aspx?g=posts&m=72528#post72528 13 | 14 | */ 15 | 16 | class Info { 17 | 18 | public function __construct(\CPCertificate $cert) 19 | { 20 | $this->cert = $cert; 21 | } 22 | 23 | public function get() 24 | { 25 | $ret = [ 26 | 'hasPrivateKey' => $this->cert->HasPrivateKey(), 27 | 'serialNumber' => $this->cert->get_SerialNumber(), 28 | 'thumbprint' => $this->cert->get_Thumbprint(), 29 | 'subject' => $this->parseMeta($this->cert->get_SubjectName()), 30 | 'issuer' => $this->parseMeta($this->cert->get_IssuerName()), 31 | 'valid' => [ 32 | 'from' => $this->cert->get_ValidFromDate(), 33 | 'to' => $this->cert->get_ValidToDate(), 34 | ] 35 | ]; 36 | 37 | try { 38 | $algo = $this->cert->PublicKey()->get_Algorithm(); 39 | $ret['algorithm'] = [ 40 | 'val' => $algo->get_Value(), 41 | 'name' => $algo->get_FriendlyName() 42 | ]; 43 | } catch (\Exception $e) { } 44 | 45 | try { 46 | $pk = $this->cert->PrivateKey(); 47 | $ret['privateKey'] = [ 48 | 'containerName' => $pk->get_ContainerName(), 49 | 'uniqueContainerName' => $pk->get_UniqueContainerName(), 50 | 'providerName' => $pk->get_ProviderName() 51 | ]; 52 | } catch (\Exception $e) { } 53 | 54 | 55 | return $ret; 56 | 57 | } 58 | 59 | private function parseMeta($str) { 60 | $ret = [ 61 | 'raw' => $str 62 | ]; 63 | if(preg_match_all('~(emailAddress|E|C|L|O|CN|OU|T|SN|G)=([^,]*)~', $str . ',', $m)) { 64 | foreach($m[1] as $idx => $key) { 65 | $ret[$key] = stripslashes($m[2][$idx]); 66 | } 67 | } 68 | return $ret; 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /www/app/Controller.php: -------------------------------------------------------------------------------- 1 | withJson(['status' => 'ok', 'php_sapi_name' => php_sapi_name()]); 14 | } 15 | 16 | public function certificates(Request $request, Response $response, array $args) 17 | { 18 | $CertFinder = new Certificate\Finder; 19 | $certificates = $CertFinder-> 20 | fetch()-> 21 | get(); 22 | $data = [ 23 | 'status' => 'ok', 24 | 'certificates' => $this->getCertsInfo($certificates) 25 | ]; 26 | 27 | return $response->withJson($data); 28 | } 29 | 30 | public function unsign(Request $request, Response $response, array $args) 31 | { 32 | $this->getFile($request); 33 | $this->checkEmptyFile(); 34 | 35 | $sd = new \CPSignedData; 36 | $sd->set_ContentEncoding(ENCODE_BINARY); 37 | $sd->set_Content($this->content); 38 | // одновременно "расшифровывает" 39 | $sd->VerifyCades($this->content, CADES_BES, false); 40 | 41 | $data = [ 42 | 'status' => 'ok', 43 | 'content' => $sd->get_Content() 44 | ]; 45 | 46 | return $response->withJson($data); 47 | } 48 | 49 | public function sign(Request $request, Response $response, array $args) 50 | { 51 | $this->getFile($request); 52 | $this->checkEmptyFile(); 53 | $cert = $this->getCertByQuery($request); 54 | 55 | $signer = new \CPSigner(); 56 | // $signer->set_TSAAddress($address); // Опционально? 57 | $signer->set_Certificate($cert); 58 | $pin = $request->getQueryParams()['pin']; 59 | if(strlen($pin)) 60 | { 61 | $signer->set_KeyPin($pin); 62 | } 63 | 64 | $sd = new \CPSignedData; 65 | $sd->set_ContentEncoding(ENCODE_BINARY); 66 | $sd->set_Content(base64_encode($this->content)); 67 | 68 | // Второй параметр - тип подписи(1 = CADES_BES): http://cpdn.cryptopro.ru/default.asp?url=content/cades/namespace_c_ad_e_s_c_o_m_fe49883d8ff77f7edbeeaf0be3d44c0b_1fe49883d8ff77f7edbeeaf0be3d44c0b.html 69 | // Третий параметр detached - отделенная(true) или совмещенная (false) 70 | $this->signedContent = $sd->SignCades($signer, CADES_BES, false, 0); 71 | 72 | $data = [ 73 | 'status' => 'ok', 74 | 'signedContent' => $this->signedContent 75 | ]; 76 | 77 | try { 78 | $CertInfo = new Certificate\Info($cert); 79 | $data['cert'] = $CertInfo->get(); 80 | } catch (\Exception $e) { } 81 | 82 | return $response->withJson($data); 83 | } 84 | 85 | public function verify(Request $request, Response $response, array $args) 86 | { 87 | $this->getFile($request); 88 | $this->checkEmptyFile(); 89 | 90 | $sd = new \CPSignedData; 91 | $sd->set_ContentEncoding(BASE64_TO_BINARY); 92 | $sd->set_Content($this->content); 93 | // Бросает исключение 94 | $sd->VerifyCades($this->content, CADES_BES, false); 95 | 96 | $data = [ 97 | 'status' => 'ok' 98 | ]; 99 | 100 | $signers = $sd->get_Signers(); 101 | $data['signers'] = $this->getSignersInfo($signers); 102 | 103 | // Возможно получить все сертификаты, в том числе просто приложенные 104 | // $certificates = $sd->get_Certificates(); 105 | // $data['certificates'] = $this->getCertsInfo($certificates); 106 | 107 | return $response->withJson($data); 108 | } 109 | 110 | ///////////////////////////////////////// PRIVATE 111 | 112 | private function getFile($request) 113 | { 114 | $this->content = $request->getBody()->getContents(); 115 | } 116 | 117 | private function checkEmptyFile() 118 | { 119 | if(strlen($this->content) === 0) 120 | { 121 | throw new \App\Exception("Empty file", 449); 122 | } 123 | } 124 | 125 | private function getCertByQuery(Request $request) 126 | { 127 | $CertFinder = new Certificate\Finder; 128 | $cert = $CertFinder-> 129 | findType($request->getQueryParams()['find_type'])-> 130 | query($request->getQueryParams()['query'])-> 131 | fetch()-> 132 | first(); 133 | return $cert; 134 | } 135 | 136 | private function getCertsInfo(\CPCertificates $certificates) 137 | { 138 | $ret = []; 139 | for($i = 1; $i <= $certificates->Count(); $i++) 140 | { 141 | $cert = $certificates->Item($i); 142 | $CertInfo = new Certificate\Info($cert); 143 | $ret[] = $CertInfo->get(); 144 | } 145 | return $ret; 146 | } 147 | 148 | private function getSignersInfo(\CPSigners $signers) 149 | { 150 | $ret = []; 151 | for($i = 1; $i <= $signers->get_Count(); $i++) 152 | { 153 | $cert = $signers->get_Item($i)->get_Certificate(); 154 | $CertInfo = new Certificate\Info($cert); 155 | $ret[] = $CertInfo->get(); 156 | } 157 | return $ret; 158 | } 159 | 160 | 161 | 162 | 163 | } 164 | -------------------------------------------------------------------------------- /www/app/Exception.php: -------------------------------------------------------------------------------- 1 | =5.5.0", 16 | "slim/slim": "^3.1", 17 | "slim/php-view": "^2.0", 18 | "monolog/monolog": "^1.17" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": ">=4.8 < 6.0" 22 | }, 23 | "autoload-dev": { 24 | "psr-4": { 25 | "Tests\\": "tests/", 26 | "App\\": "app/" 27 | } 28 | }, 29 | "config": { 30 | "process-timeout" : 0 31 | }, 32 | "scripts": { 33 | "start": "php -S localhost:8080 -t public", 34 | "test": "phpunit" 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /www/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "5e16cb7781829836a704bd8767830833", 8 | "packages": [ 9 | { 10 | "name": "container-interop/container-interop", 11 | "version": "1.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/container-interop/container-interop.git", 15 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", 20 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "psr/container": "^1.0" 25 | }, 26 | "type": "library", 27 | "autoload": { 28 | "psr-4": { 29 | "Interop\\Container\\": "src/Interop/Container/" 30 | } 31 | }, 32 | "notification-url": "https://packagist.org/downloads/", 33 | "license": [ 34 | "MIT" 35 | ], 36 | "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", 37 | "homepage": "https://github.com/container-interop/container-interop", 38 | "time": "2017-02-14T19:40:03+00:00" 39 | }, 40 | { 41 | "name": "monolog/monolog", 42 | "version": "1.24.0", 43 | "source": { 44 | "type": "git", 45 | "url": "https://github.com/Seldaek/monolog.git", 46 | "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" 47 | }, 48 | "dist": { 49 | "type": "zip", 50 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", 51 | "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", 52 | "shasum": "" 53 | }, 54 | "require": { 55 | "php": ">=5.3.0", 56 | "psr/log": "~1.0" 57 | }, 58 | "provide": { 59 | "psr/log-implementation": "1.0.0" 60 | }, 61 | "require-dev": { 62 | "aws/aws-sdk-php": "^2.4.9 || ^3.0", 63 | "doctrine/couchdb": "~1.0@dev", 64 | "graylog2/gelf-php": "~1.0", 65 | "jakub-onderka/php-parallel-lint": "0.9", 66 | "php-amqplib/php-amqplib": "~2.4", 67 | "php-console/php-console": "^3.1.3", 68 | "phpunit/phpunit": "~4.5", 69 | "phpunit/phpunit-mock-objects": "2.3.0", 70 | "ruflin/elastica": ">=0.90 <3.0", 71 | "sentry/sentry": "^0.13", 72 | "swiftmailer/swiftmailer": "^5.3|^6.0" 73 | }, 74 | "suggest": { 75 | "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", 76 | "doctrine/couchdb": "Allow sending log messages to a CouchDB server", 77 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 78 | "ext-mongo": "Allow sending log messages to a MongoDB server", 79 | "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", 80 | "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", 81 | "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", 82 | "php-console/php-console": "Allow sending log messages to Google Chrome", 83 | "rollbar/rollbar": "Allow sending log messages to Rollbar", 84 | "ruflin/elastica": "Allow sending log messages to an Elastic Search server", 85 | "sentry/sentry": "Allow sending log messages to a Sentry server" 86 | }, 87 | "type": "library", 88 | "extra": { 89 | "branch-alias": { 90 | "dev-master": "2.0.x-dev" 91 | } 92 | }, 93 | "autoload": { 94 | "psr-4": { 95 | "Monolog\\": "src/Monolog" 96 | } 97 | }, 98 | "notification-url": "https://packagist.org/downloads/", 99 | "license": [ 100 | "MIT" 101 | ], 102 | "authors": [ 103 | { 104 | "name": "Jordi Boggiano", 105 | "email": "j.boggiano@seld.be", 106 | "homepage": "http://seld.be" 107 | } 108 | ], 109 | "description": "Sends your logs to files, sockets, inboxes, databases and various web services", 110 | "homepage": "http://github.com/Seldaek/monolog", 111 | "keywords": [ 112 | "log", 113 | "logging", 114 | "psr-3" 115 | ], 116 | "time": "2018-11-05T09:00:11+00:00" 117 | }, 118 | { 119 | "name": "nikic/fast-route", 120 | "version": "v1.3.0", 121 | "source": { 122 | "type": "git", 123 | "url": "https://github.com/nikic/FastRoute.git", 124 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812" 125 | }, 126 | "dist": { 127 | "type": "zip", 128 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", 129 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812", 130 | "shasum": "" 131 | }, 132 | "require": { 133 | "php": ">=5.4.0" 134 | }, 135 | "require-dev": { 136 | "phpunit/phpunit": "^4.8.35|~5.7" 137 | }, 138 | "type": "library", 139 | "autoload": { 140 | "psr-4": { 141 | "FastRoute\\": "src/" 142 | }, 143 | "files": [ 144 | "src/functions.php" 145 | ] 146 | }, 147 | "notification-url": "https://packagist.org/downloads/", 148 | "license": [ 149 | "BSD-3-Clause" 150 | ], 151 | "authors": [ 152 | { 153 | "name": "Nikita Popov", 154 | "email": "nikic@php.net" 155 | } 156 | ], 157 | "description": "Fast request router for PHP", 158 | "keywords": [ 159 | "router", 160 | "routing" 161 | ], 162 | "time": "2018-02-13T20:26:39+00:00" 163 | }, 164 | { 165 | "name": "pimple/pimple", 166 | "version": "v3.2.3", 167 | "source": { 168 | "type": "git", 169 | "url": "https://github.com/silexphp/Pimple.git", 170 | "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" 171 | }, 172 | "dist": { 173 | "type": "zip", 174 | "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", 175 | "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", 176 | "shasum": "" 177 | }, 178 | "require": { 179 | "php": ">=5.3.0", 180 | "psr/container": "^1.0" 181 | }, 182 | "require-dev": { 183 | "symfony/phpunit-bridge": "^3.2" 184 | }, 185 | "type": "library", 186 | "extra": { 187 | "branch-alias": { 188 | "dev-master": "3.2.x-dev" 189 | } 190 | }, 191 | "autoload": { 192 | "psr-0": { 193 | "Pimple": "src/" 194 | } 195 | }, 196 | "notification-url": "https://packagist.org/downloads/", 197 | "license": [ 198 | "MIT" 199 | ], 200 | "authors": [ 201 | { 202 | "name": "Fabien Potencier", 203 | "email": "fabien@symfony.com" 204 | } 205 | ], 206 | "description": "Pimple, a simple Dependency Injection Container", 207 | "homepage": "http://pimple.sensiolabs.org", 208 | "keywords": [ 209 | "container", 210 | "dependency injection" 211 | ], 212 | "time": "2018-01-21T07:42:36+00:00" 213 | }, 214 | { 215 | "name": "psr/container", 216 | "version": "1.0.0", 217 | "source": { 218 | "type": "git", 219 | "url": "https://github.com/php-fig/container.git", 220 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 221 | }, 222 | "dist": { 223 | "type": "zip", 224 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 225 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 226 | "shasum": "" 227 | }, 228 | "require": { 229 | "php": ">=5.3.0" 230 | }, 231 | "type": "library", 232 | "extra": { 233 | "branch-alias": { 234 | "dev-master": "1.0.x-dev" 235 | } 236 | }, 237 | "autoload": { 238 | "psr-4": { 239 | "Psr\\Container\\": "src/" 240 | } 241 | }, 242 | "notification-url": "https://packagist.org/downloads/", 243 | "license": [ 244 | "MIT" 245 | ], 246 | "authors": [ 247 | { 248 | "name": "PHP-FIG", 249 | "homepage": "http://www.php-fig.org/" 250 | } 251 | ], 252 | "description": "Common Container Interface (PHP FIG PSR-11)", 253 | "homepage": "https://github.com/php-fig/container", 254 | "keywords": [ 255 | "PSR-11", 256 | "container", 257 | "container-interface", 258 | "container-interop", 259 | "psr" 260 | ], 261 | "time": "2017-02-14T16:28:37+00:00" 262 | }, 263 | { 264 | "name": "psr/http-message", 265 | "version": "1.0.1", 266 | "source": { 267 | "type": "git", 268 | "url": "https://github.com/php-fig/http-message.git", 269 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 270 | }, 271 | "dist": { 272 | "type": "zip", 273 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 274 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 275 | "shasum": "" 276 | }, 277 | "require": { 278 | "php": ">=5.3.0" 279 | }, 280 | "type": "library", 281 | "extra": { 282 | "branch-alias": { 283 | "dev-master": "1.0.x-dev" 284 | } 285 | }, 286 | "autoload": { 287 | "psr-4": { 288 | "Psr\\Http\\Message\\": "src/" 289 | } 290 | }, 291 | "notification-url": "https://packagist.org/downloads/", 292 | "license": [ 293 | "MIT" 294 | ], 295 | "authors": [ 296 | { 297 | "name": "PHP-FIG", 298 | "homepage": "http://www.php-fig.org/" 299 | } 300 | ], 301 | "description": "Common interface for HTTP messages", 302 | "homepage": "https://github.com/php-fig/http-message", 303 | "keywords": [ 304 | "http", 305 | "http-message", 306 | "psr", 307 | "psr-7", 308 | "request", 309 | "response" 310 | ], 311 | "time": "2016-08-06T14:39:51+00:00" 312 | }, 313 | { 314 | "name": "psr/log", 315 | "version": "1.1.0", 316 | "source": { 317 | "type": "git", 318 | "url": "https://github.com/php-fig/log.git", 319 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" 320 | }, 321 | "dist": { 322 | "type": "zip", 323 | "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 324 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 325 | "shasum": "" 326 | }, 327 | "require": { 328 | "php": ">=5.3.0" 329 | }, 330 | "type": "library", 331 | "extra": { 332 | "branch-alias": { 333 | "dev-master": "1.0.x-dev" 334 | } 335 | }, 336 | "autoload": { 337 | "psr-4": { 338 | "Psr\\Log\\": "Psr/Log/" 339 | } 340 | }, 341 | "notification-url": "https://packagist.org/downloads/", 342 | "license": [ 343 | "MIT" 344 | ], 345 | "authors": [ 346 | { 347 | "name": "PHP-FIG", 348 | "homepage": "http://www.php-fig.org/" 349 | } 350 | ], 351 | "description": "Common interface for logging libraries", 352 | "homepage": "https://github.com/php-fig/log", 353 | "keywords": [ 354 | "log", 355 | "psr", 356 | "psr-3" 357 | ], 358 | "time": "2018-11-20T15:27:04+00:00" 359 | }, 360 | { 361 | "name": "slim/php-view", 362 | "version": "2.2.0", 363 | "source": { 364 | "type": "git", 365 | "url": "https://github.com/slimphp/PHP-View.git", 366 | "reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f" 367 | }, 368 | "dist": { 369 | "type": "zip", 370 | "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/122ed121a8d9cf91a94020814d2a3ee6c836754f", 371 | "reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f", 372 | "shasum": "" 373 | }, 374 | "require": { 375 | "psr/http-message": "^1.0" 376 | }, 377 | "require-dev": { 378 | "phpunit/phpunit": "^4.8", 379 | "slim/slim": "^3.0" 380 | }, 381 | "type": "library", 382 | "autoload": { 383 | "psr-4": { 384 | "Slim\\Views\\": "src" 385 | } 386 | }, 387 | "notification-url": "https://packagist.org/downloads/", 388 | "license": [ 389 | "MIT" 390 | ], 391 | "authors": [ 392 | { 393 | "name": "Glenn Eggleton", 394 | "email": "geggleto@gmail.com" 395 | } 396 | ], 397 | "description": "Render PHP view scripts into a PSR-7 Response object.", 398 | "keywords": [ 399 | "framework", 400 | "php", 401 | "phtml", 402 | "renderer", 403 | "slim", 404 | "template", 405 | "view" 406 | ], 407 | "time": "2016-10-11T07:43:08+00:00" 408 | }, 409 | { 410 | "name": "slim/slim", 411 | "version": "3.12.0", 412 | "source": { 413 | "type": "git", 414 | "url": "https://github.com/slimphp/Slim.git", 415 | "reference": "f4947cc900b6e51cbfda58b9f1247bca2f76f9f0" 416 | }, 417 | "dist": { 418 | "type": "zip", 419 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/f4947cc900b6e51cbfda58b9f1247bca2f76f9f0", 420 | "reference": "f4947cc900b6e51cbfda58b9f1247bca2f76f9f0", 421 | "shasum": "" 422 | }, 423 | "require": { 424 | "container-interop/container-interop": "^1.2", 425 | "nikic/fast-route": "^1.0", 426 | "php": ">=5.5.0", 427 | "pimple/pimple": "^3.0", 428 | "psr/container": "^1.0", 429 | "psr/http-message": "^1.0" 430 | }, 431 | "provide": { 432 | "psr/http-message-implementation": "1.0" 433 | }, 434 | "require-dev": { 435 | "phpunit/phpunit": "^4.0", 436 | "squizlabs/php_codesniffer": "^2.5" 437 | }, 438 | "type": "library", 439 | "autoload": { 440 | "psr-4": { 441 | "Slim\\": "Slim" 442 | } 443 | }, 444 | "notification-url": "https://packagist.org/downloads/", 445 | "license": [ 446 | "MIT" 447 | ], 448 | "authors": [ 449 | { 450 | "name": "Rob Allen", 451 | "email": "rob@akrabat.com", 452 | "homepage": "http://akrabat.com" 453 | }, 454 | { 455 | "name": "Josh Lockhart", 456 | "email": "hello@joshlockhart.com", 457 | "homepage": "https://joshlockhart.com" 458 | }, 459 | { 460 | "name": "Gabriel Manricks", 461 | "email": "gmanricks@me.com", 462 | "homepage": "http://gabrielmanricks.com" 463 | }, 464 | { 465 | "name": "Andrew Smith", 466 | "email": "a.smith@silentworks.co.uk", 467 | "homepage": "http://silentworks.co.uk" 468 | } 469 | ], 470 | "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", 471 | "homepage": "https://slimframework.com", 472 | "keywords": [ 473 | "api", 474 | "framework", 475 | "micro", 476 | "router" 477 | ], 478 | "time": "2019-01-15T13:21:25+00:00" 479 | } 480 | ], 481 | "packages-dev": [ 482 | { 483 | "name": "doctrine/instantiator", 484 | "version": "1.1.0", 485 | "source": { 486 | "type": "git", 487 | "url": "https://github.com/doctrine/instantiator.git", 488 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" 489 | }, 490 | "dist": { 491 | "type": "zip", 492 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 493 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 494 | "shasum": "" 495 | }, 496 | "require": { 497 | "php": "^7.1" 498 | }, 499 | "require-dev": { 500 | "athletic/athletic": "~0.1.8", 501 | "ext-pdo": "*", 502 | "ext-phar": "*", 503 | "phpunit/phpunit": "^6.2.3", 504 | "squizlabs/php_codesniffer": "^3.0.2" 505 | }, 506 | "type": "library", 507 | "extra": { 508 | "branch-alias": { 509 | "dev-master": "1.2.x-dev" 510 | } 511 | }, 512 | "autoload": { 513 | "psr-4": { 514 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 515 | } 516 | }, 517 | "notification-url": "https://packagist.org/downloads/", 518 | "license": [ 519 | "MIT" 520 | ], 521 | "authors": [ 522 | { 523 | "name": "Marco Pivetta", 524 | "email": "ocramius@gmail.com", 525 | "homepage": "http://ocramius.github.com/" 526 | } 527 | ], 528 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 529 | "homepage": "https://github.com/doctrine/instantiator", 530 | "keywords": [ 531 | "constructor", 532 | "instantiate" 533 | ], 534 | "time": "2017-07-22T11:58:36+00:00" 535 | }, 536 | { 537 | "name": "myclabs/deep-copy", 538 | "version": "1.8.1", 539 | "source": { 540 | "type": "git", 541 | "url": "https://github.com/myclabs/DeepCopy.git", 542 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" 543 | }, 544 | "dist": { 545 | "type": "zip", 546 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 547 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 548 | "shasum": "" 549 | }, 550 | "require": { 551 | "php": "^7.1" 552 | }, 553 | "replace": { 554 | "myclabs/deep-copy": "self.version" 555 | }, 556 | "require-dev": { 557 | "doctrine/collections": "^1.0", 558 | "doctrine/common": "^2.6", 559 | "phpunit/phpunit": "^7.1" 560 | }, 561 | "type": "library", 562 | "autoload": { 563 | "psr-4": { 564 | "DeepCopy\\": "src/DeepCopy/" 565 | }, 566 | "files": [ 567 | "src/DeepCopy/deep_copy.php" 568 | ] 569 | }, 570 | "notification-url": "https://packagist.org/downloads/", 571 | "license": [ 572 | "MIT" 573 | ], 574 | "description": "Create deep copies (clones) of your objects", 575 | "keywords": [ 576 | "clone", 577 | "copy", 578 | "duplicate", 579 | "object", 580 | "object graph" 581 | ], 582 | "time": "2018-06-11T23:09:50+00:00" 583 | }, 584 | { 585 | "name": "phpdocumentor/reflection-common", 586 | "version": "1.0.1", 587 | "source": { 588 | "type": "git", 589 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 590 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 591 | }, 592 | "dist": { 593 | "type": "zip", 594 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 595 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 596 | "shasum": "" 597 | }, 598 | "require": { 599 | "php": ">=5.5" 600 | }, 601 | "require-dev": { 602 | "phpunit/phpunit": "^4.6" 603 | }, 604 | "type": "library", 605 | "extra": { 606 | "branch-alias": { 607 | "dev-master": "1.0.x-dev" 608 | } 609 | }, 610 | "autoload": { 611 | "psr-4": { 612 | "phpDocumentor\\Reflection\\": [ 613 | "src" 614 | ] 615 | } 616 | }, 617 | "notification-url": "https://packagist.org/downloads/", 618 | "license": [ 619 | "MIT" 620 | ], 621 | "authors": [ 622 | { 623 | "name": "Jaap van Otterdijk", 624 | "email": "opensource@ijaap.nl" 625 | } 626 | ], 627 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 628 | "homepage": "http://www.phpdoc.org", 629 | "keywords": [ 630 | "FQSEN", 631 | "phpDocumentor", 632 | "phpdoc", 633 | "reflection", 634 | "static analysis" 635 | ], 636 | "time": "2017-09-11T18:02:19+00:00" 637 | }, 638 | { 639 | "name": "phpdocumentor/reflection-docblock", 640 | "version": "4.3.0", 641 | "source": { 642 | "type": "git", 643 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 644 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08" 645 | }, 646 | "dist": { 647 | "type": "zip", 648 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", 649 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08", 650 | "shasum": "" 651 | }, 652 | "require": { 653 | "php": "^7.0", 654 | "phpdocumentor/reflection-common": "^1.0.0", 655 | "phpdocumentor/type-resolver": "^0.4.0", 656 | "webmozart/assert": "^1.0" 657 | }, 658 | "require-dev": { 659 | "doctrine/instantiator": "~1.0.5", 660 | "mockery/mockery": "^1.0", 661 | "phpunit/phpunit": "^6.4" 662 | }, 663 | "type": "library", 664 | "extra": { 665 | "branch-alias": { 666 | "dev-master": "4.x-dev" 667 | } 668 | }, 669 | "autoload": { 670 | "psr-4": { 671 | "phpDocumentor\\Reflection\\": [ 672 | "src/" 673 | ] 674 | } 675 | }, 676 | "notification-url": "https://packagist.org/downloads/", 677 | "license": [ 678 | "MIT" 679 | ], 680 | "authors": [ 681 | { 682 | "name": "Mike van Riel", 683 | "email": "me@mikevanriel.com" 684 | } 685 | ], 686 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 687 | "time": "2017-11-30T07:14:17+00:00" 688 | }, 689 | { 690 | "name": "phpdocumentor/type-resolver", 691 | "version": "0.4.0", 692 | "source": { 693 | "type": "git", 694 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 695 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 696 | }, 697 | "dist": { 698 | "type": "zip", 699 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 700 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 701 | "shasum": "" 702 | }, 703 | "require": { 704 | "php": "^5.5 || ^7.0", 705 | "phpdocumentor/reflection-common": "^1.0" 706 | }, 707 | "require-dev": { 708 | "mockery/mockery": "^0.9.4", 709 | "phpunit/phpunit": "^5.2||^4.8.24" 710 | }, 711 | "type": "library", 712 | "extra": { 713 | "branch-alias": { 714 | "dev-master": "1.0.x-dev" 715 | } 716 | }, 717 | "autoload": { 718 | "psr-4": { 719 | "phpDocumentor\\Reflection\\": [ 720 | "src/" 721 | ] 722 | } 723 | }, 724 | "notification-url": "https://packagist.org/downloads/", 725 | "license": [ 726 | "MIT" 727 | ], 728 | "authors": [ 729 | { 730 | "name": "Mike van Riel", 731 | "email": "me@mikevanriel.com" 732 | } 733 | ], 734 | "time": "2017-07-14T14:27:02+00:00" 735 | }, 736 | { 737 | "name": "phpspec/prophecy", 738 | "version": "1.8.0", 739 | "source": { 740 | "type": "git", 741 | "url": "https://github.com/phpspec/prophecy.git", 742 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" 743 | }, 744 | "dist": { 745 | "type": "zip", 746 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 747 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 748 | "shasum": "" 749 | }, 750 | "require": { 751 | "doctrine/instantiator": "^1.0.2", 752 | "php": "^5.3|^7.0", 753 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 754 | "sebastian/comparator": "^1.1|^2.0|^3.0", 755 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 756 | }, 757 | "require-dev": { 758 | "phpspec/phpspec": "^2.5|^3.2", 759 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" 760 | }, 761 | "type": "library", 762 | "extra": { 763 | "branch-alias": { 764 | "dev-master": "1.8.x-dev" 765 | } 766 | }, 767 | "autoload": { 768 | "psr-0": { 769 | "Prophecy\\": "src/" 770 | } 771 | }, 772 | "notification-url": "https://packagist.org/downloads/", 773 | "license": [ 774 | "MIT" 775 | ], 776 | "authors": [ 777 | { 778 | "name": "Konstantin Kudryashov", 779 | "email": "ever.zet@gmail.com", 780 | "homepage": "http://everzet.com" 781 | }, 782 | { 783 | "name": "Marcello Duarte", 784 | "email": "marcello.duarte@gmail.com" 785 | } 786 | ], 787 | "description": "Highly opinionated mocking framework for PHP 5.3+", 788 | "homepage": "https://github.com/phpspec/prophecy", 789 | "keywords": [ 790 | "Double", 791 | "Dummy", 792 | "fake", 793 | "mock", 794 | "spy", 795 | "stub" 796 | ], 797 | "time": "2018-08-05T17:53:17+00:00" 798 | }, 799 | { 800 | "name": "phpunit/php-code-coverage", 801 | "version": "4.0.8", 802 | "source": { 803 | "type": "git", 804 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 805 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" 806 | }, 807 | "dist": { 808 | "type": "zip", 809 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 810 | "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", 811 | "shasum": "" 812 | }, 813 | "require": { 814 | "ext-dom": "*", 815 | "ext-xmlwriter": "*", 816 | "php": "^5.6 || ^7.0", 817 | "phpunit/php-file-iterator": "^1.3", 818 | "phpunit/php-text-template": "^1.2", 819 | "phpunit/php-token-stream": "^1.4.2 || ^2.0", 820 | "sebastian/code-unit-reverse-lookup": "^1.0", 821 | "sebastian/environment": "^1.3.2 || ^2.0", 822 | "sebastian/version": "^1.0 || ^2.0" 823 | }, 824 | "require-dev": { 825 | "ext-xdebug": "^2.1.4", 826 | "phpunit/phpunit": "^5.7" 827 | }, 828 | "suggest": { 829 | "ext-xdebug": "^2.5.1" 830 | }, 831 | "type": "library", 832 | "extra": { 833 | "branch-alias": { 834 | "dev-master": "4.0.x-dev" 835 | } 836 | }, 837 | "autoload": { 838 | "classmap": [ 839 | "src/" 840 | ] 841 | }, 842 | "notification-url": "https://packagist.org/downloads/", 843 | "license": [ 844 | "BSD-3-Clause" 845 | ], 846 | "authors": [ 847 | { 848 | "name": "Sebastian Bergmann", 849 | "email": "sb@sebastian-bergmann.de", 850 | "role": "lead" 851 | } 852 | ], 853 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 854 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 855 | "keywords": [ 856 | "coverage", 857 | "testing", 858 | "xunit" 859 | ], 860 | "time": "2017-04-02T07:44:40+00:00" 861 | }, 862 | { 863 | "name": "phpunit/php-file-iterator", 864 | "version": "1.4.5", 865 | "source": { 866 | "type": "git", 867 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 868 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 869 | }, 870 | "dist": { 871 | "type": "zip", 872 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 873 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 874 | "shasum": "" 875 | }, 876 | "require": { 877 | "php": ">=5.3.3" 878 | }, 879 | "type": "library", 880 | "extra": { 881 | "branch-alias": { 882 | "dev-master": "1.4.x-dev" 883 | } 884 | }, 885 | "autoload": { 886 | "classmap": [ 887 | "src/" 888 | ] 889 | }, 890 | "notification-url": "https://packagist.org/downloads/", 891 | "license": [ 892 | "BSD-3-Clause" 893 | ], 894 | "authors": [ 895 | { 896 | "name": "Sebastian Bergmann", 897 | "email": "sb@sebastian-bergmann.de", 898 | "role": "lead" 899 | } 900 | ], 901 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 902 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 903 | "keywords": [ 904 | "filesystem", 905 | "iterator" 906 | ], 907 | "time": "2017-11-27T13:52:08+00:00" 908 | }, 909 | { 910 | "name": "phpunit/php-text-template", 911 | "version": "1.2.1", 912 | "source": { 913 | "type": "git", 914 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 915 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 916 | }, 917 | "dist": { 918 | "type": "zip", 919 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 920 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 921 | "shasum": "" 922 | }, 923 | "require": { 924 | "php": ">=5.3.3" 925 | }, 926 | "type": "library", 927 | "autoload": { 928 | "classmap": [ 929 | "src/" 930 | ] 931 | }, 932 | "notification-url": "https://packagist.org/downloads/", 933 | "license": [ 934 | "BSD-3-Clause" 935 | ], 936 | "authors": [ 937 | { 938 | "name": "Sebastian Bergmann", 939 | "email": "sebastian@phpunit.de", 940 | "role": "lead" 941 | } 942 | ], 943 | "description": "Simple template engine.", 944 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 945 | "keywords": [ 946 | "template" 947 | ], 948 | "time": "2015-06-21T13:50:34+00:00" 949 | }, 950 | { 951 | "name": "phpunit/php-timer", 952 | "version": "1.0.9", 953 | "source": { 954 | "type": "git", 955 | "url": "https://github.com/sebastianbergmann/php-timer.git", 956 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 957 | }, 958 | "dist": { 959 | "type": "zip", 960 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 961 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 962 | "shasum": "" 963 | }, 964 | "require": { 965 | "php": "^5.3.3 || ^7.0" 966 | }, 967 | "require-dev": { 968 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 969 | }, 970 | "type": "library", 971 | "extra": { 972 | "branch-alias": { 973 | "dev-master": "1.0-dev" 974 | } 975 | }, 976 | "autoload": { 977 | "classmap": [ 978 | "src/" 979 | ] 980 | }, 981 | "notification-url": "https://packagist.org/downloads/", 982 | "license": [ 983 | "BSD-3-Clause" 984 | ], 985 | "authors": [ 986 | { 987 | "name": "Sebastian Bergmann", 988 | "email": "sb@sebastian-bergmann.de", 989 | "role": "lead" 990 | } 991 | ], 992 | "description": "Utility class for timing", 993 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 994 | "keywords": [ 995 | "timer" 996 | ], 997 | "time": "2017-02-26T11:10:40+00:00" 998 | }, 999 | { 1000 | "name": "phpunit/php-token-stream", 1001 | "version": "2.0.2", 1002 | "source": { 1003 | "type": "git", 1004 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 1005 | "reference": "791198a2c6254db10131eecfe8c06670700904db" 1006 | }, 1007 | "dist": { 1008 | "type": "zip", 1009 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", 1010 | "reference": "791198a2c6254db10131eecfe8c06670700904db", 1011 | "shasum": "" 1012 | }, 1013 | "require": { 1014 | "ext-tokenizer": "*", 1015 | "php": "^7.0" 1016 | }, 1017 | "require-dev": { 1018 | "phpunit/phpunit": "^6.2.4" 1019 | }, 1020 | "type": "library", 1021 | "extra": { 1022 | "branch-alias": { 1023 | "dev-master": "2.0-dev" 1024 | } 1025 | }, 1026 | "autoload": { 1027 | "classmap": [ 1028 | "src/" 1029 | ] 1030 | }, 1031 | "notification-url": "https://packagist.org/downloads/", 1032 | "license": [ 1033 | "BSD-3-Clause" 1034 | ], 1035 | "authors": [ 1036 | { 1037 | "name": "Sebastian Bergmann", 1038 | "email": "sebastian@phpunit.de" 1039 | } 1040 | ], 1041 | "description": "Wrapper around PHP's tokenizer extension.", 1042 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 1043 | "keywords": [ 1044 | "tokenizer" 1045 | ], 1046 | "time": "2017-11-27T05:48:46+00:00" 1047 | }, 1048 | { 1049 | "name": "phpunit/phpunit", 1050 | "version": "5.7.27", 1051 | "source": { 1052 | "type": "git", 1053 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1054 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" 1055 | }, 1056 | "dist": { 1057 | "type": "zip", 1058 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 1059 | "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", 1060 | "shasum": "" 1061 | }, 1062 | "require": { 1063 | "ext-dom": "*", 1064 | "ext-json": "*", 1065 | "ext-libxml": "*", 1066 | "ext-mbstring": "*", 1067 | "ext-xml": "*", 1068 | "myclabs/deep-copy": "~1.3", 1069 | "php": "^5.6 || ^7.0", 1070 | "phpspec/prophecy": "^1.6.2", 1071 | "phpunit/php-code-coverage": "^4.0.4", 1072 | "phpunit/php-file-iterator": "~1.4", 1073 | "phpunit/php-text-template": "~1.2", 1074 | "phpunit/php-timer": "^1.0.6", 1075 | "phpunit/phpunit-mock-objects": "^3.2", 1076 | "sebastian/comparator": "^1.2.4", 1077 | "sebastian/diff": "^1.4.3", 1078 | "sebastian/environment": "^1.3.4 || ^2.0", 1079 | "sebastian/exporter": "~2.0", 1080 | "sebastian/global-state": "^1.1", 1081 | "sebastian/object-enumerator": "~2.0", 1082 | "sebastian/resource-operations": "~1.0", 1083 | "sebastian/version": "^1.0.6|^2.0.1", 1084 | "symfony/yaml": "~2.1|~3.0|~4.0" 1085 | }, 1086 | "conflict": { 1087 | "phpdocumentor/reflection-docblock": "3.0.2" 1088 | }, 1089 | "require-dev": { 1090 | "ext-pdo": "*" 1091 | }, 1092 | "suggest": { 1093 | "ext-xdebug": "*", 1094 | "phpunit/php-invoker": "~1.1" 1095 | }, 1096 | "bin": [ 1097 | "phpunit" 1098 | ], 1099 | "type": "library", 1100 | "extra": { 1101 | "branch-alias": { 1102 | "dev-master": "5.7.x-dev" 1103 | } 1104 | }, 1105 | "autoload": { 1106 | "classmap": [ 1107 | "src/" 1108 | ] 1109 | }, 1110 | "notification-url": "https://packagist.org/downloads/", 1111 | "license": [ 1112 | "BSD-3-Clause" 1113 | ], 1114 | "authors": [ 1115 | { 1116 | "name": "Sebastian Bergmann", 1117 | "email": "sebastian@phpunit.de", 1118 | "role": "lead" 1119 | } 1120 | ], 1121 | "description": "The PHP Unit Testing framework.", 1122 | "homepage": "https://phpunit.de/", 1123 | "keywords": [ 1124 | "phpunit", 1125 | "testing", 1126 | "xunit" 1127 | ], 1128 | "time": "2018-02-01T05:50:59+00:00" 1129 | }, 1130 | { 1131 | "name": "phpunit/phpunit-mock-objects", 1132 | "version": "3.4.4", 1133 | "source": { 1134 | "type": "git", 1135 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 1136 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" 1137 | }, 1138 | "dist": { 1139 | "type": "zip", 1140 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", 1141 | "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", 1142 | "shasum": "" 1143 | }, 1144 | "require": { 1145 | "doctrine/instantiator": "^1.0.2", 1146 | "php": "^5.6 || ^7.0", 1147 | "phpunit/php-text-template": "^1.2", 1148 | "sebastian/exporter": "^1.2 || ^2.0" 1149 | }, 1150 | "conflict": { 1151 | "phpunit/phpunit": "<5.4.0" 1152 | }, 1153 | "require-dev": { 1154 | "phpunit/phpunit": "^5.4" 1155 | }, 1156 | "suggest": { 1157 | "ext-soap": "*" 1158 | }, 1159 | "type": "library", 1160 | "extra": { 1161 | "branch-alias": { 1162 | "dev-master": "3.2.x-dev" 1163 | } 1164 | }, 1165 | "autoload": { 1166 | "classmap": [ 1167 | "src/" 1168 | ] 1169 | }, 1170 | "notification-url": "https://packagist.org/downloads/", 1171 | "license": [ 1172 | "BSD-3-Clause" 1173 | ], 1174 | "authors": [ 1175 | { 1176 | "name": "Sebastian Bergmann", 1177 | "email": "sb@sebastian-bergmann.de", 1178 | "role": "lead" 1179 | } 1180 | ], 1181 | "description": "Mock Object library for PHPUnit", 1182 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 1183 | "keywords": [ 1184 | "mock", 1185 | "xunit" 1186 | ], 1187 | "abandoned": true, 1188 | "time": "2017-06-30T09:13:00+00:00" 1189 | }, 1190 | { 1191 | "name": "sebastian/code-unit-reverse-lookup", 1192 | "version": "1.0.1", 1193 | "source": { 1194 | "type": "git", 1195 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1196 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 1197 | }, 1198 | "dist": { 1199 | "type": "zip", 1200 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1201 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1202 | "shasum": "" 1203 | }, 1204 | "require": { 1205 | "php": "^5.6 || ^7.0" 1206 | }, 1207 | "require-dev": { 1208 | "phpunit/phpunit": "^5.7 || ^6.0" 1209 | }, 1210 | "type": "library", 1211 | "extra": { 1212 | "branch-alias": { 1213 | "dev-master": "1.0.x-dev" 1214 | } 1215 | }, 1216 | "autoload": { 1217 | "classmap": [ 1218 | "src/" 1219 | ] 1220 | }, 1221 | "notification-url": "https://packagist.org/downloads/", 1222 | "license": [ 1223 | "BSD-3-Clause" 1224 | ], 1225 | "authors": [ 1226 | { 1227 | "name": "Sebastian Bergmann", 1228 | "email": "sebastian@phpunit.de" 1229 | } 1230 | ], 1231 | "description": "Looks up which function or method a line of code belongs to", 1232 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1233 | "time": "2017-03-04T06:30:41+00:00" 1234 | }, 1235 | { 1236 | "name": "sebastian/comparator", 1237 | "version": "1.2.4", 1238 | "source": { 1239 | "type": "git", 1240 | "url": "https://github.com/sebastianbergmann/comparator.git", 1241 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" 1242 | }, 1243 | "dist": { 1244 | "type": "zip", 1245 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 1246 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 1247 | "shasum": "" 1248 | }, 1249 | "require": { 1250 | "php": ">=5.3.3", 1251 | "sebastian/diff": "~1.2", 1252 | "sebastian/exporter": "~1.2 || ~2.0" 1253 | }, 1254 | "require-dev": { 1255 | "phpunit/phpunit": "~4.4" 1256 | }, 1257 | "type": "library", 1258 | "extra": { 1259 | "branch-alias": { 1260 | "dev-master": "1.2.x-dev" 1261 | } 1262 | }, 1263 | "autoload": { 1264 | "classmap": [ 1265 | "src/" 1266 | ] 1267 | }, 1268 | "notification-url": "https://packagist.org/downloads/", 1269 | "license": [ 1270 | "BSD-3-Clause" 1271 | ], 1272 | "authors": [ 1273 | { 1274 | "name": "Jeff Welch", 1275 | "email": "whatthejeff@gmail.com" 1276 | }, 1277 | { 1278 | "name": "Volker Dusch", 1279 | "email": "github@wallbash.com" 1280 | }, 1281 | { 1282 | "name": "Bernhard Schussek", 1283 | "email": "bschussek@2bepublished.at" 1284 | }, 1285 | { 1286 | "name": "Sebastian Bergmann", 1287 | "email": "sebastian@phpunit.de" 1288 | } 1289 | ], 1290 | "description": "Provides the functionality to compare PHP values for equality", 1291 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 1292 | "keywords": [ 1293 | "comparator", 1294 | "compare", 1295 | "equality" 1296 | ], 1297 | "time": "2017-01-29T09:50:25+00:00" 1298 | }, 1299 | { 1300 | "name": "sebastian/diff", 1301 | "version": "1.4.3", 1302 | "source": { 1303 | "type": "git", 1304 | "url": "https://github.com/sebastianbergmann/diff.git", 1305 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" 1306 | }, 1307 | "dist": { 1308 | "type": "zip", 1309 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", 1310 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", 1311 | "shasum": "" 1312 | }, 1313 | "require": { 1314 | "php": "^5.3.3 || ^7.0" 1315 | }, 1316 | "require-dev": { 1317 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 1318 | }, 1319 | "type": "library", 1320 | "extra": { 1321 | "branch-alias": { 1322 | "dev-master": "1.4-dev" 1323 | } 1324 | }, 1325 | "autoload": { 1326 | "classmap": [ 1327 | "src/" 1328 | ] 1329 | }, 1330 | "notification-url": "https://packagist.org/downloads/", 1331 | "license": [ 1332 | "BSD-3-Clause" 1333 | ], 1334 | "authors": [ 1335 | { 1336 | "name": "Kore Nordmann", 1337 | "email": "mail@kore-nordmann.de" 1338 | }, 1339 | { 1340 | "name": "Sebastian Bergmann", 1341 | "email": "sebastian@phpunit.de" 1342 | } 1343 | ], 1344 | "description": "Diff implementation", 1345 | "homepage": "https://github.com/sebastianbergmann/diff", 1346 | "keywords": [ 1347 | "diff" 1348 | ], 1349 | "time": "2017-05-22T07:24:03+00:00" 1350 | }, 1351 | { 1352 | "name": "sebastian/environment", 1353 | "version": "2.0.0", 1354 | "source": { 1355 | "type": "git", 1356 | "url": "https://github.com/sebastianbergmann/environment.git", 1357 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" 1358 | }, 1359 | "dist": { 1360 | "type": "zip", 1361 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1362 | "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", 1363 | "shasum": "" 1364 | }, 1365 | "require": { 1366 | "php": "^5.6 || ^7.0" 1367 | }, 1368 | "require-dev": { 1369 | "phpunit/phpunit": "^5.0" 1370 | }, 1371 | "type": "library", 1372 | "extra": { 1373 | "branch-alias": { 1374 | "dev-master": "2.0.x-dev" 1375 | } 1376 | }, 1377 | "autoload": { 1378 | "classmap": [ 1379 | "src/" 1380 | ] 1381 | }, 1382 | "notification-url": "https://packagist.org/downloads/", 1383 | "license": [ 1384 | "BSD-3-Clause" 1385 | ], 1386 | "authors": [ 1387 | { 1388 | "name": "Sebastian Bergmann", 1389 | "email": "sebastian@phpunit.de" 1390 | } 1391 | ], 1392 | "description": "Provides functionality to handle HHVM/PHP environments", 1393 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1394 | "keywords": [ 1395 | "Xdebug", 1396 | "environment", 1397 | "hhvm" 1398 | ], 1399 | "time": "2016-11-26T07:53:53+00:00" 1400 | }, 1401 | { 1402 | "name": "sebastian/exporter", 1403 | "version": "2.0.0", 1404 | "source": { 1405 | "type": "git", 1406 | "url": "https://github.com/sebastianbergmann/exporter.git", 1407 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" 1408 | }, 1409 | "dist": { 1410 | "type": "zip", 1411 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 1412 | "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", 1413 | "shasum": "" 1414 | }, 1415 | "require": { 1416 | "php": ">=5.3.3", 1417 | "sebastian/recursion-context": "~2.0" 1418 | }, 1419 | "require-dev": { 1420 | "ext-mbstring": "*", 1421 | "phpunit/phpunit": "~4.4" 1422 | }, 1423 | "type": "library", 1424 | "extra": { 1425 | "branch-alias": { 1426 | "dev-master": "2.0.x-dev" 1427 | } 1428 | }, 1429 | "autoload": { 1430 | "classmap": [ 1431 | "src/" 1432 | ] 1433 | }, 1434 | "notification-url": "https://packagist.org/downloads/", 1435 | "license": [ 1436 | "BSD-3-Clause" 1437 | ], 1438 | "authors": [ 1439 | { 1440 | "name": "Jeff Welch", 1441 | "email": "whatthejeff@gmail.com" 1442 | }, 1443 | { 1444 | "name": "Volker Dusch", 1445 | "email": "github@wallbash.com" 1446 | }, 1447 | { 1448 | "name": "Bernhard Schussek", 1449 | "email": "bschussek@2bepublished.at" 1450 | }, 1451 | { 1452 | "name": "Sebastian Bergmann", 1453 | "email": "sebastian@phpunit.de" 1454 | }, 1455 | { 1456 | "name": "Adam Harvey", 1457 | "email": "aharvey@php.net" 1458 | } 1459 | ], 1460 | "description": "Provides the functionality to export PHP variables for visualization", 1461 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1462 | "keywords": [ 1463 | "export", 1464 | "exporter" 1465 | ], 1466 | "time": "2016-11-19T08:54:04+00:00" 1467 | }, 1468 | { 1469 | "name": "sebastian/global-state", 1470 | "version": "1.1.1", 1471 | "source": { 1472 | "type": "git", 1473 | "url": "https://github.com/sebastianbergmann/global-state.git", 1474 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1475 | }, 1476 | "dist": { 1477 | "type": "zip", 1478 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1479 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1480 | "shasum": "" 1481 | }, 1482 | "require": { 1483 | "php": ">=5.3.3" 1484 | }, 1485 | "require-dev": { 1486 | "phpunit/phpunit": "~4.2" 1487 | }, 1488 | "suggest": { 1489 | "ext-uopz": "*" 1490 | }, 1491 | "type": "library", 1492 | "extra": { 1493 | "branch-alias": { 1494 | "dev-master": "1.0-dev" 1495 | } 1496 | }, 1497 | "autoload": { 1498 | "classmap": [ 1499 | "src/" 1500 | ] 1501 | }, 1502 | "notification-url": "https://packagist.org/downloads/", 1503 | "license": [ 1504 | "BSD-3-Clause" 1505 | ], 1506 | "authors": [ 1507 | { 1508 | "name": "Sebastian Bergmann", 1509 | "email": "sebastian@phpunit.de" 1510 | } 1511 | ], 1512 | "description": "Snapshotting of global state", 1513 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1514 | "keywords": [ 1515 | "global state" 1516 | ], 1517 | "time": "2015-10-12T03:26:01+00:00" 1518 | }, 1519 | { 1520 | "name": "sebastian/object-enumerator", 1521 | "version": "2.0.1", 1522 | "source": { 1523 | "type": "git", 1524 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1525 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" 1526 | }, 1527 | "dist": { 1528 | "type": "zip", 1529 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", 1530 | "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", 1531 | "shasum": "" 1532 | }, 1533 | "require": { 1534 | "php": ">=5.6", 1535 | "sebastian/recursion-context": "~2.0" 1536 | }, 1537 | "require-dev": { 1538 | "phpunit/phpunit": "~5" 1539 | }, 1540 | "type": "library", 1541 | "extra": { 1542 | "branch-alias": { 1543 | "dev-master": "2.0.x-dev" 1544 | } 1545 | }, 1546 | "autoload": { 1547 | "classmap": [ 1548 | "src/" 1549 | ] 1550 | }, 1551 | "notification-url": "https://packagist.org/downloads/", 1552 | "license": [ 1553 | "BSD-3-Clause" 1554 | ], 1555 | "authors": [ 1556 | { 1557 | "name": "Sebastian Bergmann", 1558 | "email": "sebastian@phpunit.de" 1559 | } 1560 | ], 1561 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1562 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1563 | "time": "2017-02-18T15:18:39+00:00" 1564 | }, 1565 | { 1566 | "name": "sebastian/recursion-context", 1567 | "version": "2.0.0", 1568 | "source": { 1569 | "type": "git", 1570 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1571 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" 1572 | }, 1573 | "dist": { 1574 | "type": "zip", 1575 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1576 | "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", 1577 | "shasum": "" 1578 | }, 1579 | "require": { 1580 | "php": ">=5.3.3" 1581 | }, 1582 | "require-dev": { 1583 | "phpunit/phpunit": "~4.4" 1584 | }, 1585 | "type": "library", 1586 | "extra": { 1587 | "branch-alias": { 1588 | "dev-master": "2.0.x-dev" 1589 | } 1590 | }, 1591 | "autoload": { 1592 | "classmap": [ 1593 | "src/" 1594 | ] 1595 | }, 1596 | "notification-url": "https://packagist.org/downloads/", 1597 | "license": [ 1598 | "BSD-3-Clause" 1599 | ], 1600 | "authors": [ 1601 | { 1602 | "name": "Jeff Welch", 1603 | "email": "whatthejeff@gmail.com" 1604 | }, 1605 | { 1606 | "name": "Sebastian Bergmann", 1607 | "email": "sebastian@phpunit.de" 1608 | }, 1609 | { 1610 | "name": "Adam Harvey", 1611 | "email": "aharvey@php.net" 1612 | } 1613 | ], 1614 | "description": "Provides functionality to recursively process PHP variables", 1615 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1616 | "time": "2016-11-19T07:33:16+00:00" 1617 | }, 1618 | { 1619 | "name": "sebastian/resource-operations", 1620 | "version": "1.0.0", 1621 | "source": { 1622 | "type": "git", 1623 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1624 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1625 | }, 1626 | "dist": { 1627 | "type": "zip", 1628 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1629 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1630 | "shasum": "" 1631 | }, 1632 | "require": { 1633 | "php": ">=5.6.0" 1634 | }, 1635 | "type": "library", 1636 | "extra": { 1637 | "branch-alias": { 1638 | "dev-master": "1.0.x-dev" 1639 | } 1640 | }, 1641 | "autoload": { 1642 | "classmap": [ 1643 | "src/" 1644 | ] 1645 | }, 1646 | "notification-url": "https://packagist.org/downloads/", 1647 | "license": [ 1648 | "BSD-3-Clause" 1649 | ], 1650 | "authors": [ 1651 | { 1652 | "name": "Sebastian Bergmann", 1653 | "email": "sebastian@phpunit.de" 1654 | } 1655 | ], 1656 | "description": "Provides a list of PHP built-in functions that operate on resources", 1657 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1658 | "time": "2015-07-28T20:34:47+00:00" 1659 | }, 1660 | { 1661 | "name": "sebastian/version", 1662 | "version": "2.0.1", 1663 | "source": { 1664 | "type": "git", 1665 | "url": "https://github.com/sebastianbergmann/version.git", 1666 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1667 | }, 1668 | "dist": { 1669 | "type": "zip", 1670 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1671 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1672 | "shasum": "" 1673 | }, 1674 | "require": { 1675 | "php": ">=5.6" 1676 | }, 1677 | "type": "library", 1678 | "extra": { 1679 | "branch-alias": { 1680 | "dev-master": "2.0.x-dev" 1681 | } 1682 | }, 1683 | "autoload": { 1684 | "classmap": [ 1685 | "src/" 1686 | ] 1687 | }, 1688 | "notification-url": "https://packagist.org/downloads/", 1689 | "license": [ 1690 | "BSD-3-Clause" 1691 | ], 1692 | "authors": [ 1693 | { 1694 | "name": "Sebastian Bergmann", 1695 | "email": "sebastian@phpunit.de", 1696 | "role": "lead" 1697 | } 1698 | ], 1699 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1700 | "homepage": "https://github.com/sebastianbergmann/version", 1701 | "time": "2016-10-03T07:35:21+00:00" 1702 | }, 1703 | { 1704 | "name": "symfony/polyfill-ctype", 1705 | "version": "v1.10.0", 1706 | "source": { 1707 | "type": "git", 1708 | "url": "https://github.com/symfony/polyfill-ctype.git", 1709 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" 1710 | }, 1711 | "dist": { 1712 | "type": "zip", 1713 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", 1714 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", 1715 | "shasum": "" 1716 | }, 1717 | "require": { 1718 | "php": ">=5.3.3" 1719 | }, 1720 | "suggest": { 1721 | "ext-ctype": "For best performance" 1722 | }, 1723 | "type": "library", 1724 | "extra": { 1725 | "branch-alias": { 1726 | "dev-master": "1.9-dev" 1727 | } 1728 | }, 1729 | "autoload": { 1730 | "psr-4": { 1731 | "Symfony\\Polyfill\\Ctype\\": "" 1732 | }, 1733 | "files": [ 1734 | "bootstrap.php" 1735 | ] 1736 | }, 1737 | "notification-url": "https://packagist.org/downloads/", 1738 | "license": [ 1739 | "MIT" 1740 | ], 1741 | "authors": [ 1742 | { 1743 | "name": "Symfony Community", 1744 | "homepage": "https://symfony.com/contributors" 1745 | }, 1746 | { 1747 | "name": "Gert de Pagter", 1748 | "email": "BackEndTea@gmail.com" 1749 | } 1750 | ], 1751 | "description": "Symfony polyfill for ctype functions", 1752 | "homepage": "https://symfony.com", 1753 | "keywords": [ 1754 | "compatibility", 1755 | "ctype", 1756 | "polyfill", 1757 | "portable" 1758 | ], 1759 | "time": "2018-08-06T14:22:27+00:00" 1760 | }, 1761 | { 1762 | "name": "symfony/yaml", 1763 | "version": "v4.2.3", 1764 | "source": { 1765 | "type": "git", 1766 | "url": "https://github.com/symfony/yaml.git", 1767 | "reference": "d461670ee145092b7e2a56c1da7118f19cadadb0" 1768 | }, 1769 | "dist": { 1770 | "type": "zip", 1771 | "url": "https://api.github.com/repos/symfony/yaml/zipball/d461670ee145092b7e2a56c1da7118f19cadadb0", 1772 | "reference": "d461670ee145092b7e2a56c1da7118f19cadadb0", 1773 | "shasum": "" 1774 | }, 1775 | "require": { 1776 | "php": "^7.1.3", 1777 | "symfony/polyfill-ctype": "~1.8" 1778 | }, 1779 | "conflict": { 1780 | "symfony/console": "<3.4" 1781 | }, 1782 | "require-dev": { 1783 | "symfony/console": "~3.4|~4.0" 1784 | }, 1785 | "suggest": { 1786 | "symfony/console": "For validating YAML files using the lint command" 1787 | }, 1788 | "type": "library", 1789 | "extra": { 1790 | "branch-alias": { 1791 | "dev-master": "4.2-dev" 1792 | } 1793 | }, 1794 | "autoload": { 1795 | "psr-4": { 1796 | "Symfony\\Component\\Yaml\\": "" 1797 | }, 1798 | "exclude-from-classmap": [ 1799 | "/Tests/" 1800 | ] 1801 | }, 1802 | "notification-url": "https://packagist.org/downloads/", 1803 | "license": [ 1804 | "MIT" 1805 | ], 1806 | "authors": [ 1807 | { 1808 | "name": "Fabien Potencier", 1809 | "email": "fabien@symfony.com" 1810 | }, 1811 | { 1812 | "name": "Symfony Community", 1813 | "homepage": "https://symfony.com/contributors" 1814 | } 1815 | ], 1816 | "description": "Symfony Yaml Component", 1817 | "homepage": "https://symfony.com", 1818 | "time": "2019-01-16T20:35:37+00:00" 1819 | }, 1820 | { 1821 | "name": "webmozart/assert", 1822 | "version": "1.4.0", 1823 | "source": { 1824 | "type": "git", 1825 | "url": "https://github.com/webmozart/assert.git", 1826 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" 1827 | }, 1828 | "dist": { 1829 | "type": "zip", 1830 | "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", 1831 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", 1832 | "shasum": "" 1833 | }, 1834 | "require": { 1835 | "php": "^5.3.3 || ^7.0", 1836 | "symfony/polyfill-ctype": "^1.8" 1837 | }, 1838 | "require-dev": { 1839 | "phpunit/phpunit": "^4.6", 1840 | "sebastian/version": "^1.0.1" 1841 | }, 1842 | "type": "library", 1843 | "extra": { 1844 | "branch-alias": { 1845 | "dev-master": "1.3-dev" 1846 | } 1847 | }, 1848 | "autoload": { 1849 | "psr-4": { 1850 | "Webmozart\\Assert\\": "src/" 1851 | } 1852 | }, 1853 | "notification-url": "https://packagist.org/downloads/", 1854 | "license": [ 1855 | "MIT" 1856 | ], 1857 | "authors": [ 1858 | { 1859 | "name": "Bernhard Schussek", 1860 | "email": "bschussek@gmail.com" 1861 | } 1862 | ], 1863 | "description": "Assertions to validate method input/output with nice error messages.", 1864 | "keywords": [ 1865 | "assert", 1866 | "check", 1867 | "validate" 1868 | ], 1869 | "time": "2018-12-25T11:19:39+00:00" 1870 | } 1871 | ], 1872 | "aliases": [], 1873 | "minimum-stability": "stable", 1874 | "stability-flags": [], 1875 | "prefer-stable": false, 1876 | "prefer-lowest": false, 1877 | "platform": { 1878 | "php": ">=5.5.0" 1879 | }, 1880 | "platform-dev": [] 1881 | } 1882 | -------------------------------------------------------------------------------- /www/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | volumes: 4 | logs: 5 | driver: local 6 | 7 | services: 8 | slim: 9 | image: php:7-alpine 10 | working_dir: /var/www 11 | command: php -S 0.0.0.0:8080 -t public 12 | environment: 13 | docker: "true" 14 | ports: 15 | - 8080:8080 16 | volumes: 17 | - .:/var/www 18 | - logs:/var/www/logs 19 | -------------------------------------------------------------------------------- /www/logs/README.md: -------------------------------------------------------------------------------- 1 | Your Slim Framework application's log files will be written to this directory. 2 | -------------------------------------------------------------------------------- /www/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tests 5 | 6 | 7 | -------------------------------------------------------------------------------- /www/public/dependencies.php: -------------------------------------------------------------------------------- 1 | getContainer(); 5 | 6 | // view renderer 7 | $container['renderer'] = function ($c) { 8 | $settings = $c->get('settings')['renderer']; 9 | return new Slim\Views\PhpRenderer($settings['template_path']); 10 | }; 11 | 12 | // monolog 13 | $container['logger'] = function ($c) { 14 | $settings = $c->get('settings')['logger']; 15 | $logger = new Monolog\Logger($settings['name']); 16 | $logger->pushProcessor(new Monolog\Processor\UidProcessor()); 17 | $logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], $settings['level'])); 18 | return $logger; 19 | }; 20 | -------------------------------------------------------------------------------- /www/public/index.php: -------------------------------------------------------------------------------- 1 | getContainer(); 25 | $c['errorHandler'] = function ($c) { 26 | return function ($request, $response, $exception) use ($c) { 27 | $errCode = $exception->getCode(); 28 | $errMsg = $exception->getMessage(); 29 | 30 | $httpCode = 500; 31 | 32 | if(is_a($exception, '\\App\\Exception')) 33 | { 34 | $httpCode = $errCode >= 400 && $errCode < 600 ? $errCode : 500; 35 | } 36 | else 37 | { 38 | // Ошибка КриптоПро? 39 | $errMsg = \App\Exception::cryptoproError($errCode, $errMsg); 40 | } 41 | 42 | 43 | return $response-> 44 | withStatus($httpCode)-> 45 | withJson(['status' => 'fail', 'errMsg' => $errMsg, 'errCode' => $errCode]); 46 | }; 47 | }; 48 | 49 | $c['notFoundHandler'] = function ($c) { 50 | return function ($request, $response) use ($c) { 51 | return $response-> 52 | withStatus(404)-> 53 | withJson(['status' => 'fail', 'errMsg' => 'Page not found', 'errCode' => 404]); 54 | }; 55 | }; 56 | 57 | $c['notAllowedHandler'] = function ($c) { 58 | return function ($request, $response, $methods) use ($c) { 59 | return $response-> 60 | withStatus(405)-> 61 | withHeader('Allow', implode(', ', $methods))-> 62 | withHeader('Content-type', 'text/html')-> 63 | withJson(['status' => 'fail', 'errMsg' => 'Method must be one of: ' . implode(', ', $methods), 'errCode' => 405]); 64 | }; 65 | }; 66 | 67 | // Run app 68 | $app->run(); 69 | -------------------------------------------------------------------------------- /www/public/routes.php: -------------------------------------------------------------------------------- 1 | get('/healthcheck', \App\Controller::class . ':healthcheck'); 7 | $app->get('/certificates', \App\Controller::class . ':certificates'); 8 | $app->post('/sign', \App\Controller::class . ':sign'); 9 | $app->post('/cosign', \App\Controller::class . ':cosign'); 10 | $app->post('/verify', \App\Controller::class . ':verify'); 11 | $app->post('/unsign', \App\Controller::class . ':unsign'); 12 | -------------------------------------------------------------------------------- /www/public/settings.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'displayErrorDetails' => true, // set to false in production 5 | 'addContentLengthHeader' => false, // Allow the web server to send the content-length header 6 | 7 | // Renderer settings 8 | 'renderer' => [ 9 | 'template_path' => __DIR__ . '/../templates/', 10 | ], 11 | 12 | // Monolog settings 13 | 'logger' => [ 14 | 'name' => 'slim-app', 15 | 'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log', 16 | 'level' => \Monolog\Logger::DEBUG, 17 | ], 18 | ], 19 | ]; 20 | -------------------------------------------------------------------------------- /www/templates/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Slim 3 6 | 7 | 27 | 28 | 29 |

Slim

30 |
a microframework for PHP
31 | 32 | 33 |

Hello !

34 | 35 |

Try SlimFramework

36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /www/test_extension.php: -------------------------------------------------------------------------------- 1 | Open($location, $name, $mode); 7 | return $store; 8 | } 9 | 10 | function SetupCertificates($location, $name, $mode) 11 | { 12 | $store = SetupStore($location, $name, $mode); 13 | $certs = $store->get_Certificates(); 14 | return $certs; 15 | 16 | } 17 | 18 | function SetupCertificate($location, $name, $mode, 19 | $find_type, $query, $valid_only, 20 | $number) 21 | { 22 | $certs = SetupCertificates($location, $name, $mode); 23 | if($find_type != NULL) 24 | { 25 | $certs = $certs->Find($find_type, $query, $valid_only); 26 | return $certs->Item($number); 27 | } 28 | else 29 | { 30 | $cert = $certs->Item($number); 31 | return $cert; 32 | } 33 | } 34 | 35 | function test_CPSignedData_Sign_Verify() 36 | { 37 | try{ 38 | $content = "test content"; 39 | $address = "http://testca.cryptopro.ru/tsp/tsp.srf"; 40 | $cert = SetupCertificate(CURRENT_USER_STORE, "My", STORE_OPEN_READ_ONLY, 41 | CERTIFICATE_FIND_SUBJECT_NAME, "Test", 0, 42 | 1); 43 | 44 | if(!$cert) 45 | return "Certificate not found"; 46 | $signer = new CPSigner(); 47 | $signer->set_TSAAddress($address); 48 | $signer->set_Certificate($cert); 49 | 50 | $sd = new CPSignedData(); 51 | $sd->set_ContentEncoding(1); 52 | $sd->set_Content(base64_encode($content)); 53 | 54 | // Второй параметр - тип подписи(1 = CADES_BES): http://cpdn.cryptopro.ru/default.asp?url=content/cades/namespace_c_ad_e_s_c_o_m_fe49883d8ff77f7edbeeaf0be3d44c0b_1fe49883d8ff77f7edbeeaf0be3d44c0b.html 55 | 56 | //Третий параметр detached - отделенная(true) или совмещенная (false) 57 | $sm = $sd->SignCades($signer, 1, false, 0); 58 | 59 | printf("Signature is:\n"); 60 | printf($sm); 61 | printf("\n"); 62 | 63 | $sd->VerifyCades($sm, 1, false); 64 | return 1; 65 | }catch(Exception $e) 66 | { 67 | printf($e->getMessage()); 68 | } 69 | } 70 | 71 | if(test_CPSignedData_Sign_Verify() == 1) 72 | { 73 | printf("TEST OK\n"); 74 | }else 75 | { 76 | printf("TEST FAIL\n"); 77 | } 78 | 79 | ?> 80 | -------------------------------------------------------------------------------- /www/tests/Functional/BaseTestCase.php: -------------------------------------------------------------------------------- 1 | $requestMethod, 39 | 'REQUEST_URI' => $requestUri 40 | ] 41 | ); 42 | 43 | // Set up a request object based on the environment 44 | $request = Request::createFromEnvironment($environment); 45 | 46 | // Add request data, if it exists 47 | if (isset($requestData)) { 48 | $request = $request->withParsedBody($requestData); 49 | } 50 | 51 | // Set up a response object 52 | $response = new Response(); 53 | 54 | // Use the application settings 55 | $settings = require __DIR__ . '/../../src/settings.php'; 56 | 57 | // Instantiate the application 58 | $app = new App($settings); 59 | 60 | // Set up dependencies 61 | require __DIR__ . '/../../src/dependencies.php'; 62 | 63 | // Register middleware 64 | if ($this->withMiddleware) { 65 | require __DIR__ . '/../../src/middleware.php'; 66 | } 67 | 68 | // Register routes 69 | require __DIR__ . '/../../src/routes.php'; 70 | 71 | // Process the application 72 | $response = $app->process($request, $response); 73 | 74 | // Return the response 75 | return $response; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /www/tests/Functional/HomepageTest.php: -------------------------------------------------------------------------------- 1 | runApp('GET', '/'); 13 | 14 | $this->assertEquals(200, $response->getStatusCode()); 15 | $this->assertContains('SlimFramework', (string)$response->getBody()); 16 | $this->assertNotContains('Hello', (string)$response->getBody()); 17 | } 18 | 19 | /** 20 | * Test that the index route with optional name argument returns a rendered greeting 21 | */ 22 | public function testGetHomepageWithGreeting() 23 | { 24 | $response = $this->runApp('GET', '/name'); 25 | 26 | $this->assertEquals(200, $response->getStatusCode()); 27 | $this->assertContains('Hello name!', (string)$response->getBody()); 28 | } 29 | 30 | /** 31 | * Test that the index route won't accept a post request 32 | */ 33 | public function testPostHomepageNotAllowed() 34 | { 35 | $response = $this->runApp('POST', '/', ['test']); 36 | 37 | $this->assertEquals(405, $response->getStatusCode()); 38 | $this->assertContains('Method not allowed', (string)$response->getBody()); 39 | } 40 | } --------------------------------------------------------------------------------