Commit 2e2fb208 authored by Dmitry Feshchenko's avatar Dmitry Feshchenko
Browse files

Add BankID service;

Add tests
parent 18bccb1f
No related merge requests found
Showing with 447 additions and 380 deletions
+447 -380
### Composer template
composer.phar
/vendor/
/phpunit.xml
language: php
dist: trusty
branches:
only:
- dev
- master
php:
- 5.6
- 7.0
sudo: required
\ No newline at end of file
# Changelog
All Notable changes to `:package_name` will be documented in this file.
Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## NEXT - YYYY-MM-DD
### Added
- Nothing
### Deprecated
- Nothing
### Fixed
- Nothing
### Removed
- Nothing
### Security
- Nothing
# Contributor Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at `:author_email`. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
# Contributing
Contributions are **welcome** and will be fully **credited**.
We accept contributions via Pull Requests on [Github](https://github.com/:vendor/:package_name).
## Pull Requests
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Check the code style with ``$ composer check-style`` and fix it with ``$ composer fix-style``.
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
- **Create feature branches** - Don't ask us to pull from your master branch.
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
## Running Tests
``` bash
$ composer test
```
**Happy coding**!
<!-- Provide a general summary of the issue in the Title above -->
## Detailed description
Provide a detailed description of the change or addition you are proposing.
Make it clear if the issue is a bug, an enhancement or just a question.
## Context
Why is this change important to you? How would you use it?
How can it benefit other users?
## Possible implementation
Not obligatory, but suggest an idea for implementing addition or change.
## Your environment
Include as many relevant details about the environment you experienced the bug in and how to reproduce it.
* Version used (e.g. PHP 5.6, HHVM 3):
* Operating system and version (e.g. Ubuntu 16.04, Windows 7):
* Link to your project:
* ...
* ...
# The MIT License (MIT)
Copyright (c) 2017 :author_name <:author_email>
Copyright (c) 2017 Dmitry Feshchenko <dimafe2000@gmail.com>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
......
<!--- Provide a general summary of your changes in the Title above -->
## Description
Describe your changes in detail.
## Motivation and context
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here (if you write `fixes #num`
or `closes #num`, the issue will be automatically closed when the pull is accepted.)
## How has this been tested?
Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc.
## Screenshots (if appropriate)
## Types of changes
What types of changes does your code introduce? Put an `x` in all the boxes that apply:
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
Go over all the following points, and put an `x` in all the boxes that apply.
Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our [continuous integration](http://www.phptherightway.com/#continuous-integration) server to make sure your [tests and code style pass](https://help.github.com/articles/about-required-status-checks/).
- [ ] I have read the **[CONTRIBUTING](CONTRIBUTING.md)** document.
- [ ] My pull request addresses exactly one patch/feature.
- [ ] I have created a branch for this patch/feature.
- [ ] Each individual commit in the pull request is meaningful.
- [ ] I have added tests to cover my changes.
- [ ] If my change requires a change to the documentation, I have updated it accordingly.
If you're unsure about any of these, don't hesitate to ask. We're here to help!
# :package_name
# Bank-ID
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-travis]][link-travis]
[![Coverage Status][ico-scrutinizer]][link-scrutinizer]
[![Quality Score][ico-code-quality]][link-code-quality]
[![Total Downloads][ico-downloads]][link-downloads]
[![Build Status](https://travis-ci.org/dimafe6/bank-id.svg?branch=dev)](https://travis-ci.org/dimafe6/bank-id)
**Note:** Replace ```:author_name``` ```:author_username``` ```:author_website``` ```:author_email``` ```:vendor``` ```:package_name``` ```:package_description``` with their correct values in [README.md](README.md), [CHANGELOG.md](CHANGELOG.md), [CONTRIBUTING.md](CONTRIBUTING.md), [LICENSE.md](LICENSE.md) and [composer.json](composer.json) files, then delete this line. You can run `$ php prefill.php` in the command line to make all replacements at once. Delete the file prefill.php as well.
......@@ -66,18 +62,3 @@ If you discover any security related issues, please email :author_email instead
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
[ico-version]: https://img.shields.io/packagist/v/:vendor/:package_name.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/:vendor/:package_name/master.svg?style=flat-square
[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/:vendor/:package_name.svg?style=flat-square
[ico-code-quality]: https://img.shields.io/scrutinizer/g/:vendor/:package_name.svg?style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/:vendor/:package_name.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/:vendor/:package_name
[link-travis]: https://travis-ci.org/:vendor/:package_name
[link-scrutinizer]: https://scrutinizer-ci.com/g/:vendor/:package_name/code-structure
[link-code-quality]: https://scrutinizer-ci.com/g/:vendor/:package_name
[link-downloads]: https://packagist.org/packages/:vendor/:package_name
[link-author]: https://github.com/:author_username
[link-contributors]: ../../contributors
{
"name": ":vendor/:package_name",
"name": "dimafe6/bank-id",
"type": "library",
"description": ":package_description",
"description": "Library for Swedish BankID",
"keywords": [
":vendor",
":package_name"
"dimafe6",
"bank-id"
],
"homepage": "https://github.com/:vendor/:package_name",
"homepage": "https://github.com/dimafe6/bank-id",
"license": "MIT",
"authors": [
{
"name": ":author_name",
"email": ":author_email",
"homepage": ":author_website",
"role": "Developer"
"name": "Dmitry Feshchenko",
"email": "dimafe2000@gmail.com"
},
{
"name": "Oleg Davudyuk",
"email": "ilveann@gmail.com"
}
],
"require": {
"php" : "~5.6|~7.0"
"php" : ">=5.6.0",
"ext-soap":"*"
},
"require-dev": {
"phpunit/phpunit" : "~4.0||~5.0||~6.0",
"squizlabs/php_codesniffer": "^2.3"
"phpunit/phpunit" : "6.3.*"
},
"autoload": {
"psr-4": {
":vendor\\:package_name\\": "src"
"Dimafe6\\BankID\\": "src"
}
},
"autoload-dev": {
"psr-4": {
":vendor\\:package_name\\": "tests"
"BankID\\Test\\": "tests"
}
},
"scripts": {
"test": "phpunit",
"check-style": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests",
"fix-style": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests"
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"config": {
"sort-packages": true
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="vendor/autoload.php" verbose="true" stopOnFailure="true">
<php>
<env name="personalNumber" value=""/>
</php>
<testsuites>
<testsuite name="BankID Test Suite">
<directory suffix="Test.php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
\ No newline at end of file
<?php
define('COL_DESCRIPTION', 0);
define('COL_HELP', 1);
define('COL_DEFAULT', 2);
$fields = [
'author_name' => ['Your name', '', ''],
'author_github_username' => ['Your Github username', '<username> in https://github.com/username', ''],
'author_email' => ['Your email address', '', ''],
'author_twitter' => ['Your twitter username', '', '@{author_github_username}'],
'author_website' => ['Your website', '', 'https://github.com/{author_github_username}'],
'package_vendor' => ['Package vendor', '<vendor> in https://github.com/vendor/package', '{author_github_username}'],
'package_name' => ['Package name', '<package> in https://github.com/vendor/package', ''],
'package_description' => ['Package very short description', '', ''],
'psr4_namespace' => ['PSR-4 namespace', 'usually, Vendor\\Package', '{package_vendor}\\{package_name}'],
];
$values = [];
$replacements = [
':vendor\\\\:package_name\\\\' => function () use(&$values) { return str_replace('\\', '\\\\', $values['psr4_namespace']) . '\\\\'; },
':author_name' => function () use(&$values) { return $values['author_name']; },
':author_username' => function () use(&$values) { return $values['author_github_username']; },
':author_website' => function () use(&$values) { return $values['author_website'] ?: ('https://github.com/' . $values['author_github_username']); },
':author_email' => function () use(&$values) { return $values['author_email'] ?: ($values['author_github_username'] . '@example.com'); },
':vendor' => function () use(&$values) { return $values['package_vendor']; },
':package_name' => function () use(&$values) { return $values['package_name']; },
':package_description' => function () use(&$values) { return $values['package_description']; },
'League\\Skeleton' => function () use(&$values) { return $values['psr4_namespace']; },
];
function read_from_console ($prompt) {
if ( function_exists('readline') ) {
$line = trim(readline($prompt));
if (!empty($line)) {
readline_add_history($line);
}
} else {
echo $prompt;
$line = trim(fgets(STDIN));
}
return $line;
}
function interpolate($text, $values)
{
if (!preg_match_all('/\{(\w+)\}/', $text, $m)) {
return $text;
}
foreach ($m[0] as $k => $str) {
$f = $m[1][$k];
$text = str_replace($str, $values[$f], $text);
}
return $text;
}
$modify = 'n';
do {
if ($modify == 'q') {
exit;
}
$values = [];
echo "----------------------------------------------------------------------\n";
echo "Please, provide the following information:\n";
echo "----------------------------------------------------------------------\n";
foreach ($fields as $f => $field) {
$default = isset($field[COL_DEFAULT]) ? interpolate($field[COL_DEFAULT], $values): '';
$prompt = sprintf(
'%s%s%s: ',
$field[COL_DESCRIPTION],
$field[COL_HELP] ? ' (' . $field[COL_HELP] . ')': '',
$field[COL_DEFAULT] !== '' ? ' [' . $default . ']': ''
);
$values[$f] = read_from_console($prompt);
if (empty($values[$f])) {
$values[$f] = $default;
}
}
echo "\n";
echo "----------------------------------------------------------------------\n";
echo "Please, check that everything is correct:\n";
echo "----------------------------------------------------------------------\n";
foreach ($fields as $f => $field) {
echo $field[COL_DESCRIPTION] . ": $values[$f]\n";
}
echo "\n";
} while (($modify = strtolower(read_from_console('Modify files with these values? [y/N/q] '))) != 'y');
echo "\n";
$files = array_merge(
glob(__DIR__ . '/*.md'),
glob(__DIR__ . '/*.xml.dist'),
glob(__DIR__ . '/composer.json'),
glob(__DIR__ . '/src/*.php'),
glob(__DIR__ . '/tests/*.php')
);
foreach ($files as $f) {
$contents = file_get_contents($f);
foreach ($replacements as $str => $func) {
$contents = str_replace($str, $func(), $contents);
}
file_put_contents($f, $contents);
}
echo "Done.\n";
echo "Now you should remove the file '" . basename(__FILE__) . "'.\n";
<?php
namespace Dimafe6\BankID\Model;
/**
* Class CollectResponse
*
* @category PHP
* @package Dimafe6\BankID\Model
* @author Dmytro Feshchenko <dimafe2000@gmail.com>
*/
class CollectResponse
{
const PROGRESS_STATUS_OUTSTANDING_TRANSACTION = 'OUTSTANDING_TRANSACTION';
const PROGRESS_STATUS_NO_CLIENT = 'NO_CLIENT';
const PROGRESS_STATUS_STARTED = 'STARTED';
const PROGRESS_STATUS_USER_SIGN = 'USER_SIGN';
const PROGRESS_STATUS_USER_REQ = 'USER_REQ';
const PROGRESS_STATUS_COMPLETE = 'COMPLETE';
/**
* @var string
*/
public $progressStatus;
/**
* String (b64). XML-signature. (If the order is COMPLETE). The content of the
* signature is described in BankID Signature Profile specification.
*
* @var string
*/
public $signature;
/**
* UserInfoType (If the order is COMPLETE)
*
* @var string
*/
public $userInfo;
/**
* String (b64). OCSP-response (If the order is COMPLETE). The OCSP response
* is signed by a certificate that has the same issuer as the certificate
* being verified. The OSCP response has an extension for Nonce.
* The nonce is calculated as:
* SHA-1 hash over the base 64 XML signature encoded as UTF-8.
* 12 random bytes is added after the hash
* The nonce is 32 bytes (20 + 12)
*
* @var string
*/
public $ocspResponse;
}
<?php
namespace Dimafe6\BankID\Model;
class OrderResponse
{
/**
* @var string
*/
public $orderRef;
/**
* @var string
*/
public $autoStartToken;
}
<?php
namespace Dimafe6\BankID\Service;
use Dimafe6\BankID\Model\CollectResponse;
use Dimafe6\BankID\Model\OrderResponse;
use SoapClient;
/**
* Class BankIDService
*
* @category PHP
* @package Dimafe6\BankID\Service
* @author Dmytro Feshchenko <dimafe2000@gmail.com>
*/
class BankIDService
{
/**
* Bank ID Sign method name
*/
const METHOD_SIGN = 'Sign';
/**
* Bank ID Authenticate method name
*/
const METHOD_AUTH = 'Authenticate';
/**
* Bank ID Collect method name
*/
const METHOD_COLLECT = 'Collect';
/**
* @var SoapClient
*/
private $client;
/**
* @var string
*/
private $wsdlUrl;
/**
* @var string
*/
private $soapOptions;
/**
* BankIDService constructor.
* @param string $wsdlUrl Bank ID API url
* @param array $options SoapClient options
* @param bool $enableSsl Enable SSL
*/
public function __construct($wsdlUrl, array $options, $enableSsl)
{
if (!$enableSsl) {
$context = stream_context_create(array(
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
],
));
$options['stream_context'] = $context;
}
$this->wsdlUrl = $wsdlUrl;
$this->soapOptions = $options;
$this->client = new SoapClient($this->wsdlUrl, $this->soapOptions);
}
/**
* @param $personalNumber
* @param $userVisibleData
* @return OrderResponse
* @throws \SoapFault
*/
public function getSignResponse($personalNumber, $userVisibleData)
{
$userVisibleData = base64_encode($userVisibleData);
$parameters = [
'parameters' => [
'personalNumber' => $personalNumber,
'userVisibleData' => $userVisibleData,
],
];
$response = $this->client->__soapCall(self::METHOD_SIGN, $parameters);
$orderResponse = new OrderResponse();
$orderResponse->orderRef = $response->orderRef;
$orderResponse->autoStartToken = $response->autoStartToken;
return $orderResponse;
}
/**
* @param $personalNumber
* @return OrderResponse|null
*/
public function getAuthResponse($personalNumber)
{
$parameters = [
'parameters' => [
'personalNumber' => $personalNumber
],
];
try {
$response = $this->client->__soapCall(self::METHOD_AUTH, $parameters);
if ($response->orderRef && $response->autoStartToken
) {
$orderResponse = new OrderResponse();
$orderResponse->orderRef = $response->orderRef;
$orderResponse->autoStartToken = $response->autoStartToken;
return $orderResponse;
}
return null;
} catch (\Exception $exception) {
return null;
}
}
/**
* @param string $orderRef
* @return CollectResponse
*/
public function collectResponse($orderRef)
{
try {
$response = $this->client->__soapCall(self::METHOD_COLLECT, ['orderRef' => $orderRef]);
$collect = new CollectResponse();
$collect->progressStatus = $response->progressStatus;
if ($collect->progressStatus == CollectResponse::PROGRESS_STATUS_COMPLETE) {
$collect->userInfo = $response->userInfo;
$collect->signature = $response->signature;
$collect->ocspResponse = $response->ocspResponse;
}
return $collect;
} catch (\Exception $exception) {
return null;
}
}
}
<?php
namespace League\Skeleton;
class SkeletonClass
{
/**
* Create a new Skeleton Instance
*/
public function __construct()
{
// constructor body
}
/**
* Friendly welcome
*
* @param string $phrase Phrase to return
*
* @return string Returns the phrase passed in
*/
public function echoPhrase($phrase)
{
return $phrase;
}
}
<?php
namespace Dimafe6\BankID\Service;
use Dimafe6\BankID\Model\CollectResponse;
use Dimafe6\BankID\Model\OrderResponse;
use PHPUnit\Framework\TestCase;
class BankIDServiceTest extends TestCase
{
/**
* @var BankIDService
*/
private $bankIDService;
/**
* @var string
*/
private $personalNumber;
public function setUp()
{
$this->bankIDService = new BankIDService(
'https://appapi2.test.bankid.com/rp/v4?wsdl',
['local_cert' => __DIR__ . '/../bankId.pem'],
false
);
$this->personalNumber = getenv('personalNumber');
if (empty($this->personalNumber)) {
$this->fail("Need set personalNumber variable in phpunit.xml");
}
}
public function testConstructor()
{
$this->assertTrue($this->bankIDService instanceof BankIDService);
$this->assertTrue(!empty($this->personalNumber));
}
/**
* @depends testConstructor
* @return OrderResponse
*/
public function testSignResponse()
{
$signResponse = $this->bankIDService->getSignResponse($this->personalNumber, 'Test user data');
$this->assertTrue($signResponse instanceof OrderResponse);
return $signResponse;
}
/**
* @depends testSignResponse
* @param $signResponse
* @return CollectResponse
*/
public function testCollectSignResponse($signResponse)
{
$this->assertTrue($signResponse instanceof OrderResponse);
fwrite(STDOUT, "\n");
do {
fwrite(STDOUT, "Waiting 5sec for confirmation from BankID mobile application...\n");
sleep(5);
$collectResponse = $this->bankIDService->collectResponse($signResponse->orderRef);
$this->assertTrue($collectResponse instanceof CollectResponse);
if (!$collectResponse instanceof CollectResponse) {
$this->fail('Error collect response');
}
} while ($collectResponse->progressStatus !== CollectResponse::PROGRESS_STATUS_COMPLETE);
$this->assertEquals(CollectResponse::PROGRESS_STATUS_COMPLETE, $collectResponse->progressStatus);
return $collectResponse;
}
public function testAuthResponse()
{
$authResponse = $this->bankIDService->getAuthResponse($this->personalNumber);
$this->assertTrue($authResponse instanceof OrderResponse);
return $authResponse;
}
/**
* @depends testAuthResponse
* @param $authResponse
* @return CollectResponse
*/
public function testAuthSignResponse($authResponse)
{
$this->assertTrue($authResponse instanceof OrderResponse);
fwrite(STDOUT, "\n");
do {
fwrite(STDOUT, "Waiting 5sec for confirmation from BankID mobile application...\n");
sleep(5);
$collectResponse = $this->bankIDService->collectResponse($authResponse->orderRef);
$this->assertTrue($collectResponse instanceof CollectResponse);
if (!$collectResponse instanceof CollectResponse) {
$this->fail('Error collect response');
}
} while ($collectResponse->progressStatus !== CollectResponse::PROGRESS_STATUS_COMPLETE);
$this->assertEquals(CollectResponse::PROGRESS_STATUS_COMPLETE, $collectResponse->progressStatus);
return $collectResponse;
}
}
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEArK/2j+F8MJd3R7HTkhD53BDh//KnTOhoZoObqtIUPaw/u4VB
26DUHkFGDucPP+j9chMAIOkPGFnWh3RiV9Qcx0LmCiEZbhd5bfgD9G1Y/TfDTPGa
uTY+ANQsMp7e9GYsU+US3kndNNwD23Ka9kcrmZTWXhMQoB8/mXURZXGtgt+xoiWc
KArlfO8dcN6vqUTGb8qljutVuSsNzjpGCDGlqtGjEpXlveSb1qGTk/H69myWaHsF
jN/A8bbF+XzSpVAGOW1m7WDa0XcvMWZtjBXmV7nA2W2WoypoE3mEtJYkosqOAEu+
yoZVhxWQdAT1mPDzO63oN+kM92xHOQOr7Qb28wIDAQABAoIBACGLWtdPIzsjKQn1
upXck1SSuPvpbGMtoB4NwZ7YiRMD0yt/crARmTK5Vj0N2DH/dcADfdpmu0ZtKRWN
346VBvQUBDCChniSucVJUKdZ2FfzzY20PuxsY3XwwRciMkgCUukHDfe9HGmotV0a
8YwWfhsqxMtoY6ne+BE8ouD0SJKrxEIKDe2NAYk/hYDkZ73SHK+MogsT+jhnkDL5
iVTELlGIc6Va/aN3dnp/rm683qJb3gbZAEwtPt011w1IqkR1ulkHWHutkIqHQc9C
HNjVVMyke7hMLELv+lirPcdvflQpmtHhc4JJRELSxzxzvb0rG0xnAw5XtQJD4P79
HKQO0HUCgYEA5qTO6ODrX1qpxFlyCGDvblY4YsR1VUSHufwRsYB1c6xpb6AF04vU
0tsVQzwUQWwYZ5PFNm+oqU9VH28SwVzS4VNf1tyW4IBahwqqdZuF/p/L3V6i92IG
YLr/y4Q1GWuyuEkw8l+LYqfS2f+Pe6GbuQSaxUZeLCTW7liqkcv0kS8CgYEAv6wK
f0iNXl92RMNKF9bUe/3VmDsFjiW2uw+MEHJt4Nvk7LJ8tL+/u0TXxmLCW9ZFaj/N
FR7kuWnhbdmzUwHtAV7gCQq+xcecAGPeJFeEgCWJ6yVKFT4uDCOBkSh4fvDApEmD
o9UxAuW3AMD0ZtqrnfyXS38i04LIR0slUXyCXX0CgYEA4dNsY8gVrX9vybhqVpnS
1Q3Gl64T1DENU6TjDhDg7ylY8tqT2dWHxAyOfQ5OJuBX5NJivjIFygDLL8PpcToZ
oFWp+Q5zC82g1agzzoNAZ1a+nTkUB3QLGpr96Z7A/urcSmQfcLDsIOSBJsF7E2ng
tv8zKwUDH+XSK/zUxXwVMjECgYB7BmEie54JkfpmfnbDQGfYQf/kGxYgvAJCpOMA
94GhT2LrrlCu71iQScq5klAwBCM/5D2tLcwfWl+QU6hvQhAuzge8pgH3Dn0KHw/J
gccRPYb9wEyBwAxsTCnw0uosiDkN+gWdlcxEkM9ak38LuZVn7WXq1mqzGgGVCR2l
5OYEPQKBgQCI1t05h4yDVC2p9grXqV5GIF+XvM+vQePKax0XXJVgrNv8B78l3wBd
3mQK77p8zCkymdG9W5U5maLAg1Wr6hVsXyLLesdcW9VrEUbMBMWdJb6C5KyVev2m
xgOYTAG71rnfQJqqmqMizuCw2Xi1r3zzDE3PUuqLgN6srjcongGijQ==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIEyDCCArCgAwIBAgIIQhrfHSgUmDEwDQYJKoZIhvcNAQELBQAwcTELMAkGA1UE
BhMCU0UxHTAbBgNVBAoMFFRlc3RiYW5rIEEgQUIgKHB1YmwpMRUwEwYDVQQFEwwx
MTExMTExMTExMTExLDAqBgNVBAMMI1Rlc3RiYW5rIEEgUlAgQ0EgdjEgZm9yIEJh
bmtJRCBUZXN0MB4XDTE1MDgxNzIyMDAwMFoXDTIwMDgxODIxNTk1OVowcDELMAkG
A1UEBhMCU0UxHTAbBgNVBAoMFFRlc3RiYW5rIEEgQUIgKHB1YmwpMREwDwYDVQQF
EwgxMjM0NTY3ODEXMBUGA1UEKQwOVGVzdCBhdiBCYW5rSUQxFjAUBgNVBAMMDUZQ
IFRlc3RjZXJ0IDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsr/aP
4Xwwl3dHsdOSEPncEOH/8qdM6Ghmg5uq0hQ9rD+7hUHboNQeQUYO5w8/6P1yEwAg
6Q8YWdaHdGJX1BzHQuYKIRluF3lt+AP0bVj9N8NM8Zq5Nj4A1Cwynt70ZixT5RLe
Sd003APbcpr2RyuZlNZeExCgHz+ZdRFlca2C37GiJZwoCuV87x1w3q+pRMZvyqWO
61W5Kw3OOkYIMaWq0aMSleW95JvWoZOT8fr2bJZoewWM38DxtsX5fNKlUAY5bWbt
YNrRdy8xZm2MFeZXucDZbZajKmgTeYS0liSiyo4AS77KhlWHFZB0BPWY8PM7reg3
6Qz3bEc5A6vtBvbzAgMBAAGjZTBjMBEGA1UdIAQKMAgwBgYEKgMEBTAOBgNVHQ8B
Af8EBAMCB4AwHQYDVR0OBBYEFJZci5tuY/wQO4yXQLA4XzsGEDfcMB8GA1UdIwQY
MBaAFOK5VQi8YqBGOV2ADFBKkgHLTO+LMA0GCSqGSIb3DQEBCwUAA4ICAQBxY+Vm
v/wR/fJlGgnXv6rKPxnSMWo0vj9xL1sxYjXkTqqUCE0wU6KFX6h93LsDiqUhw8F2
9Iwld+yet3m3c2Oy4MJQhm4Gs0OtzlO+Wq4e8rk7OtZvkkd26lpnC9ZDu8n2qvmw
VzWr07ZnI/D8NiLNFjR+frrftQmFnAxHuXHqwZk0PCjf7Y8ZJtsCyLp65/ecSIGV
p6sa1fWKK0zODpoSZhmca/fi1yfcoA+RhuHTtwi6PKAXpBU1/29y/hO7/UDw8cT3
ekNFGdL+dMYKoUN/P1sdyE+NGRaP3rnzwAjuoH3Dd+Em86DrL/8+1Smbng4FSQFI
wBe7Pxv6s4UFFk5A8K5wm3KwHnfNgDG3yT7Xv1nE8Y7Aai0fpMONCsCqT/ni+4Eb
trt1Ol767Cd7FPKkT2xroLne3toDj/b3ENCuVTnuoDpcA9dDl+5rlUJk4yKNAH9Z
JdZcmVFiBeFLvBIvdgoXFD3ll69lB9BERYaNnZVW5gCHL/i43dxwuo7zawHy+p0/
AwSqDF2JlWun5/c6VfnbM1hOBFJNKSxZv6om+QvY9jJGKT1DkFmHSPv7LM/ZcoTM
XJHTDcnyw9XbLkn04iXWLX5gITemJGAt9XAoaXXcmV2awxIDZHGVX3115V9Dd8Ir
kjLZow6Ct9QGdaglMcsoxnj1iSXc0B3ohNGtRQ==
-----END CERTIFICATE-----
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment