From 3c18ea1e147e21a4490f28dd1a68f7c2bcb53940 Mon Sep 17 00:00:00 2001 From: Marcin Szymanski Date: Sun, 30 Sep 2018 01:07:12 +0100 Subject: [PATCH 01/94] Fix incorrect logging message --- app/TransactionRules/Triggers/ToAccountIs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/TransactionRules/Triggers/ToAccountIs.php b/app/TransactionRules/Triggers/ToAccountIs.php index 1e9a1d8051..00f7f3cfd1 100644 --- a/app/TransactionRules/Triggers/ToAccountIs.php +++ b/app/TransactionRules/Triggers/ToAccountIs.php @@ -90,7 +90,7 @@ final class ToAccountIs extends AbstractTrigger implements TriggerInterface return true; } - Log::debug(sprintf('RuleTrigger ToAccountIs for journal #%d: "%s" is NOT "%s", return true.', $journal->id, $toAccountName, $search)); + Log::debug(sprintf('RuleTrigger ToAccountIs for journal #%d: "%s" is NOT "%s", return false.', $journal->id, $toAccountName, $search)); return false; } From e33bbc6f16c18942d4f4c3e5173a1db7a58e65ea Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 30 Sep 2018 11:57:51 +0200 Subject: [PATCH 02/94] Expand test coverage. --- app/Helpers/Attachments/AttachmentHelper.php | 4 +- .../Json/AutoCompleteController.php | 527 +++++------------- app/Http/Requests/SplitJournalFormRequest.php | 2 + app/Import/Storage/ImportArrayStorage.php | 4 +- .../ExecuteRuleOnExistingTransactions.php | 4 - routes/web.php | 14 +- .../Json/AutoCompleteControllerTest.php | 119 +++- .../Prerequisites/YnabPrerequisitesTest.php | 161 ++++++ tests/Unit/Import/Routine/YnabRoutineTest.php | 319 +++++++++++ 9 files changed, 746 insertions(+), 408 deletions(-) create mode 100644 tests/Unit/Import/Prerequisites/YnabPrerequisitesTest.php create mode 100644 tests/Unit/Import/Routine/YnabRoutineTest.php diff --git a/app/Helpers/Attachments/AttachmentHelper.php b/app/Helpers/Attachments/AttachmentHelper.php index 637a74045f..09f22838f1 100644 --- a/app/Helpers/Attachments/AttachmentHelper.php +++ b/app/Helpers/Attachments/AttachmentHelper.php @@ -192,7 +192,7 @@ class AttachmentHelper implements AttachmentHelperInterface public function saveAttachmentsForModel(object $model, ?array $files): bool { if(!($model instanceof Model)) { - return false; + return false; // @codeCoverageIgnore } Log::debug(sprintf('Now in saveAttachmentsForModel for model %s', \get_class($model))); if (\is_array($files)) { @@ -270,7 +270,7 @@ class AttachmentHelper implements AttachmentHelperInterface $fileObject->rewind(); if(0 === $file->getSize()) { - throw new FireflyException('Cannot upload empty or non-existent file.'); + throw new FireflyException('Cannot upload empty or non-existent file.'); // @codeCoverageIgnore } $content = $fileObject->fread($file->getSize()); diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index f441948828..2fa745ba89 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Json; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\TransactionCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Account; @@ -37,58 +38,16 @@ use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Collection; /** - * TODO refactor so each auto-complete thing is a function call because lots of code duplication. * Class AutoCompleteController. * - * @SuppressWarnings(PHPMD.TooManyPublicMethods) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AutoCompleteController extends Controller { - /** - * Returns a JSON list of all accounts. - * - * @param Request $request - * @param AccountRepositoryInterface $repository - * - * @return JsonResponse - */ - public function allAccounts(Request $request, AccountRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-all-accounts'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); - } - // find everything: - $return = array_values( - array_unique( - $repository->getAccountsByType( - [AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET] - )->pluck('name')->toArray() - ) - ); - if ('' !== $search) { - $return = array_values( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ); - } - $cache->store($return); - - return response()->json($return); - } - /** * List of all journals. * @@ -106,7 +65,7 @@ class AutoCompleteController extends Controller $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; $cache->addProperty($key); if ($cache->has()) { - return response()->json($cache->get()); + return response()->json($cache->get()); // @codeCoverageIgnore } // find everything: $collector->setLimit(250)->setPage(1); @@ -129,251 +88,85 @@ class AutoCompleteController extends Controller } /** - * List of revenue accounts. - * - * @param Request $request - * @param AccountRepositoryInterface $repository + * @param Request $request + * @param string $subject * + * @throws FireflyException * @return JsonResponse */ - public function assetAccounts(Request $request, AccountRepositoryInterface $repository): JsonResponse + public function autoComplete(Request $request, string $subject): JsonResponse { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-asset-accounts'); + $search = (string)$request->get('search'); + $unfiltered = null; + $filtered = null; + $cache = new CacheProperties; + $cache->addProperty($subject); // very unlikely a user will actually search for this string. $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; $cache->addProperty($key); if ($cache->has()) { - return response()->json($cache->get()); + return response()->json($cache->get()); // @codeCoverageIgnore } - // find everything: - $set = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); - $filtered = $set->filter( - function (Account $account) { - if (true === $account->active) { - return $account; - } - - return false; // @codeCoverageIgnore - } - ); - $return = array_values(array_unique($filtered->pluck('name')->toArray())); - - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) + // search for all accounts. + if ('all-accounts' === $subject) { + $unfiltered = $this->getAccounts( + [AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, + AccountType::DEBT, AccountType::MORTGAGE] ); } - $cache->store($return); - return response()->json($return); - } - - /** - * Returns a JSON list of all bills. - * - * @param Request $request - * @param BillRepositoryInterface $repository - * - * @return JsonResponse - */ - public function bills(Request $request, BillRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-bills'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + // search for expense accounts. + if ('expense-accounts' === $subject) { + $unfiltered = $this->getAccounts([AccountType::EXPENSE, AccountType::BENEFICIARY]); } - // find everything: - $return = array_unique($repository->getActiveBills()->pluck('name')->toArray()); - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); + // search for revenue accounts. + if ('revenue-accounts' === $subject) { + $unfiltered = $this->getAccounts([AccountType::REVENUE]); } - $cache->store($return); - return response()->json($return); - } - - /** - * List of budgets. - * - * @param Request $request - * @param BudgetRepositoryInterface $repository - * - * @return JsonResponse - */ - public function budgets(Request $request, BudgetRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-budgets'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + // search for asset accounts. + if ('asset-accounts' === $subject) { + $unfiltered = $this->getAccounts([AccountType::ASSET, AccountType::DEFAULT]); } - // find everything: - $return = array_unique($repository->getBudgets()->pluck('name')->toArray()); - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); + // search for categories. + if ('categories' === $subject) { + $unfiltered = $this->getCategories(); } - $cache->store($return); - return response()->json($return); - } - - /** - * Returns a list of categories. - * - * @param Request $request - * @param CategoryRepositoryInterface $repository - * - * @return JsonResponse - */ - public function categories(Request $request, CategoryRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-categories'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + // search for budgets. + if ('budgets' === $subject) { + $unfiltered = $this->getBudgets(); } - // find everything: - $return = array_unique($repository->getCategories()->pluck('name')->toArray()); - if ('' !== $search) { - $return = array_values( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ); + + // search for tags + if ('tags' === $subject) { + $unfiltered = $this->getTags(); } - $cache->store($return); - return response()->json($return); - } - - /** - * List of currency names. - * - * @param Request $request - * @param CurrencyRepositoryInterface $repository - * - * @return JsonResponse - */ - public function currencyNames(Request $request, CurrencyRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-currency-names'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + // search for bills + if ('bills' === $subject) { + $unfiltered = $this->getBills(); } - // find everything: - $return = $repository->get()->pluck('name')->toArray(); - sort($return); - - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); + // search for currency names. + if ('currency-names' === $subject) { + $unfiltered = $this->getCurrencyNames(); } - $cache->store($return); - - return response()->json($return); - } - - /** - * Returns a JSON list of all beneficiaries. - * - * @param Request $request - * @param AccountRepositoryInterface $repository - * - * @return JsonResponse - */ - public function expenseAccounts(Request $request, AccountRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-expense-accounts'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + if ('transaction_types' === $subject) { + $unfiltered = $this->getTransactionTypes(); } - // find everything: - $set = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]); - $filtered = $set->filter( - function (Account $account) { - if (true === $account->active) { - return $account; - } - return false; - } - ); - $return = array_unique($filtered->pluck('name')->toArray()); - sort($return); + // filter results + $filtered = $this->filterResult($unfiltered, $search); - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); + if (null === $filtered) { + throw new FireflyException(sprintf('Auto complete handler cannot handle "%s"', $subject)); // @codeCoverageIgnore } - $cache->store($return); + $cache->store($filtered); - return response()->json($return); + return response()->json($filtered); } /** @@ -394,7 +187,7 @@ class AutoCompleteController extends Controller $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; $cache->addProperty($key); if ($cache->has()) { - return response()->json($cache->get()); + return response()->json($cache->get()); // @codeCoverageIgnore } // find everything: $collector->setLimit(400)->setPage(1); @@ -430,94 +223,6 @@ class AutoCompleteController extends Controller return response()->json($return); } - /** - * List of revenue accounts. - * - * @param Request $request - * @param AccountRepositoryInterface $repository - * - * @return JsonResponse - */ - public function revenueAccounts(Request $request, AccountRepositoryInterface $repository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-revenue-accounts'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); - } - // find everything: - $set = $repository->getAccountsByType([AccountType::REVENUE]); - $filtered = $set->filter( - function (Account $account) { - if (true === $account->active) { - return $account; - } - - return false; - } - ); - $return = array_unique($filtered->pluck('name')->toArray()); - sort($return); - - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); - } - $cache->store($return); - - return response()->json($return); - } - - /** - * Returns a JSON list of all beneficiaries. - * - * @param Request $request - * @param TagRepositoryInterface $tagRepository - * - * @return JsonResponse - */ - public function tags(Request $request, TagRepositoryInterface $tagRepository): JsonResponse - { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-revenue-accounts'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); - } - // find everything: - $return = array_unique($tagRepository->get()->pluck('tag')->toArray()); - sort($return); - - if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) - ); - } - $cache->store($return); - - return response()->json($return); - } - /** * List of journals by type. * @@ -536,7 +241,7 @@ class AutoCompleteController extends Controller $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; $cache->addProperty($key); if ($cache->has()) { - return response()->json($cache->get()); + return response()->json($cache->get()); // @codeCoverageIgnore } // find everything: $type = config('firefly.transactionTypesByWhat.' . $what); @@ -563,43 +268,117 @@ class AutoCompleteController extends Controller } /** - * List if transaction types. + * @param array $unfiltered + * @param string $query * - * @param Request $request - * @param JournalRepositoryInterface $repository - * - * @return JsonResponse + * @return array|null */ - public function transactionTypes(Request $request, JournalRepositoryInterface $repository): JsonResponse + private function filterResult(?array $unfiltered, string $query): ?array { - $search = (string)$request->get('search'); - $cache = new CacheProperties; - $cache->addProperty('ac-revenue-accounts'); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); + if (null === $unfiltered) { + return null; // @codeCoverageIgnore } - // find everything: - $return = array_unique($repository->getTransactionTypes()->pluck('type')->toArray()); - sort($return); + if ('' === $query) { + sort($unfiltered); - if ('' !== $search) { + return $unfiltered; + } + $return = []; + if ('' !== $query) { $return = array_values( - array_unique( - array_filter( - $return, function (string $value) use ($search) { - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) + array_filter( + $unfiltered, function (string $value) use ($query) { + return !(false === stripos($value, $query)); + }, ARRAY_FILTER_USE_BOTH ) ); } - $cache->store($return); + sort($return); - return response()->json($return); + return $return; + } + + /** + * @param string $query + * @param array $types + * + * @return array + */ + private function getAccounts(array $types): array + { + $repository = app(AccountRepositoryInterface::class); + // find everything: + /** @var Collection $collection */ + $collection = $repository->getAccountsByType($types); + $filtered =$collection->filter(function(Account $account) { + return $account->active === true; + }); + $return = array_values(array_unique($filtered->pluck('name')->toArray())); + + return $return; } + + /** + * @return array + */ + private function getBills(): array + { + $repository = app(BillRepositoryInterface::class); + + return array_unique($repository->getActiveBills()->pluck('name')->toArray()); + } + + /** + * @return array + */ + private function getBudgets(): array + { + $repository = app(BudgetRepositoryInterface::class); + + return array_unique($repository->getBudgets()->pluck('name')->toArray()); + } + + /** + * @return array + */ + private function getCategories(): array + { + $repository = app(CategoryRepositoryInterface::class); + + return array_unique($repository->getCategories()->pluck('name')->toArray()); + } + + /** + * @return array + */ + private function getCurrencyNames(): array + { + /** @var CurrencyRepositoryInterface $repository */ + $repository = app(CurrencyRepositoryInterface::class); + + return $repository->get()->pluck('name')->toArray(); + } + + /** + * @return array + */ + private function getTags(): array + { + /** @var TagRepositoryInterface $repository */ + $repository = app(TagRepositoryInterface::class); + + return array_unique($repository->get()->pluck('tag')->toArray()); + } + + /** + * @return array + */ + private function getTransactionTypes(): array + { + $repository = app(JournalRepositoryInterface::class); + + return array_unique($repository->getTransactionTypes()->pluck('type')->toArray()); + } } diff --git a/app/Http/Requests/SplitJournalFormRequest.php b/app/Http/Requests/SplitJournalFormRequest.php index 7cedd16a18..0ad4321f26 100644 --- a/app/Http/Requests/SplitJournalFormRequest.php +++ b/app/Http/Requests/SplitJournalFormRequest.php @@ -168,8 +168,10 @@ class SplitJournalFormRequest extends Request /** @var array $array */ foreach ($transactions as $array) { if (null !== $array['destination_id'] && null !== $array['source_id'] && $array['destination_id'] === $array['source_id']) { + // @codeCoverageIgnoreStart $validator->errors()->add('journal_source_id', (string)trans('validation.source_equals_destination')); $validator->errors()->add('journal_destination_id', (string)trans('validation.source_equals_destination')); + // @codeCoverageIgnoreEnd } } diff --git a/app/Import/Storage/ImportArrayStorage.php b/app/Import/Storage/ImportArrayStorage.php index 76e2605347..179340e50e 100644 --- a/app/Import/Storage/ImportArrayStorage.php +++ b/app/Import/Storage/ImportArrayStorage.php @@ -193,9 +193,11 @@ class ImportArrayStorage unset($transaction['importHashV2'], $transaction['original-source']); $json = json_encode($transaction); if (false === $json) { + // @codeCoverageIgnoreStart /** @noinspection ForgottenDebugOutputInspection */ Log::error('Could not encode import array.', print_r($transaction, true)); - throw new FireflyException('Could not encode import array. Please see the logs.'); // @codeCoverageIgnore + throw new FireflyException('Could not encode import array. Please see the logs.'); + // @codeCoverageIgnoreEnd } $hash = hash('sha256', $json, false); Log::debug(sprintf('The hash is: %s', $hash)); diff --git a/app/Jobs/ExecuteRuleOnExistingTransactions.php b/app/Jobs/ExecuteRuleOnExistingTransactions.php index 16d0e660d2..51c7943e8b 100644 --- a/app/Jobs/ExecuteRuleOnExistingTransactions.php +++ b/app/Jobs/ExecuteRuleOnExistingTransactions.php @@ -179,10 +179,6 @@ class ExecuteRuleOnExistingTransactions extends Job implements ShouldQueue ++$misses; } Log::info(sprintf('Current progress: %d Transactions. Hits: %d, misses: %d', $total, $hits, $misses)); - // Stop processing this group if the rule specifies 'stop_processing' - if ($processor->getRule()->stop_processing) { - break; - } } Log::info(sprintf('Total transactions: %d. Hits: %d, misses: %d', $total, $hits, $misses)); } diff --git a/routes/web.php b/routes/web.php index 37b1e07c94..1034e926f6 100755 --- a/routes/web.php +++ b/routes/web.php @@ -543,19 +543,12 @@ Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'json', 'as' => 'json.'], function () { // for auto complete - Route::get('expense-accounts', ['uses' => 'Json\AutoCompleteController@expenseAccounts', 'as' => 'expense-accounts']); - Route::get('all-accounts', ['uses' => 'Json\AutoCompleteController@allAccounts', 'as' => 'all-accounts']); - Route::get('revenue-accounts', ['uses' => 'Json\AutoCompleteController@revenueAccounts', 'as' => 'revenue-accounts']); - Route::get('asset-accounts', ['uses' => 'Json\AutoCompleteController@assetAccounts', 'as' => 'asset-accounts']); - Route::get('categories', ['uses' => 'Json\AutoCompleteController@categories', 'as' => 'categories']); - Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']); - Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']); - Route::get('bills', ['uses' => 'Json\AutoCompleteController@bills', 'as' => 'bills']); - Route::get('currency-names', ['uses' => 'Json\AutoCompleteController@currencyNames', 'as' => 'currency-names']); + + Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']); Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']); Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']); - Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']); +// Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']); // boxes Route::get('box/balance', ['uses' => 'Json\BoxController@balance', 'as' => 'box.balance']); @@ -578,6 +571,7 @@ Route::group( Route::post('intro/enable/{route}/{specificPage?}', ['uses' => 'Json\IntroController@postEnable', 'as' => 'intro.enable']); Route::get('intro/{route}/{specificPage?}', ['uses' => 'Json\IntroController@getIntroSteps', 'as' => 'intro']); + Route::get('/{subject}', ['uses' => 'Json\AutoCompleteController@autoComplete', 'as' => 'autocomplete']); } ); diff --git a/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php b/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php index 718eb6f86a..1e503348aa 100644 --- a/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php +++ b/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php @@ -29,6 +29,7 @@ use FireflyIII\Models\Bill; use FireflyIII\Models\Budget; use FireflyIII\Models\Category; use FireflyIII\Models\Tag; +use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -47,8 +48,6 @@ use Tests\TestCase; */ class AutoCompleteControllerTest extends TestCase { - - /** * */ @@ -68,11 +67,12 @@ class AutoCompleteControllerTest extends TestCase $collection = new Collection([$accountA]); $accountRepos = $this->mock(AccountRepositoryInterface::class); $accountRepos->shouldReceive('getAccountsByType') - ->withArgs([[AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET]]) + ->withArgs([[AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, + AccountType::DEBT, AccountType::MORTGAGE]]) ->andReturn($collection); $this->be($this->user()); - $response = $this->get(route('json.all-accounts')); + $response = $this->get(route('json.autocomplete',['all-accounts'])); $response->assertStatus(200); $response->assertExactJson([$accountA->name]); @@ -88,10 +88,10 @@ class AutoCompleteControllerTest extends TestCase $collection = new Collection([$accountA]); $accountRepos = $this->mock(AccountRepositoryInterface::class); $accountRepos->shouldReceive('getAccountsByType') - ->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn($collection); + ->withArgs([[AccountType::ASSET, AccountType::DEFAULT]])->andReturn($collection); $this->be($this->user()); - $response = $this->get(route('json.asset-accounts')); + $response = $this->get(route('json.autocomplete',['asset-accounts'])); $response->assertStatus(200); $response->assertExactJson([$accountA->name]); @@ -102,16 +102,39 @@ class AutoCompleteControllerTest extends TestCase */ public function testAllTransactionJournals(): void { + $transaction = new Transaction(); + $transaction->description = 'hi there'; + $collection = new Collection([$transaction]); + $collector = $this->mock(TransactionCollectorInterface::class); $collector->shouldReceive('setLimit')->withArgs([250])->andReturnSelf(); $collector->shouldReceive('setPage')->withArgs([1])->andReturnSelf(); - $collector->shouldReceive('getTransactions')->andReturn(new Collection); + $collector->shouldReceive('getTransactions')->andReturn($collection); $this->be($this->user()); $response = $this->get(route('json.all-transaction-journals')); $response->assertStatus(200); } + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController + */ + public function testAllTransactionJournalsSearch(): void + { + $transaction = new Transaction(); + $transaction->description = 'hi there'; + $collection = new Collection([$transaction]); + + $collector = $this->mock(TransactionCollectorInterface::class); + $collector->shouldReceive('setLimit')->withArgs([250])->andReturnSelf(); + $collector->shouldReceive('setPage')->withArgs([1])->andReturnSelf(); + $collector->shouldReceive('getTransactions')->andReturn($collection); + + $this->be($this->user()); + $response = $this->get(route('json.all-transaction-journals').'?search=hi'); + $response->assertStatus(200); + } + /** * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController */ @@ -123,7 +146,22 @@ class AutoCompleteControllerTest extends TestCase $repository->shouldReceive('getActiveBills')->andReturn($bills); $this->be($this->user()); - $response = $this->get(route('json.bills')); + $response = $this->get(route('json.autocomplete',['bills'])); + $response->assertStatus(200); + } + + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController + */ + public function testBillsSearch(): void + { + $repository = $this->mock(BillRepositoryInterface::class); + $bills = factory(Bill::class, 10)->make(); + + $repository->shouldReceive('getActiveBills')->andReturn($bills); + + $this->be($this->user()); + $response = $this->get(route('json.autocomplete',['bills']).'?search=1234'); $response->assertStatus(200); } @@ -139,7 +177,7 @@ class AutoCompleteControllerTest extends TestCase $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $categoryRepos->shouldReceive('getBudgets')->andReturn(new Collection([$budget])); $this->be($this->user()); - $response = $this->get(route('json.budgets')); + $response = $this->get(route('json.autocomplete',['budgets'])); $response->assertStatus(200); $response->assertExactJson([$budget->name]); } @@ -156,7 +194,7 @@ class AutoCompleteControllerTest extends TestCase $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $categoryRepos->shouldReceive('getCategories')->andReturn(new Collection([$category])); $this->be($this->user()); - $response = $this->get(route('json.categories')); + $response = $this->get(route('json.autocomplete',['categories'])); $response->assertStatus(200); $response->assertExactJson([$category->name]); } @@ -172,7 +210,7 @@ class AutoCompleteControllerTest extends TestCase $repository->shouldReceive('get')->andReturn(new Collection([$currency]))->once(); $this->be($this->user()); - $response = $this->get(route('json.currency-names')); + $response = $this->get(route('json.autocomplete',['currency-names'])); $response->assertStatus(200); $response->assertExactJson(['Euro']); } @@ -194,7 +232,7 @@ class AutoCompleteControllerTest extends TestCase $accountRepos->shouldReceive('getAccountsByType')->withArgs([[AccountType::EXPENSE, AccountType::BENEFICIARY]])->once()->andReturn($collection); $this->be($this->user()); - $response = $this->get(route('json.expense-accounts')); + $response = $this->get(route('json.autocomplete',['expense-accounts'])); $response->assertStatus(200); $response->assertExactJson([$accountA->name]); } @@ -218,6 +256,25 @@ class AutoCompleteControllerTest extends TestCase $response->assertExactJson([['id' => $journal->id, 'name' => $journal->id . ': ' . $journal->description]]); } + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController + */ + public function testJournalsWithIdSearch(): void + { + $journal = $this->user()->transactionJournals()->where('id', '!=', 1)->first(); + $journal->journal_id = $journal->id; + $collection = new Collection([$journal]); + $collector = $this->mock(TransactionCollectorInterface::class); + $collector->shouldReceive('setLimit')->withArgs([400])->andReturnSelf(); + $collector->shouldReceive('setPage')->withArgs([1])->andReturnSelf(); + $collector->shouldReceive('getTransactions')->andReturn($collection); + + $this->be($this->user()); + $response = $this->get(route('json.journals-with-id', [1]).'?search=a' ); + $response->assertStatus(200); + $response->assertExactJson([['id' => $journal->id, 'name' => $journal->id . ': ' . $journal->description]]); + } + /** * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController */ @@ -235,7 +292,7 @@ class AutoCompleteControllerTest extends TestCase $accountRepos->shouldReceive('getAccountsByType')->withArgs([[AccountType::REVENUE]])->once()->andReturn($collection); $this->be($this->user()); - $response = $this->get(route('json.revenue-accounts')); + $response = $this->get(route('json.autocomplete',['revenue-accounts'])); $response->assertStatus(200); $response->assertExactJson([$accountA->name]); } @@ -253,7 +310,7 @@ class AutoCompleteControllerTest extends TestCase $tagRepos->shouldReceive('get')->andReturn(new Collection([$tag]))->once(); $this->be($this->user()); - $response = $this->get(route('json.tags')); + $response = $this->get(route('json.autocomplete', ['tags'])); $response->assertStatus(200); $response->assertExactJson([$tag->tag]); } @@ -263,6 +320,10 @@ class AutoCompleteControllerTest extends TestCase */ public function testTransactionJournals(): void { + $transaction = new Transaction(); + $transaction->description = 'hi there'; + $collection = new Collection([$transaction]); + // mock stuff $collector = $this->mock(TransactionCollectorInterface::class); $journalRepos = $this->mock(JournalRepositoryInterface::class); @@ -270,12 +331,36 @@ class AutoCompleteControllerTest extends TestCase $collector->shouldReceive('setTypes')->andReturnSelf(); $collector->shouldReceive('setLimit')->andReturnSelf(); $collector->shouldReceive('setPage')->andReturnSelf(); - $collector->shouldReceive('getTransactions')->andReturn(new Collection); + $collector->shouldReceive('getTransactions')->andReturn($collection); $this->be($this->user()); $response = $this->get(route('json.transaction-journals', ['deposit'])); $response->assertStatus(200); - $response->assertExactJson([]); + $response->assertExactJson(['hi there']); + } + + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController + */ + public function testTransactionJournalsSearch(): void + { + $transaction = new Transaction(); + $transaction->description = 'hi there'; + $collection = new Collection([$transaction]); + + // mock stuff + $collector = $this->mock(TransactionCollectorInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + $collector->shouldReceive('setTypes')->andReturnSelf(); + $collector->shouldReceive('setLimit')->andReturnSelf(); + $collector->shouldReceive('setPage')->andReturnSelf(); + $collector->shouldReceive('getTransactions')->andReturn($collection); + + $this->be($this->user()); + $response = $this->get(route('json.transaction-journals', ['deposit']).'?search=hi'); + $response->assertStatus(200); + $response->assertExactJson(['hi there']); } /** @@ -289,7 +374,7 @@ class AutoCompleteControllerTest extends TestCase $journalRepos->shouldReceive('getTransactionTypes')->once()->andReturn(new Collection); $this->be($this->user()); - $response = $this->get(route('json.transaction-types', ['deposit'])); + $response = $this->get(route('json.autocomplete',['transaction_types'])); $response->assertStatus(200); $response->assertExactJson([]); } diff --git a/tests/Unit/Import/Prerequisites/YnabPrerequisitesTest.php b/tests/Unit/Import/Prerequisites/YnabPrerequisitesTest.php new file mode 100644 index 0000000000..fa45b049c6 --- /dev/null +++ b/tests/Unit/Import/Prerequisites/YnabPrerequisitesTest.php @@ -0,0 +1,161 @@ +. + */ + +declare(strict_types=1); + +namespace tests\Unit\Import\Prerequisites; + +use FireflyIII\Import\Prerequisites\YnabPrerequisites; +use FireflyIII\Models\Preference; +use Log; +use Mockery; +use Preferences; +use Tests\TestCase; + +/** + * Class YnabPrerequisitesTest + */ +class YnabPrerequisitesTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Log::info(sprintf('Now in %s.', \get_class($this))); + } + + + /** + * @covers \FireflyIII\Import\Prerequisites\YnabPrerequisites + */ + public function testGetView(): void + { + + $object = new YnabPrerequisites; + $object->setUser($this->user()); + $this->assertEquals('import.ynab.prerequisites', $object->getView()); + } + + /** + * First test, user has nothing. + * + * @covers \FireflyIII\Import\Prerequisites\YnabPrerequisites + */ + public function testGetViewParametersNull(): void + { + + Preferences::shouldReceive('getForUser')->once()->withArgs([Mockery::any(), 'ynab_client_id', null])->andReturn(null); + Preferences::shouldReceive('getForUser')->once()->withArgs([Mockery::any(), 'ynab_client_secret', null])->andReturn(null); + + $object = new YnabPrerequisites(); + $object->setUser($this->user()); + $result = $object->getViewParameters(); + + $expected = ['client_id' => '', 'client_secret' => '', 'callback_uri' => 'http://localhost/import/ynab-callback', 'is_https' => false]; + + $this->assertEquals($expected, $result); + } + + /** + * + */ + public function testStorePrerequisites(): void { + + Preferences::shouldReceive('setForUser')->once()->withArgs([Mockery::any(), 'ynab_client_id', 'hello']); + Preferences::shouldReceive('setForUser')->once()->withArgs([Mockery::any(), 'ynab_client_secret', 'hi there']); + + $data = [ + 'client_id' => 'hello', + 'client_secret' => 'hi there' + ]; + + $object = new YnabPrerequisites(); + $object->setUser($this->user()); + $object->storePrerequisites($data); + } + + /** + * First test, user has empty. + * + * @covers \FireflyIII\Import\Prerequisites\YnabPrerequisites + */ + public function testGetViewParametersEmpty(): void + { + $clientId = new Preference; + $clientId->data = ''; + + $clientSecret = new Preference; + $clientSecret->data = ''; + + Preferences::shouldReceive('getForUser')->once()->withArgs([Mockery::any(), 'ynab_client_id', null])->andReturn($clientId); + Preferences::shouldReceive('getForUser')->once()->withArgs([Mockery::any(), 'ynab_client_secret', null])->andReturn($clientSecret); + + $object = new YnabPrerequisites(); + $object->setUser($this->user()); + $result = $object->getViewParameters(); + + $expected = ['client_id' => '', 'client_secret' => '', 'callback_uri' => 'http://localhost/import/ynab-callback', 'is_https' => false]; + + $this->assertEquals($expected, $result); + } + + /** + * @covers \FireflyIII\Import\Prerequisites\YnabPrerequisites + */ + public function testIsComplete(): void + { + + Preferences::shouldReceive('getForUser')->once()->withArgs([Mockery::any(), 'ynab_client_id', null])->andReturn(null); + + $object = new YnabPrerequisites(); + $object->setUser($this->user()); + $result = $object->isComplete(); + + $this->assertFalse($result); + } + + /** + * First test, user has nothing. + * + * @covers \FireflyIII\Import\Prerequisites\YnabPrerequisites + */ + public function testGetViewParametersFilled(): void + { + $clientId = new Preference; + $clientId->data = 'client-id'; + + $clientSecret = new Preference; + $clientSecret->data = 'client-secret'; + + Preferences::shouldReceive('getForUser')->twice()->withArgs([Mockery::any(), 'ynab_client_id', null])->andReturn($clientId); + Preferences::shouldReceive('getForUser')->twice()->withArgs([Mockery::any(), 'ynab_client_secret', null])->andReturn($clientSecret); + + $object = new YnabPrerequisites(); + $object->setUser($this->user()); + $result = $object->getViewParameters(); + + $expected = ['client_id' => 'client-id', 'client_secret' => 'client-secret', 'callback_uri' => 'http://localhost/import/ynab-callback', 'is_https' => false]; + + $this->assertEquals($expected, $result); + } +} \ No newline at end of file diff --git a/tests/Unit/Import/Routine/YnabRoutineTest.php b/tests/Unit/Import/Routine/YnabRoutineTest.php new file mode 100644 index 0000000000..00c0018895 --- /dev/null +++ b/tests/Unit/Import/Routine/YnabRoutineTest.php @@ -0,0 +1,319 @@ +. + */ + +declare(strict_types=1); + +namespace tests\Unit\Import\Routine; + + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Import\Routine\YnabRoutine; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Support\Import\Routine\Ynab\GetAccountsHandler; +use FireflyIII\Support\Import\Routine\Ynab\ImportDataHandler; +use FireflyIII\Support\Import\Routine\Ynab\StageGetAccessHandler; +use FireflyIII\Support\Import\Routine\Ynab\StageGetBudgetsHandler; +use Log; +use Mockery; +use Tests\TestCase; + +/** + * Class YnabRoutineTest + */ +class YnabRoutineTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Log::info(sprintf('Now in %s.', \get_class($this))); + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunGetAccessToken(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_1_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'get_access_token'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(StageGetAccessHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running'])->once(); + + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'ready_to_run'])->once(); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'get_budgets'])->once(); + + // mock calls for handler + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunMultiBudgets(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_2_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'get_budgets'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(StageGetBudgetsHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + $config = ['budgets' => [1, 2, 3]]; + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running'])->once(); + $repository->shouldReceive('getConfiguration')->once()->andReturn($config); + + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'need_job_config'])->once(); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'select_budgets'])->once(); + + // mock calls for handler + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunSingleBudget(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_3_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'get_budgets'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(StageGetBudgetsHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + $config = ['budgets' => [1]]; + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running'])->once(); + $repository->shouldReceive('getConfiguration')->once()->andReturn($config); + + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'ready_to_run'])->once(); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'get_accounts'])->once(); + + // mock calls for handler + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunGetAccounts(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_4_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'get_accounts'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(GetAccountsHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running'])->once(); + + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'select_accounts'])->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'need_job_config'])->once(); + + + // mock calls for handler + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunGoForImport(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_5_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'go-for-import'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(ImportDataHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running'])->once(); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'do_import'])->once(); + + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'provider_finished'])->once(); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'final'])->once(); + + + + // mock calls for handler + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunException(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_6_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'bad_state'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(ImportDataHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertEquals('YNAB import routine cannot handle stage "bad_state"', $e->getMessage()); + } + } + + /** + * @covers \FireflyIII\Import\Routine\YnabRoutine + */ + public function testRunBadStatus(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'ynab_r_7_' . random_int(1, 10000); + $job->status = 'not_ready_to_run'; + $job->stage = 'bad_state'; + $job->provider = 'ynab'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock handler and repository + $handler = $this->mock(ImportDataHandler::class); + $repository = $this->mock(ImportJobRepositoryInterface::class); + + // mock calls for repository + $repository->shouldReceive('setUser')->once(); + + $routine = new YnabRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertEquals('YNAB import routine cannot handle stage "bad_state"', $e->getMessage()); + } + } +} \ No newline at end of file From c0669c158a86c565b73212ef8e86f577266e2198 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 30 Sep 2018 12:00:08 +0200 Subject: [PATCH 03/94] Update badge to read php 7.2 --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 75d84d2a24..0ba4bdc4e4 100644 --- a/readme.md +++ b/readme.md @@ -151,4 +151,4 @@ If you are looking for alternatives, check out [Kickball's Awesome-Selfhosted li ### Badges I like badges! -[![Travis branch](https://travis-ci.com/firefly-iii/firefly-iii.svg?branch=master)](https://travis-ci.com/firefly-iii/firefly-iii) [![Scrutinizer](https://img.shields.io/scrutinizer/g/firefly-iii/firefly-iii.svg?style=flat-square)](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/) [![Coveralls github branch](https://img.shields.io/coveralls/github/firefly-iii/firefly-iii/master.svg?style=flat-square)](https://coveralls.io/github/firefly-iii/firefly-iii) [![Requires PHP7.1](https://img.shields.io/badge/php-7.1-red.svg?style=flat-square)](https://secure.php.net/downloads.php) [![license](https://img.shields.io/github/license/firefly-iii/firefly-iii.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0.en.html) [![Patreon page](https://img.shields.io/badge/patreon-JC5-brightgreen.svg?longCache=true&style=flat-square)](https://patreon.com/JC5) +[![Travis branch](https://travis-ci.com/firefly-iii/firefly-iii.svg?branch=master)](https://travis-ci.com/firefly-iii/firefly-iii) [![Scrutinizer](https://img.shields.io/scrutinizer/g/firefly-iii/firefly-iii.svg?style=flat-square)](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/) [![Coveralls github branch](https://img.shields.io/coveralls/github/firefly-iii/firefly-iii/master.svg?style=flat-square)](https://coveralls.io/github/firefly-iii/firefly-iii) [![Requires PHP7.2](https://img.shields.io/badge/php-7.2-red.svg?style=flat-square)](https://secure.php.net/downloads.php) [![license](https://img.shields.io/github/license/firefly-iii/firefly-iii.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0.en.html) [![Patreon page](https://img.shields.io/badge/patreon-JC5-brightgreen.svg?longCache=true&style=flat-square)](https://patreon.com/JC5) From d4c763df843d4b02c82d8a50fbd424d172967c19 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 30 Sep 2018 18:41:10 +0200 Subject: [PATCH 04/94] Fix #1751 --- public/js/ff/transactions/show.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/ff/transactions/show.js b/public/js/ff/transactions/show.js index 74509ba2e0..3a63d137ae 100644 --- a/public/js/ff/transactions/show.js +++ b/public/js/ff/transactions/show.js @@ -29,7 +29,7 @@ $(function () { url: autoCompleteUri, filter: function (list) { return $.map(list, function (name) { - return {name: name}; + return {name: name.name}; }); } }, @@ -38,7 +38,7 @@ $(function () { wildcard: '%QUERY', filter: function (list) { return $.map(list, function (name) { - return {name: name}; + return {name: name.name}; }); } } From e50641e969602bf43986d66e80ba33522d6f16df Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 30 Sep 2018 19:11:49 +0200 Subject: [PATCH 05/94] Fix #1751 --- .../Json/AutoCompleteController.php | 27 +++++----- public/js/ff/transactions/show.js | 54 +++++++++---------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index 2fa745ba89..2aaeb29c03 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -206,17 +206,14 @@ class AutoCompleteController extends Controller sort($return); if ('' !== $search) { - $return = array_values( - array_unique( - array_filter( - $return, function (array $array) use ($search) { - $value = $array['name']; - - return !(false === stripos($value, $search)); - }, ARRAY_FILTER_USE_BOTH - ) - ) + $return = array_filter( + $return, function (array $array) use ($search) { + $haystack = $array['name']; + $result = stripos($haystack, $search); + return !(false === $result); + } ); + } $cache->store($return); @@ -311,10 +308,12 @@ class AutoCompleteController extends Controller // find everything: /** @var Collection $collection */ $collection = $repository->getAccountsByType($types); - $filtered =$collection->filter(function(Account $account) { - return $account->active === true; - }); - $return = array_values(array_unique($filtered->pluck('name')->toArray())); + $filtered = $collection->filter( + function (Account $account) { + return $account->active === true; + } + ); + $return = array_values(array_unique($filtered->pluck('name')->toArray())); return $return; diff --git a/public/js/ff/transactions/show.js b/public/js/ff/transactions/show.js index 3a63d137ae..d3dad51d6b 100644 --- a/public/js/ff/transactions/show.js +++ b/public/js/ff/transactions/show.js @@ -25,41 +25,37 @@ $(function () { var transactions = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'), queryTokenizer: Bloodhound.tokenizers.whitespace, + identify: function (obj) { + return obj.id; + }, prefetch: { - url: autoCompleteUri, - filter: function (list) { - return $.map(list, function (name) { - return {name: name.name}; - }); - } + url: autoCompleteUri + // filter: function (list) { + // return $.map(list, function (name) { + // return {name: name.name}; + // }); + // } }, remote: { url: autoCompleteUri + '?search=%QUERY', - wildcard: '%QUERY', - filter: function (list) { - return $.map(list, function (name) { - return {name: name.name}; - }); - } + wildcard: '%QUERY' + // filter: function (list) { + // return $.map(list, function (name) { + // return {name: name.name}; + // }); + // } } }); transactions.initialize(); - var input=$("#link_other"); + var input = $("#link_other"); input.typeahead({hint: true, highlight: true,}, {source: transactions, displayKey: 'name', autoSelect: false}); - - input.change(function () { - var current = input.typeahead("getActive"); - if (current) { - // Some item from your model is active! - if (current.name.toLowerCase() === - input.val().toLowerCase()) { - // This means the exact match is found. Use toLowerCase() if you want case insensitive match. - $('input[name="link_journal_id"]').val(current.id); - } else { - $('input[name="link_journal_id"]').val(0); - } - } else { - $('input[name="link_journal_id"]').val(0); - } - }); + input.bind('typeahead:select', function (ev, suggestion) { + console.log('Selection: ' + suggestion.name); + if (suggestion.name.toLowerCase() === input.val().toLowerCase()) { + // This means the exact match is found. Use toLowerCase() if you want case insensitive match. + $('input[name="link_journal_id"]').val(suggestion.id); + } else { + $('input[name="link_journal_id"]').val(0); + } + }); }); \ No newline at end of file From 50ab1fa3f03482b6071c6749533a2c7661e54f45 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 30 Sep 2018 20:14:17 +0200 Subject: [PATCH 06/94] Test improvement for import routine. --- app/Import/Routine/BunqRoutine.php | 6 +- app/Import/Storage/ImportArrayStorage.php | 101 ++++++++---------- .../Routine/Bunq/StageImportDataHandler.php | 8 ++ tests/Unit/Import/Routine/BunqRoutineTest.php | 51 ++++++++- 4 files changed, 104 insertions(+), 62 deletions(-) diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index c53c75a720..f5b6deb3b3 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -78,13 +78,13 @@ class BunqRoutine implements RoutineInterface $handler->run(); $transactions = $handler->getTransactions(); // could be that more transactions will arrive in a second run. - if (true === $handler->stillRunning) { + if (true === $handler->isStillRunning()) { Log::debug('Handler indicates that it is still working.'); $this->repository->setStatus($this->importJob, 'ready_to_run'); $this->repository->setStage($this->importJob, 'go-for-import'); } $this->repository->appendTransactions($this->importJob, $transactions); - if (false === $handler->stillRunning) { + if (false === $handler->isStillRunning()) { Log::info('Handler indicates that its done!'); $this->repository->setStatus($this->importJob, 'provider_finished'); $this->repository->setStage($this->importJob, 'final'); @@ -98,6 +98,8 @@ class BunqRoutine implements RoutineInterface } + + /** * Set the import job. * diff --git a/app/Import/Storage/ImportArrayStorage.php b/app/Import/Storage/ImportArrayStorage.php index 179340e50e..9568c31f32 100644 --- a/app/Import/Storage/ImportArrayStorage.php +++ b/app/Import/Storage/ImportArrayStorage.php @@ -46,7 +46,7 @@ use Illuminate\Support\Collection; use Log; /** - * Creates new transactions based upon arrays. Will first check the array for duplicates. + * Creates new transactions based on arrays. * * Class ImportArrayStorage * @@ -58,11 +58,11 @@ class ImportArrayStorage private $checkForTransfers = false; /** @var ImportJob The import job */ private $importJob; - /** @var JournalRepositoryInterface */ + /** @var JournalRepositoryInterface Journal repository for storage. */ private $journalRepos; /** @var ImportJobRepositoryInterface Import job repository */ private $repository; - /** @var Collection The transfers. */ + /** @var Collection The transfers the user already has. */ private $transfers; /** @@ -152,12 +152,10 @@ class ImportArrayStorage /** * Count the number of transfers in the array. If this is zero, don't bother checking for double transfers. - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function countTransfers(): void { - Log::debug('Now in count transfers.'); + Log::debug('Now in countTransfers()'); /** @var array $array */ $array = $this->importJob->transactions; $count = 0; @@ -167,17 +165,44 @@ class ImportArrayStorage Log::debug(sprintf('Row #%d is a transfer, increase count to %d', $index + 1, $count)); } } - if (0 === $count) { - Log::debug('Count is zero, will not check for duplicate transfers.'); - } + Log::debug(sprintf('Count of transfers in import array is %d.', $count)); if ($count > 0) { - Log::debug(sprintf('Count is %d, will check for duplicate transfers.', $count)); $this->checkForTransfers = true; - + Log::debug('Will check for duplicate transfers.'); // get users transfers. Needed for comparison. $this->getTransfers(); } + } + /** + * @param int $index + * @param array $transaction + * + * @return bool + * @throws FireflyException + */ + private function duplicateDetected(int $index, array $transaction): bool + { + $hash = $this->getHash($transaction); + $existingId = $this->hashExists($hash); + if (null !== $existingId) { + $message = sprintf('Row #%d ("%s") could not be imported. It already exists.', $index, $transaction['description']); + $this->logDuplicateObject($transaction, $existingId); + $this->repository->addErrorMessage($this->importJob, $message); + + return true; + } + + // do transfer detection: + if ($this->checkForTransfers && $this->transferExists($transaction)) { + $message = sprintf('Row #%d ("%s") could not be imported. Such a transfer already exists.', $index, $transaction['description']); + $this->logDuplicateTransfer($transaction); + $this->repository->addErrorMessage($this->importJob, $message); + + return true; + } + + return false; } /** @@ -397,34 +422,17 @@ class ImportArrayStorage $count = \count($array); $toStore = []; - Log::debug(sprintf('Now in store(). Count of items is %d', $count)); + Log::debug(sprintf('Now in store(). Count of items is %d.', $count)); + /* + * Detect duplicates in initial array: + */ foreach ($array as $index => $transaction) { Log::debug(sprintf('Now at item %d out of %d', $index + 1, $count)); - $hash = $this->getHash($transaction); - $existingId = $this->hashExists($hash); - if (null !== $existingId) { - $this->logDuplicateObject($transaction, $existingId); - $this->repository->addErrorMessage( - $this->importJob, sprintf( - 'Row #%d ("%s") could not be imported. It already exists.', - $index, $transaction['description'] - ) - ); + if ($this->duplicateDetected($index, $transaction)) { continue; } - if ($this->checkForTransfers && $this->transferExists($transaction)) { - $this->logDuplicateTransfer($transaction); - $this->repository->addErrorMessage( - $this->importJob, sprintf( - 'Row #%d ("%s") could not be imported. Such a transfer already exists.', - $index, - $transaction['description'] - ) - ); - continue; - } - $transaction['importHashV2'] = $hash; + $transaction['importHashV2'] = $this->getHash($transaction); $toStore[] = $transaction; } $count = \count($toStore); @@ -438,31 +446,8 @@ class ImportArrayStorage // now actually store them: $collection = new Collection; foreach ($toStore as $index => $store) { - // do duplicate detection again! - $hash = $this->getHash($store); - $existingId = $this->hashExists($hash); - if (null !== $existingId) { - $this->logDuplicateObject($store, $existingId); - $this->repository->addErrorMessage( - $this->importJob, sprintf( - 'Row #%d ("%s") could not be imported. It already exists.', - $index, $store['description'] - ) - ); - continue; - } - - // do transfer detection again! - if ($this->checkForTransfers && $this->transferExists($store)) { - $this->logDuplicateTransfer($store); - $this->repository->addErrorMessage( - $this->importJob, sprintf( - 'Row #%d ("%s") could not be imported. Such a transfer already exists.', - $index, - $store['description'] - ) - ); + if ($this->duplicateDetected($index, $store)) { continue; } diff --git a/app/Support/Import/Routine/Bunq/StageImportDataHandler.php b/app/Support/Import/Routine/Bunq/StageImportDataHandler.php index 2f9822b9fe..704cc0bb62 100644 --- a/app/Support/Import/Routine/Bunq/StageImportDataHandler.php +++ b/app/Support/Import/Routine/Bunq/StageImportDataHandler.php @@ -80,6 +80,14 @@ class StageImportDataHandler return $this->transactions; } + /** + * @return bool + */ + public function isStillRunning(): bool + { + return $this->stillRunning; + } + /** * * @throws FireflyException diff --git a/tests/Unit/Import/Routine/BunqRoutineTest.php b/tests/Unit/Import/Routine/BunqRoutineTest.php index defe5916c0..b8f179f244 100644 --- a/tests/Unit/Import/Routine/BunqRoutineTest.php +++ b/tests/Unit/Import/Routine/BunqRoutineTest.php @@ -71,13 +71,59 @@ class BunqRoutineTest extends TestCase $repository->shouldReceive('setUser')->once(); $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running']); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'provider_finished']); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'final']); + $repository->shouldReceive('appendTransactions')->withArgs([Mockery::any(), ['a' => 'c']])->once(); + $handler->shouldReceive('setImportJob')->once(); $handler->shouldReceive('run')->once(); $handler->shouldReceive('getTransactions')->once()->andReturn(['a' => 'c']); - //$repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'provider_finished'])->once(); - //$repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'final'])->once(); + $handler->shouldReceive('isStillRunning')->andReturn(false); + $routine = new BunqRoutine; + $routine->setImportJob($job); + try { + $routine->run(); + } catch (FireflyException $e) { + $this->assertFalse(true, $e->getMessage()); + } + + } + + /** + * @covers \FireflyIII\Import\Routine\BunqRoutine + */ + public function testRunImportStillRunning(): void + { + $job = new ImportJob; + $job->user_id = $this->user()->id; + $job->key = 'brY_' . random_int(1, 10000); + $job->status = 'ready_to_run'; + $job->stage = 'go-for-import'; + $job->provider = 'bunq'; + $job->file_type = ''; + $job->configuration = []; + $job->save(); + + // mock stuff: + $repository = $this->mock(ImportJobRepositoryInterface::class); + $handler = $this->mock(StageImportDataHandler::class); + + + + $handler->shouldReceive('setImportJob')->once(); + $handler->shouldReceive('run')->once(); + $handler->shouldReceive('getTransactions')->once()->andReturn(['a' => 'c']); + $handler->shouldReceive('isStillRunning')->andReturn(true); + + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'ready_to_run']); + $repository->shouldReceive('setStage')->withArgs([Mockery::any(), 'go-for-import']); + + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('setStatus')->withArgs([Mockery::any(), 'running']); $repository->shouldReceive('appendTransactions')->withArgs([Mockery::any(), ['a' => 'c']])->once(); + + $routine = new BunqRoutine; $routine->setImportJob($job); try { @@ -88,6 +134,7 @@ class BunqRoutineTest extends TestCase } + /** * @covers \FireflyIII\Import\Routine\BunqRoutine */ From efa3eb19813301c5deb2bbdca6df70457e803d79 Mon Sep 17 00:00:00 2001 From: HamuZ HamuZ <550499+hamuz@users.noreply.github.com> Date: Mon, 1 Oct 2018 08:21:03 +0300 Subject: [PATCH 07/94] fix typo in PrependDescription [skip ci] --- app/TransactionRules/Actions/PrependDescription.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/TransactionRules/Actions/PrependDescription.php b/app/TransactionRules/Actions/PrependDescription.php index 56a355f721..23b5153402 100644 --- a/app/TransactionRules/Actions/PrependDescription.php +++ b/app/TransactionRules/Actions/PrependDescription.php @@ -27,7 +27,7 @@ use FireflyIII\Models\TransactionJournal; use Log; /** - * Class AppendDescription. + * Class PrependDescription. */ class PrependDescription implements ActionInterface { From dc73db2a07f9c2cf014b21b0220aa4a97ad47168 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 1 Oct 2018 19:24:24 +0200 Subject: [PATCH 08/94] Added FinTS import --- .../FinTSJobConfiguration.php | 137 ++++++++++++++++ app/Import/Routine/FinTSRoutine.php | 84 ++++++++++ app/Support/FinTS/FinTS.php | 92 +++++++++++ .../FinTS/ChooseAccountHandler.php | 120 ++++++++++++++ .../FinTS/FinTSConfigurationInterface.php | 50 ++++++ .../FinTS/NewFinTSJobHandler.php | 106 +++++++++++++ .../Routine/FinTS/StageImportDataHandler.php | 147 ++++++++++++++++++ composer.json | 1 + config/import.php | 10 ++ public/images/logos/fints.png | Bin 0 -> 2399 bytes resources/lang/en_US/form.php | 10 ++ resources/lang/en_US/import.php | 9 +- .../views/import/fints/choose_account.twig | 44 ++++++ resources/views/import/fints/new.twig | 39 +++++ 14 files changed, 848 insertions(+), 1 deletion(-) create mode 100644 app/Import/JobConfiguration/FinTSJobConfiguration.php create mode 100644 app/Import/Routine/FinTSRoutine.php create mode 100644 app/Support/FinTS/FinTS.php create mode 100644 app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php create mode 100644 app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php create mode 100644 app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php create mode 100644 app/Support/Import/Routine/FinTS/StageImportDataHandler.php create mode 100644 public/images/logos/fints.png create mode 100644 resources/views/import/fints/choose_account.twig create mode 100644 resources/views/import/fints/new.twig diff --git a/app/Import/JobConfiguration/FinTSJobConfiguration.php b/app/Import/JobConfiguration/FinTSJobConfiguration.php new file mode 100644 index 0000000000..a3dc24b709 --- /dev/null +++ b/app/Import/JobConfiguration/FinTSJobConfiguration.php @@ -0,0 +1,137 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Import\JobConfiguration; + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\ImportJob; +use FireflyIII\Support\Import\JobConfiguration\FinTS\ChooseAccountHandler; +use FireflyIII\Support\Import\JobConfiguration\FinTS\FinTSConfigurationInterface; +use FireflyIII\Support\Import\JobConfiguration\FinTS\NewFinTSJobHandler; +use Illuminate\Support\MessageBag; + +abstract class FinTSConfigurationSteps +{ + const NEW = 'new'; + const CHOOSE_ACCOUNT = 'choose_account'; + const GO_FOR_IMPORT = 'go-for-import'; +} + +class FinTSJobConfiguration implements JobConfigurationInterface +{ + /** @var ImportJob */ + private $importJob; + + /** + * Returns true when the initial configuration for this job is complete. + * + * @return bool + */ + public function configurationComplete(): bool + { + return $this->importJob->stage == FinTSConfigurationSteps::GO_FOR_IMPORT; + } + + /** + * Store any data from the $data array into the job. Anything in the message bag will be flashed + * as an error to the user, regardless of its content. + * + * @param array $data + * + * @return MessageBag + * @throws FireflyException + */ + public function configureJob(array $data): MessageBag + { + return $this->getConfigurationObject()->configureJob($data); + } + + /** + * Return the data required for the next step in the job configuration. + * + * @return array + * @throws FireflyException + */ + public function getNextData(): array + { + return $this->getConfigurationObject()->getNextData(); + } + + /** + * Returns the view of the next step in the job configuration. + * + * @return string + * @throws FireflyException + */ + public function getNextView(): string + { + switch ($this->importJob->stage) { + case FinTSConfigurationSteps::NEW: + case FinTSConfigurationSteps::CHOOSE_ACCOUNT: + return 'import.fints.' . $this->importJob->stage; + break; + default: + // @codeCoverageIgnoreStart + throw new FireflyException( + sprintf('FinTSJobConfiguration::getNextView() cannot handle stage "%s"', $this->importJob->stage) + ); + // @codeCoverageIgnoreEnd + } + } + + /** + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + } + + /** + * Get the configuration handler for this specific stage. + * + * @return FinTSConfigurationInterface + * @throws FireflyException + */ + private function getConfigurationObject(): FinTSConfigurationInterface + { + $class = 'DoNotExist'; + switch ($this->importJob->stage) { + case FinTSConfigurationSteps::NEW: + $class = NewFinTSJobHandler::class; + break; + case FinTSConfigurationSteps::CHOOSE_ACCOUNT: + $class = ChooseAccountHandler::class; + break; + } + if (!class_exists($class)) { + throw new FireflyException(sprintf('Class %s does not exist in getConfigurationClass().', $class)); // @codeCoverageIgnore + } + + $configurator = app($class); + $configurator->setImportJob($this->importJob); + + return $configurator; + } + + +} \ No newline at end of file diff --git a/app/Import/Routine/FinTSRoutine.php b/app/Import/Routine/FinTSRoutine.php new file mode 100644 index 0000000000..7effeecfc5 --- /dev/null +++ b/app/Import/Routine/FinTSRoutine.php @@ -0,0 +1,84 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Import\Routine; + + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Support\Import\Routine\FinTS\StageImportDataHandler; +use Illuminate\Support\Facades\Log; + +class FinTSRoutine implements RoutineInterface +{ + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + + /** + * At the end of each run(), the import routine must set the job to the expected status. + * + * The final status of the routine must be "provider_finished". + * + * @throws FireflyException + */ + public function run(): void + { + Log::debug(sprintf('Now in FinTSRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage)); + $valid = ['ready_to_run']; // should be only ready_to_run + if (\in_array($this->importJob->status, $valid, true)) { + switch ($this->importJob->stage) { + default: + throw new FireflyException(sprintf('FinTSRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore + case FinTSConfigurationSteps::GO_FOR_IMPORT: + $this->repository->setStatus($this->importJob, 'running'); + /** @var StageImportDataHandler $handler */ + $handler = app(StageImportDataHandler::class); + $handler->setImportJob($this->importJob); + $handler->run(); + $transactions = $handler->getTransactions(); + + $this->repository->setTransactions($this->importJob, $transactions); + $this->repository->setStatus($this->importJob, 'provider_finished'); + $this->repository->setStage($this->importJob, 'final'); + + return; + } + } + } + + /** + * @param ImportJob $importJob + * + * @return void + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->repository->setUser($importJob->user); + } + +} \ No newline at end of file diff --git a/app/Support/FinTS/FinTS.php b/app/Support/FinTS/FinTS.php new file mode 100644 index 0000000000..c2bff5b290 --- /dev/null +++ b/app/Support/FinTS/FinTS.php @@ -0,0 +1,92 @@ +finTS = new \Fhp\FinTs( + $config['fints_url'], + $config['fints_port'], + $config['fints_bank_code'], + $config['fints_username'], + $config['fints_password'] + ); + } + + public function checkConnection() + { + try { + $this->finTS->getSEPAAccounts(); + return true; + } catch (\Exception $exception) { + return $exception->getMessage(); + } + } + + /** + * @return \Fhp\Model\SEPAAccount[] + * @throws FireflyException + */ + public function getAccounts() + { + try { + return $this->finTS->getSEPAAccounts(); + } catch (\Exception $exception) { + throw new FireflyException($exception->getMessage()); + } + } + + /** + * @param string $accountNumber + * @return \Fhp\Model\SEPAAccount + * @throws FireflyException + */ + public function getAccount($accountNumber) + { + $accounts = $this->getAccounts(); + $filteredAccounts = array_filter($accounts, function ($account) use ($accountNumber) { + return $account->getAccountNumber() == $accountNumber; + }); + if (count($filteredAccounts) != 1) { + throw new FireflyException("Cannot find account with number " . $accountNumber); + } + return $filteredAccounts[0]; + } + + /** + * @param \Fhp\Model\SEPAAccount $account + * @param \DateTime $from + * @param \DateTIme $to + * @return \Fhp\Model\StatementOfAccount\StatementOfAccount|null + * @throws FireflyException + */ + public function getStatementOfAccount(\Fhp\Model\SEPAAccount $account, \DateTime $from, \DateTIme $to) + { + try { + return $this->finTS->getStatementOfAccount($account, $from, $to); + } catch (\Exception $exception) { + throw new FireflyException($exception->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php new file mode 100644 index 0000000000..b17749b437 --- /dev/null +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -0,0 +1,120 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Support\Import\JobConfiguration\FinTS; + + +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Support\FinTS\FinTS; +use Illuminate\Support\MessageBag; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; + +class ChooseAccountHandler implements FinTSConfigurationInterface +{ + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + /** @var AccountRepositoryInterface */ + private $accountRepository; + + /** + * Store data associated with current stage. + * + * @param array $data + * + * @return MessageBag + */ + public function configureJob(array $data): MessageBag + { + $config = $this->importJob->configuration; + $config['fints_account'] = (string)($data['fints_account'] ?? ''); + $config['local_account'] = (string)($data['local_account'] ?? ''); + $config['local_account'] = (string)($data['local_account'] ?? ''); + $config['from_date'] = (string)($data['from_date'] ?? ''); + $config['to_date'] = (string)($data['to_date'] ?? ''); + $this->repository->setConfiguration($this->importJob, $config); + + try { + $finTS = new FinTS($this->importJob->configuration); + $finTS->getAccount($config['fints_account']); + } catch (FireflyException $e) { + return new MessageBag($e->getMessage()); + } + + $this->repository->setStage($this->importJob, FinTSConfigurationSteps::GO_FOR_IMPORT); + + return new MessageBag(); + } + + /** + * Get the data necessary to show the configuration screen. + * + * @return array + * @throws \FireflyIII\Exceptions\FireflyException + */ + public function getNextData(): array + { + $finTS = new FinTS($this->importJob->configuration); + $finTSAccounts = $finTS->getAccounts(); + $finTSAccountsData = []; + foreach ($finTSAccounts as $account) { + $finTSAccountsData[$account->getAccountNumber()] = $account->getIban(); + } + + $localAccounts = []; + foreach ($this->accountRepository->getAccountsByType([AccountType::ASSET]) as $localAccount) { + $display_name = $localAccount->name; + if ($localAccount->iban) { + $display_name .= " - $localAccount->iban"; + } + $localAccounts[$localAccount->id] = $display_name; + } + + $data = [ + 'fints_accounts' => $finTSAccountsData, + 'fints_account' => $this->importJob->configuration['fints_account'] ?? null, + 'local_accounts' => $localAccounts, + 'local_account' => $this->importJob->configuration['local_account'] ?? null, + 'from_date' => $this->importJob->configuration['from_date'] ?? (new \DateTime('now - 1 month'))->format('Y-m-d'), + 'to_date' => $this->importJob->configuration['to_date'] ?? (new \DateTime('now'))->format('Y-m-d') + ]; + return $data; + } + + /** + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->repository->setUser($importJob->user); + } + + +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php b/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php new file mode 100644 index 0000000000..47bcedad33 --- /dev/null +++ b/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php @@ -0,0 +1,50 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Support\Import\JobConfiguration\FinTS; + +use FireflyIII\Models\ImportJob; +use Illuminate\Support\MessageBag; + +interface FinTSConfigurationInterface +{ + /** + * Store data associated with current stage. + * + * @param array $data + * + * @return MessageBag + */ + public function configureJob(array $data): MessageBag; + + /** + * Get the data necessary to show the configuration screen. + * + * @return array + */ + public function getNextData(): array; + + /** + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void; +} \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php new file mode 100644 index 0000000000..848543da0d --- /dev/null +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -0,0 +1,106 @@ +. + */ +declare(strict_types=1); + + +namespace FireflyIII\Support\Import\JobConfiguration\FinTS; + + +use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Support\FinTS\FinTS; +use Illuminate\Support\MessageBag; + +class NewFinTSJobHandler implements FinTSConfigurationInterface +{ + /** @var ImportJob */ + private $importJob; + /** @var ImportJobRepositoryInterface */ + private $repository; + + /** + * Store data associated with current stage. + * + * @param array $data + * + * @return MessageBag + * @throws \FireflyIII\Exceptions\FireflyException + */ + public function configureJob(array $data): MessageBag + { + $config = []; + + $config['fints_url'] = trim($data['fints_url'] ?? ''); + $config['fints_port'] = (int)($data['fints_port'] ?? ''); + $config['fints_bank_code'] = (string)($data['fints_bank_code'] ?? ''); + $config['fints_username'] = (string)($data['fints_username'] ?? ''); + $config['fints_password'] = (string)($data['fints_password'] ?? ''); + + $this->repository->setConfiguration($this->importJob, $config); + + $incomplete = false; + foreach ($config as $value) { + $incomplete = $value == '' or $incomplete; + } + if ($incomplete) { + return new MessageBag([trans('import.incomplete_fints_form')]); + } + + $finTS = new FinTS($this->importJob->configuration); + if (($checkConnection = $finTS->checkConnection()) !== true) { + return new MessageBag([trans('import.fints_connection_failed', ['originalError' => $checkConnection])]); + } + + $this->repository->setStage($this->importJob, FinTSConfigurationSteps::CHOOSE_ACCOUNT); + + return new MessageBag(); + } + + /** + * Get the data necessary to show the configuration screen. + * + * @return array + */ + public function getNextData(): array + { + $config = $this->importJob->configuration; + var_dump($config); + return [ + 'fints_url' => $config['fints_url'] ?? "", + 'fints_port' => $config['fints_port'] ?? "443", + 'fints_bank_code' => $config['fints_bank_code'] ?? "", + 'fints_username' => $config['fints_username'] ?? "", + 'fints_password' => $config['fints_password'] ?? "", + ]; + } + + /** + * @param ImportJob $importJob + */ + public function setImportJob(ImportJob $importJob): void + { + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->repository->setUser($importJob->user); + } + +} \ No newline at end of file diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php new file mode 100644 index 0000000000..1f120c5600 --- /dev/null +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -0,0 +1,147 @@ +transactions = []; + $this->importJob = $importJob; + $this->repository = app(ImportJobRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->mapper = app(OpposingAccountMapper::class); + $this->mapper->setUser($importJob->user); + $this->repository->setUser($importJob->user); + $this->accountRepository->setUser($importJob->user); + } + + /** + * @throws \FireflyIII\Exceptions\FireflyException + */ + public function run() + { + Log::debug('Now in StageImportDataHandler::run()'); + + $localAccount = $this->accountRepository->find($this->importJob->configuration['local_account']); + $finTS = new FinTS($this->importJob->configuration); + $fintTSAccount = $finTS->getAccount($this->importJob->configuration['fints_account']); + $statementOfAccount = $finTS->getStatementOfAccount($fintTSAccount, new \DateTime($this->importJob->configuration['from_date']), new \DateTime($this->importJob->configuration['to_date'])); + $collection = []; + foreach ($statementOfAccount->getStatements() as $statement) { + foreach ($statement->getTransactions() as $transaction) { + $collection[] = $this->convertTransaction($transaction, $localAccount); + } + } + + $this->transactions = $collection; + } + + private function convertTransaction(FinTSTransaction $transaction, LocalAccount $source): array + { + Log::debug(sprintf('Start converting transaction %s', $transaction->getDescription1())); + + $amount = $transaction->getAmount(); + $debitOrCredit = $transaction->getCreditDebit(); + + Log::debug(sprintf('Amount is %s', $amount)); + if ($debitOrCredit == Transaction::CD_CREDIT) { + $type = TransactionType::DEPOSIT; + } else { + $type = TransactionType::WITHDRAWAL; + $amount = -$amount; + } + + $destination = $this->mapper->map( + null, + $amount, + ['iban' => $transaction->getAccountNumber(), 'name' => $transaction->getName()] + ); + if ($debitOrCredit == Transaction::CD_CREDIT) { + [$source, $destination] = [$destination, $source]; + } + + if ($source->accountType->type === AccountType::ASSET && $destination->accountType->type === AccountType::ASSET) { + $type = TransactionType::TRANSFER; + Log::debug('Both are assets, will make transfer.'); + } + + $storeData = [ + 'user' => $this->importJob->user_id, + 'type' => $type, + 'date' => $transaction->getValutaDate()->format('Y-m-d'), + 'description' => $transaction->getDescription1(), + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'bill_id' => null, + 'bill_name' => null, + 'tags' => [], + 'internal_reference' => null, + 'external_id' => null, + 'notes' => null, + 'bunq_payment_id' => null, + 'transactions' => [ + // single transaction: + [ + 'description' => null, + 'amount' => $amount, + 'currency_id' => null, + 'currency_code' => 'EUR', + 'foreign_amount' => null, + 'foreign_currency_id' => null, + 'foreign_currency_code' => null, + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'source_id' => $source->id, + 'source_name' => null, + 'destination_id' => $destination->id, + 'destination_name' => null, + 'reconciled' => false, + 'identifier' => 0, + ], + ], + ]; + + return $storeData; + } + + /** + * @return array + */ + public function getTransactions(): array + { + return $this->transactions; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 3a22067015..66d610c88b 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,7 @@ "league/commonmark": "0.*", "league/csv": "9.*", "league/fractal": "^0.17.0", + "mschindler83/fints-hbci-php": "^1.0", "pragmarx/google2fa": "3.*", "pragmarx/google2fa-laravel": "0.*", "rcrowe/twigbridge": "0.9.*", diff --git a/config/import.php b/config/import.php index 5f6a724700..ff93e167ae 100644 --- a/config/import.php +++ b/config/import.php @@ -25,6 +25,7 @@ declare(strict_types=1); use FireflyIII\Import\JobConfiguration\BunqJobConfiguration; use FireflyIII\Import\JobConfiguration\FakeJobConfiguration; use FireflyIII\Import\JobConfiguration\FileJobConfiguration; +use FireflyIII\Import\JobConfiguration\FinTSJobConfiguration; use FireflyIII\Import\JobConfiguration\SpectreJobConfiguration; use FireflyIII\Import\JobConfiguration\YnabJobConfiguration; use FireflyIII\Import\Prerequisites\BunqPrerequisites; @@ -34,6 +35,7 @@ use FireflyIII\Import\Prerequisites\YnabPrerequisites; use FireflyIII\Import\Routine\BunqRoutine; use FireflyIII\Import\Routine\FakeRoutine; use FireflyIII\Import\Routine\FileRoutine; +use FireflyIII\Import\Routine\FinTSRoutine; use FireflyIII\Import\Routine\SpectreRoutine; use FireflyIII\Import\Routine\YnabRoutine; use FireflyIII\Support\Import\Routine\File\CSVProcessor; @@ -49,6 +51,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => true, 'bad' => false, // always disabled ], // demo user can use these import providers (when enabled): @@ -61,6 +64,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => false, ], // a normal user user can use these import providers (when enabled): 'allowed_for_user' => [ @@ -72,6 +76,7 @@ return [ 'plaid' => true, 'quovo' => true, 'yodlee' => true, + 'fints' => true, ], // some providers have pre-requisites. 'has_prereq' => [ @@ -83,6 +88,7 @@ return [ 'plaid' => true, 'quovo' => true, 'yodlee' => true, + 'fints' => false, ], // if so, there must be a class to handle them. 'prerequisites' => [ @@ -94,6 +100,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => false, ], // some providers may need extra configuration per job 'has_job_config' => [ @@ -105,6 +112,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => true, ], // if so, this is the class that handles it. 'configuration' => [ @@ -116,6 +124,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => FinTSJobConfiguration::class, ], // this is the routine that runs the actual import. 'routine' => [ @@ -127,6 +136,7 @@ return [ 'plaid' => false, 'quovo' => false, 'yodlee' => false, + 'fints' => FinTSRoutine::class, ], 'options' => [ diff --git a/public/images/logos/fints.png b/public/images/logos/fints.png new file mode 100644 index 0000000000000000000000000000000000000000..0024f8af419524303cfc8ff70c14412df89883a1 GIT binary patch literal 2399 zcmZ`*3se)=77c%d2vuHHguZ4WAo?_u1PmdB2m}QbkU$Cv_$mPg2@n#K0b&)9pyolX zA3lowl~2?@F{lNBWk67mU$_wXQBsUhthHzqB>sf8u->55B4Jy__8pB~Oh<;K>@U3xkh9#HGkD6{C}4 zIs&0?%A(OBy1N@Oh{HxRgE@g9TEOPQY`kft`thL4?P07%)L8 zC{Vba3EkZjMd9#3)Go9Y8e>A%L7`A2UT_G}%W3bj9G=;kghCLP2mmoLG3XdeG>3N> zz}nc@02myA!|j9_JNZW=A*NtwB!A1&B7d#p1oDG;EH1?2M55&DG6OkLke!K%JkiJB zQk@VhAwI0b zu9^<+?MLC?iWD%pOUV>XT=GVeS5EW-`J9L-c?-UYWI<#cNnvOu{HY^LDhh|q<$-)Y zEFE7^)PjL)S}3MdJKgNXd7z%VcfQra(g z*A!2`H+Te4f=R%tY!dt|5ZyV!tdOHlOb8_7Fj#9M7DvS5Q5eO*8s6#^9Hk265eg4v zLL45A!-*g(T(IR+lqK4FNvRxPmXZMZIZ`@TONUm0!l#z311tY}1CVt*q5(hnebMIX zGk>VfTQsv?s zZ{w<}x(_wpo(ILP15;8p-)UpqE|z_5E)3yKyPsT)W{-<2N()44A{Ei|uSPn_Q~nI>9ZBVE z5cA+rsfxM1@FHWHZL?UO4MW-^Jn{7Hv0I)Z89WA*XZ4?O^f-axUb9a z+uX0rT1(X@9Kvfh9jpFva}3`4Qi#y8VMFIBpH8iij>>UTAy-xLS@Gq&X$EAh&MMA!AslV}&Ue z)XV{=qE;<)ndE@ydb8PnFk|k9M*O34b*lO=gOV<3rs^LZ0`xm-5uWlk#=HVzrP;T> z+0bfr?`?8LP5b>iFJBJjyziz0!t|jJkCIO!Q}>e=4hDz|FJy=ZYwxbZ%rx;W{+XKU zj0yBFtf9?5cv9UD*bk|97@i@m4`|p{Y*9n|a%Y}?WTv^aQFbDwF(K{oOV|3T4^uR; zjvIB{UQ@UD7SZ?ToVrNhsfx{o2Sw86`&@&N?g=2R9IKu)Uj3tsx#F+a+?cESU%AL-!B1vx+!3BDZTM;Xu-~1HE(gLf4i*6o z>N#$s>2-0}8P5ne>gwj=g*KAR+!!_mJ?KSQG@*DX1b()tx7ASZBIK-keAM*mc?7vjMJHohGou%ae|^}LFL3KNFvKGXw(D-y z8V=1iY1I4IzkOfbQhPaGSn$~Q_sfS 'Public key', 'country_code' => 'Country code', 'provider_code' => 'Bank or data-provider', + 'fints_url' => 'FinTS API URL', + 'fints_port' => 'Port', + 'fints_bank_code' => 'Bank code', + 'fints_username' => 'Username', + 'fints_password' => 'PIN / Password', + 'fints_account' => 'FinTS account', + 'local_account' => 'Firefly III account', + 'from_date' => 'Date from', + 'to_date' => 'Date to', + 'due_date' => 'Due date', 'payment_date' => 'Payment date', diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 16f0e84c73..783b8f0a7f 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -199,7 +199,14 @@ return [ 'spectre_extra_key_units' => 'Units', 'spectre_extra_key_unit_price' => 'Unit price', 'spectre_extra_key_transactions_count' => 'Transaction count', - + //job configuration for finTS + 'fints_connection_failed' => 'An error occurred while trying to connecting to your bank. Please mak sure that all the data you entered is correct. Original error message: :originalError', + 'button_fints' => 'FinTS', + 'job_config_fints_url_help' => 'E.g. https://banking-dkb.s-fints-pt-dkb.de/fints30', + 'job_config_fints_username_help' => 'For many banks this is your account number.', + 'job_config_fints_port_help' => 'The default port is 443.', + 'job_config_fints_account_help' => 'Choose the bank account for which you want to import transactions.', + 'job_config_local_account_help' => 'Choose the Firefly III account corresponding to your bank account chosen above.', // specifics: 'specific_ing_name' => 'ING NL', 'specific_ing_descr' => 'Create better descriptions in ING exports', diff --git a/resources/views/import/fints/choose_account.twig b/resources/views/import/fints/choose_account.twig new file mode 100644 index 0000000000..8b0509dac7 --- /dev/null +++ b/resources/views/import/fints/choose_account.twig @@ -0,0 +1,44 @@ +{% extends "./layout/default" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.render }} +{% endblock %} +{% block content %} +
+ + +
+
+
+
+

{{ trans('import.job_config_input') }}

+
+
+ {{ ExpandedForm.select('fints_account', data.fints_accounts, data.fints_account, {helpText: trans('import.job_config_fints_account_help'), required: true}) }} +
+
+ {{ ExpandedForm.select('local_account', data.local_accounts, data.local_account, {helpText: trans('import.job_config_local_account_help'), required: true}) }} +
+
+ {{ ExpandedForm.date('from_date', data.from_date, {required: true}) }} +
+
+ {{ ExpandedForm.date('to_date', data.to_date, {required: true}) }} +
+
+
+
+
+
+
+
+ +
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/resources/views/import/fints/new.twig b/resources/views/import/fints/new.twig new file mode 100644 index 0000000000..70e67b057a --- /dev/null +++ b/resources/views/import/fints/new.twig @@ -0,0 +1,39 @@ +{% extends "./layout/default" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.render }} +{% endblock %} +{% block content %} +
+ + +
+
+
+
+

{{ trans('import.job_config_input') }}

+
+
+ {{ ExpandedForm.text('fints_url', data.fints_url, {helpText: trans('import.job_config_fints_url_help'), required: true}) }} + {{ ExpandedForm.text('fints_port', data.fints_port, {helpText: trans('import.job_config_fints_port_help'), required: true}) }} + {{ ExpandedForm.text('fints_bank_code', data.fints_bank_code, {required: true}) }} + {{ ExpandedForm.text('fints_username', data.fints_username, {helpText: trans('import.job_config_fints_username_help'), required: true}) }} + {{ ExpandedForm.password('fints_password', {required: true}) }} +
+
+
+
+
+
+
+
+ +
+
+
+
+
+{% endblock %} \ No newline at end of file From c32e9fabd9bd5b491ab947c7bfb73218fcda4f3e Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:46:18 +0200 Subject: [PATCH 09/94] Bugfix --- .../Import/JobConfiguration/FinTS/ChooseAccountHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php index b17749b437..0be29ffbe0 100644 --- a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -53,7 +53,6 @@ class ChooseAccountHandler implements FinTSConfigurationInterface $config = $this->importJob->configuration; $config['fints_account'] = (string)($data['fints_account'] ?? ''); $config['local_account'] = (string)($data['local_account'] ?? ''); - $config['local_account'] = (string)($data['local_account'] ?? ''); $config['from_date'] = (string)($data['from_date'] ?? ''); $config['to_date'] = (string)($data['to_date'] ?? ''); $this->repository->setConfiguration($this->importJob, $config); From 91e0e33a0466e5907dab17e4874625b869136316 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:47:38 +0200 Subject: [PATCH 10/94] Remove debug --- app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php index 848543da0d..d18f8c50d8 100644 --- a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -83,7 +83,6 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface public function getNextData(): array { $config = $this->importJob->configuration; - var_dump($config); return [ 'fints_url' => $config['fints_url'] ?? "", 'fints_port' => $config['fints_port'] ?? "443", From ce917298ed1acaf2c5fbbbd73903a6ea2589a2ef Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:56:53 +0200 Subject: [PATCH 11/94] Store password encrypted --- app/Support/FinTS/FinTS.php | 3 ++- .../Import/JobConfiguration/FinTS/NewFinTSJobHandler.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Support/FinTS/FinTS.php b/app/Support/FinTS/FinTS.php index c2bff5b290..5da743aa43 100644 --- a/app/Support/FinTS/FinTS.php +++ b/app/Support/FinTS/FinTS.php @@ -4,6 +4,7 @@ namespace FireflyIII\Support\FinTS; use FireflyIII\Exceptions\FireflyException; +use Illuminate\Support\Facades\Crypt; class FinTS { @@ -30,7 +31,7 @@ class FinTS $config['fints_port'], $config['fints_bank_code'], $config['fints_username'], - $config['fints_password'] + Crypt::decrypt($config['fints_password']) ); } diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php index d18f8c50d8..d03f773813 100644 --- a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -28,6 +28,7 @@ use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps; use FireflyIII\Models\ImportJob; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Support\FinTS\FinTS; +use Illuminate\Support\Facades\Crypt; use Illuminate\Support\MessageBag; class NewFinTSJobHandler implements FinTSConfigurationInterface @@ -53,7 +54,7 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface $config['fints_port'] = (int)($data['fints_port'] ?? ''); $config['fints_bank_code'] = (string)($data['fints_bank_code'] ?? ''); $config['fints_username'] = (string)($data['fints_username'] ?? ''); - $config['fints_password'] = (string)($data['fints_password'] ?? ''); + $config['fints_password'] = (string)(Crypt::encrypt($data['fints_password']) ?? ''); $this->repository->setConfiguration($this->importJob, $config); @@ -87,8 +88,7 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface 'fints_url' => $config['fints_url'] ?? "", 'fints_port' => $config['fints_port'] ?? "443", 'fints_bank_code' => $config['fints_bank_code'] ?? "", - 'fints_username' => $config['fints_username'] ?? "", - 'fints_password' => $config['fints_password'] ?? "", + 'fints_username' => $config['fints_username'] ?? "" ]; } From 3ba41d712f38dd4f2af0f59f0499ccad31293e7a Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:57:17 +0200 Subject: [PATCH 12/94] Added import and type hinting --- app/Support/FinTS/FinTS.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/Support/FinTS/FinTS.php b/app/Support/FinTS/FinTS.php index 5da743aa43..47931fb77c 100644 --- a/app/Support/FinTS/FinTS.php +++ b/app/Support/FinTS/FinTS.php @@ -3,6 +3,7 @@ namespace FireflyIII\Support\FinTS; +use Fhp\Model\SEPAAccount; use FireflyIII\Exceptions\FireflyException; use Illuminate\Support\Facades\Crypt; @@ -46,7 +47,7 @@ class FinTS } /** - * @return \Fhp\Model\SEPAAccount[] + * @return SEPAAccount[] * @throws FireflyException */ public function getAccounts() @@ -60,13 +61,13 @@ class FinTS /** * @param string $accountNumber - * @return \Fhp\Model\SEPAAccount + * @return SEPAAccount * @throws FireflyException */ - public function getAccount($accountNumber) + public function getAccount(string $accountNumber) { $accounts = $this->getAccounts(); - $filteredAccounts = array_filter($accounts, function ($account) use ($accountNumber) { + $filteredAccounts = array_filter($accounts, function (SEPAAccount $account) use ($accountNumber) { return $account->getAccountNumber() == $accountNumber; }); if (count($filteredAccounts) != 1) { @@ -76,13 +77,13 @@ class FinTS } /** - * @param \Fhp\Model\SEPAAccount $account + * @param SEPAAccount $account * @param \DateTime $from * @param \DateTIme $to * @return \Fhp\Model\StatementOfAccount\StatementOfAccount|null * @throws FireflyException */ - public function getStatementOfAccount(\Fhp\Model\SEPAAccount $account, \DateTime $from, \DateTIme $to) + public function getStatementOfAccount(SEPAAccount $account, \DateTime $from, \DateTIme $to) { try { return $this->finTS->getStatementOfAccount($account, $from, $to); From d7ca7e4cd8ccc8ad44fc73abc5baf2319bc3dab0 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:58:57 +0200 Subject: [PATCH 13/94] MessageBag needs messages as array --- .../Import/JobConfiguration/FinTS/ChooseAccountHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php index 0be29ffbe0..7bc9ba665e 100644 --- a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -61,7 +61,7 @@ class ChooseAccountHandler implements FinTSConfigurationInterface $finTS = new FinTS($this->importJob->configuration); $finTS->getAccount($config['fints_account']); } catch (FireflyException $e) { - return new MessageBag($e->getMessage()); + return new MessageBag([$e->getMessage()]); } $this->repository->setStage($this->importJob, FinTSConfigurationSteps::GO_FOR_IMPORT); From 84d0e44a08f258d6de41bb13b82096f0af70c8df Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 13:59:48 +0200 Subject: [PATCH 14/94] Strict comparison --- .../Import/JobConfiguration/FinTS/NewFinTSJobHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php index d03f773813..a2063f4780 100644 --- a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -60,7 +60,7 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface $incomplete = false; foreach ($config as $value) { - $incomplete = $value == '' or $incomplete; + $incomplete = $value === '' or $incomplete; } if ($incomplete) { return new MessageBag([trans('import.incomplete_fints_form')]); From 7de3c7f80a52cf2c3c2238f4558f3530997c26ee Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 14:02:06 +0200 Subject: [PATCH 15/94] Code style --- .../Import/JobConfiguration/FinTS/NewFinTSJobHandler.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php index a2063f4780..ccc4b7b67a 100644 --- a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -85,10 +85,10 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface { $config = $this->importJob->configuration; return [ - 'fints_url' => $config['fints_url'] ?? "", - 'fints_port' => $config['fints_port'] ?? "443", - 'fints_bank_code' => $config['fints_bank_code'] ?? "", - 'fints_username' => $config['fints_username'] ?? "" + 'fints_url' => $config['fints_url'] ?? '', + 'fints_port' => $config['fints_port'] ?? '443', + 'fints_bank_code' => $config['fints_bank_code'] ?? '', + 'fints_username' => $config['fints_username'] ?? '' ]; } From 4bb4ffbac4ce534b6576198881e46638edd24b93 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 14:05:07 +0200 Subject: [PATCH 16/94] Use Carbon instead of DateTime --- .../Import/JobConfiguration/FinTS/ChooseAccountHandler.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php index 7bc9ba665e..0bc1c40f7e 100644 --- a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Support\Import\JobConfiguration\FinTS; +use Carbon\Carbon; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps; use FireflyIII\Models\AccountType; @@ -98,8 +99,8 @@ class ChooseAccountHandler implements FinTSConfigurationInterface 'fints_account' => $this->importJob->configuration['fints_account'] ?? null, 'local_accounts' => $localAccounts, 'local_account' => $this->importJob->configuration['local_account'] ?? null, - 'from_date' => $this->importJob->configuration['from_date'] ?? (new \DateTime('now - 1 month'))->format('Y-m-d'), - 'to_date' => $this->importJob->configuration['to_date'] ?? (new \DateTime('now'))->format('Y-m-d') + 'from_date' => $this->importJob->configuration['from_date'] ?? (new Carbon('now - 1 month'))->format('Y-m-d'), + 'to_date' => $this->importJob->configuration['to_date'] ?? (new Carbon('now'))->format('Y-m-d') ]; return $data; } From 7e590fb6b3421ce777018dca85e15df08d40d277 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 14:10:53 +0200 Subject: [PATCH 17/94] Use arbitrary precision math --- app/Support/Import/Routine/FinTS/StageImportDataHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index 1f120c5600..e22927ffce 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -71,7 +71,7 @@ class StageImportDataHandler { Log::debug(sprintf('Start converting transaction %s', $transaction->getDescription1())); - $amount = $transaction->getAmount(); + $amount = (string) $transaction->getAmount(); $debitOrCredit = $transaction->getCreditDebit(); Log::debug(sprintf('Amount is %s', $amount)); @@ -79,7 +79,7 @@ class StageImportDataHandler $type = TransactionType::DEPOSIT; } else { $type = TransactionType::WITHDRAWAL; - $amount = -$amount; + $amount = bcmul($amount, '-1'); } $destination = $this->mapper->map( From 88083c5b38f2dec0027c641087d6afb73f92d7dd Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 3 Oct 2018 14:13:46 +0200 Subject: [PATCH 18/94] Added 'original-source'-field to imported transactions --- app/Support/Import/Routine/FinTS/StageImportDataHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index e22927ffce..daac971462 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -110,6 +110,7 @@ class StageImportDataHandler 'external_id' => null, 'notes' => null, 'bunq_payment_id' => null, + 'original-source' => sprintf('fints-v%s', config('firefly.version')), 'transactions' => [ // single transaction: [ From 336a9a97f9ae05cf8ccaac6dbeb087025a0bde2b Mon Sep 17 00:00:00 2001 From: Mike Conway Date: Wed, 3 Oct 2018 19:37:16 -0700 Subject: [PATCH 19/94] Update PiggyBankRequest.php Fix inconsistencies between repository and request variables --- app/Api/V1/Requests/PiggyBankRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Api/V1/Requests/PiggyBankRequest.php b/app/Api/V1/Requests/PiggyBankRequest.php index 3024b0eac9..080a9fe8c1 100644 --- a/app/Api/V1/Requests/PiggyBankRequest.php +++ b/app/Api/V1/Requests/PiggyBankRequest.php @@ -58,8 +58,8 @@ class PiggyBankRequest extends Request 'account_id' => $this->integer('account_id'), 'targetamount' => $this->string('target_amount'), 'current_amount' => $current, - 'start_date' => $this->date('start_date'), - 'target_date' => $this->date('target_date'), + 'startdate' => $this->date('start_date'), + 'targetdate' => $this->date('target_date'), 'notes' => $this->string('notes'), ]; } From 56fdb57d24edfe5e1ca8506b075056832154be4b Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 4 Oct 2018 20:06:12 +0200 Subject: [PATCH 20/94] Fix for #1583 --- app/Support/Binder/CLIToken.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Support/Binder/CLIToken.php b/app/Support/Binder/CLIToken.php index faeb5aef34..62a750f4bf 100644 --- a/app/Support/Binder/CLIToken.php +++ b/app/Support/Binder/CLIToken.php @@ -51,7 +51,7 @@ class CLIToken implements BinderInterface foreach ($users as $user) { $accessToken = app('preferences')->getForUser($user, 'access_token', null); - if ($accessToken->data === $value) { + if(null !== $accessToken && $accessToken->data === $value) { Log::info(sprintf('Recognized user #%d (%s) from his acccess token.', $user->id, $user->email)); return $value; From a1e2dac658058b7d377e5ff997834cae586498a0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 4 Oct 2018 20:55:04 +0200 Subject: [PATCH 21/94] Another fix for #1583 --- app/Factory/TransactionFactory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Factory/TransactionFactory.php b/app/Factory/TransactionFactory.php index ab66656da7..611ca37a93 100644 --- a/app/Factory/TransactionFactory.php +++ b/app/Factory/TransactionFactory.php @@ -120,8 +120,8 @@ class TransactionFactory Log::debug(sprintf('Expect source destination to be of type "%s"', $destinationType)); // find source and destination account: - $sourceAccount = $this->findAccount($sourceType, $data['source_id'], $data['source_name']); - $destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']); + $sourceAccount = $this->findAccount($sourceType, (int)$data['source_id'], $data['source_name']); + $destinationAccount = $this->findAccount($destinationType, (int)$data['destination_id'], $data['destination_name']); if (null === $sourceAccount || null === $destinationAccount) { $debugData = $data; From 306e1081e3b13f4cf5ee5de9e7f079e543d56439 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 5 Oct 2018 16:19:48 +0200 Subject: [PATCH 22/94] Bugfix: array_filter preserves keys, so $filteredAccounts[0] might not exist --- app/Support/FinTS/FinTS.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Support/FinTS/FinTS.php b/app/Support/FinTS/FinTS.php index 47931fb77c..d5dba345ee 100644 --- a/app/Support/FinTS/FinTS.php +++ b/app/Support/FinTS/FinTS.php @@ -73,7 +73,7 @@ class FinTS if (count($filteredAccounts) != 1) { throw new FireflyException("Cannot find account with number " . $accountNumber); } - return $filteredAccounts[0]; + return reset($filteredAccounts); } /** From aaff40c4ad8faf2d5490309b85806f3456a1062b Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 5 Oct 2018 16:30:05 +0200 Subject: [PATCH 23/94] Construct FinTS via service container so it can be mocked --- .../Import/JobConfiguration/FinTS/ChooseAccountHandler.php | 4 ++-- .../Import/JobConfiguration/FinTS/NewFinTSJobHandler.php | 2 +- app/Support/Import/Routine/FinTS/StageImportDataHandler.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php index 0bc1c40f7e..d08575288a 100644 --- a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -59,7 +59,7 @@ class ChooseAccountHandler implements FinTSConfigurationInterface $this->repository->setConfiguration($this->importJob, $config); try { - $finTS = new FinTS($this->importJob->configuration); + $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); $finTS->getAccount($config['fints_account']); } catch (FireflyException $e) { return new MessageBag([$e->getMessage()]); @@ -78,7 +78,7 @@ class ChooseAccountHandler implements FinTSConfigurationInterface */ public function getNextData(): array { - $finTS = new FinTS($this->importJob->configuration); + $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); $finTSAccounts = $finTS->getAccounts(); $finTSAccountsData = []; foreach ($finTSAccounts as $account) { diff --git a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php index ccc4b7b67a..619177ff6d 100644 --- a/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php @@ -66,7 +66,7 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface return new MessageBag([trans('import.incomplete_fints_form')]); } - $finTS = new FinTS($this->importJob->configuration); + $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); if (($checkConnection = $finTS->checkConnection()) !== true) { return new MessageBag([trans('import.fints_connection_failed', ['originalError' => $checkConnection])]); } diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index daac971462..443502ef6b 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -54,7 +54,7 @@ class StageImportDataHandler Log::debug('Now in StageImportDataHandler::run()'); $localAccount = $this->accountRepository->find($this->importJob->configuration['local_account']); - $finTS = new FinTS($this->importJob->configuration); + $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); $fintTSAccount = $finTS->getAccount($this->importJob->configuration['fints_account']); $statementOfAccount = $finTS->getStatementOfAccount($fintTSAccount, new \DateTime($this->importJob->configuration['from_date']), new \DateTime($this->importJob->configuration['to_date'])); $collection = []; From 0cda098b4f86c446c89f0a9b529a87abaecc5db5 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 5 Oct 2018 16:32:29 +0200 Subject: [PATCH 24/94] Don't use deprecated method accountRepository->find --- .../Import/Routine/FinTS/StageImportDataHandler.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index 443502ef6b..2162b1d754 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -6,6 +6,7 @@ namespace FireflyIII\Support\Import\Routine\FinTS; use Fhp\Model\StatementOfAccount\Transaction as FinTSTransaction; use Fhp\Model\StatementOfAccount\Transaction; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\AccountType; use FireflyIII\Models\ImportJob; use FireflyIII\Models\TransactionType; @@ -47,13 +48,16 @@ class StageImportDataHandler } /** - * @throws \FireflyIII\Exceptions\FireflyException + * @throws FireflyException */ public function run() { Log::debug('Now in StageImportDataHandler::run()'); - $localAccount = $this->accountRepository->find($this->importJob->configuration['local_account']); + $localAccount = $this->accountRepository->findNull($this->importJob->configuration['local_account']); + if ($localAccount === null) { + throw new FireflyException('Cannot find Firefly account with id ' . $this->importJob->configuration['local_account']); + } $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); $fintTSAccount = $finTS->getAccount($this->importJob->configuration['fints_account']); $statementOfAccount = $finTS->getStatementOfAccount($fintTSAccount, new \DateTime($this->importJob->configuration['from_date']), new \DateTime($this->importJob->configuration['to_date'])); From 6f707912391cd4bef0a445d2a0a992095a50c1ab Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 5 Oct 2018 17:54:51 +0200 Subject: [PATCH 25/94] Refactoring of code for #1159 --- .../FinTSConfigurationSteps.php | 35 ++ .../FinTSJobConfiguration.php | 15 +- app/Import/Routine/FinTSRoutine.php | 6 +- app/Support/FinTS/FinTS.php | 85 +++-- .../FinTS/ChooseAccountHandler.php | 29 +- .../FinTS/FinTSConfigurationInterface.php | 5 +- .../FinTS/NewFinTSJobHandler.php | 17 +- .../Routine/FinTS/StageImportDataHandler.php | 173 ++++++---- composer.lock | 305 ++++++++++++------ resources/lang/en_US/form.php | 2 +- resources/lang/en_US/import.php | 207 ++++++------ 11 files changed, 543 insertions(+), 336 deletions(-) create mode 100644 app/Import/JobConfiguration/FinTSConfigurationSteps.php diff --git a/app/Import/JobConfiguration/FinTSConfigurationSteps.php b/app/Import/JobConfiguration/FinTSConfigurationSteps.php new file mode 100644 index 0000000000..6f77b61b09 --- /dev/null +++ b/app/Import/JobConfiguration/FinTSConfigurationSteps.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Import\JobConfiguration; + +/** + * + * Class FinTSConfigurationSteps + */ +abstract class FinTSConfigurationSteps +{ + public const NEW = 'new'; + public const CHOOSE_ACCOUNT = 'choose_account'; + public const GO_FOR_IMPORT = 'go-for-import'; +} \ No newline at end of file diff --git a/app/Import/JobConfiguration/FinTSJobConfiguration.php b/app/Import/JobConfiguration/FinTSJobConfiguration.php index a3dc24b709..4b9c337343 100644 --- a/app/Import/JobConfiguration/FinTSJobConfiguration.php +++ b/app/Import/JobConfiguration/FinTSJobConfiguration.php @@ -1,7 +1,7 @@ importJob->stage == FinTSConfigurationSteps::GO_FOR_IMPORT; + return $this->importJob->stage === FinTSConfigurationSteps::GO_FOR_IMPORT; } /** diff --git a/app/Import/Routine/FinTSRoutine.php b/app/Import/Routine/FinTSRoutine.php index 7effeecfc5..7248c10a3f 100644 --- a/app/Import/Routine/FinTSRoutine.php +++ b/app/Import/Routine/FinTSRoutine.php @@ -1,7 +1,7 @@ . + */ +declare(strict_types=1); namespace FireflyIII\Support\FinTS; @@ -7,6 +26,10 @@ use Fhp\Model\SEPAAccount; use FireflyIII\Exceptions\FireflyException; use Illuminate\Support\Facades\Crypt; +/** + * + * Class FinTS + */ class FinTS { /** @var \Fhp\FinTs */ @@ -14,19 +37,14 @@ class FinTS /** * @param array $config + * * @throws FireflyException */ public function __construct(array $config) { - if ( - !isset($config['fints_url']) or - !isset($config['fints_port']) or - !isset($config['fints_bank_code']) or - !isset($config['fints_username']) or - !isset($config['fints_password'])) - throw new FireflyException( - "Constructed FinTS with incomplete config." - ); + if (!isset($config['fints_url'], $config['fints_port'], $config['fints_bank_code'], $config['fints_username'], $config['fints_password'])) { + throw new FireflyException('Constructed FinTS with incomplete config.'); + } $this->finTS = new \Fhp\FinTs( $config['fints_url'], $config['fints_port'], @@ -36,16 +54,41 @@ class FinTS ); } + /** + * @return bool|string + */ public function checkConnection() { try { $this->finTS->getSEPAAccounts(); + return true; } catch (\Exception $exception) { return $exception->getMessage(); } } + /** + * @param string $accountNumber + * + * @return SEPAAccount + * @throws FireflyException + */ + public function getAccount(string $accountNumber) + { + $accounts = $this->getAccounts(); + $filteredAccounts = array_filter( + $accounts, function (SEPAAccount $account) use ($accountNumber) { + return $account->getAccountNumber() === $accountNumber; + } + ); + if (count($filteredAccounts) != 1) { + throw new FireflyException("Cannot find account with number " . $accountNumber); + } + + return reset($filteredAccounts); + } + /** * @return SEPAAccount[] * @throws FireflyException @@ -59,27 +102,11 @@ class FinTS } } - /** - * @param string $accountNumber - * @return SEPAAccount - * @throws FireflyException - */ - public function getAccount(string $accountNumber) - { - $accounts = $this->getAccounts(); - $filteredAccounts = array_filter($accounts, function (SEPAAccount $account) use ($accountNumber) { - return $account->getAccountNumber() == $accountNumber; - }); - if (count($filteredAccounts) != 1) { - throw new FireflyException("Cannot find account with number " . $accountNumber); - } - return reset($filteredAccounts); - } - /** * @param SEPAAccount $account - * @param \DateTime $from - * @param \DateTIme $to + * @param \DateTime $from + * @param \DateTIme $to + * * @return \Fhp\Model\StatementOfAccount\StatementOfAccount|null * @throws FireflyException */ diff --git a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php index d08575288a..7f3ce9a511 100644 --- a/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +++ b/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php @@ -1,7 +1,7 @@ importJob->configuration; + $config = $this->repository->getConfiguration($this->importJob); $config['fints_account'] = (string)($data['fints_account'] ?? ''); $config['local_account'] = (string)($data['local_account'] ?? ''); $config['from_date'] = (string)($data['from_date'] ?? ''); @@ -59,7 +63,7 @@ class ChooseAccountHandler implements FinTSConfigurationInterface $this->repository->setConfiguration($this->importJob, $config); try { - $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); + $finTS = app(FinTS::class, ['config' => $config]); $finTS->getAccount($config['fints_account']); } catch (FireflyException $e) { return new MessageBag([$e->getMessage()]); @@ -89,19 +93,20 @@ class ChooseAccountHandler implements FinTSConfigurationInterface foreach ($this->accountRepository->getAccountsByType([AccountType::ASSET]) as $localAccount) { $display_name = $localAccount->name; if ($localAccount->iban) { - $display_name .= " - $localAccount->iban"; + $display_name .= sprintf(' - %s', $localAccount->iban); } $localAccounts[$localAccount->id] = $display_name; } $data = [ 'fints_accounts' => $finTSAccountsData, - 'fints_account' => $this->importJob->configuration['fints_account'] ?? null, + 'fints_account' => $this->importJob->configuration['fints_account'] ?? null, 'local_accounts' => $localAccounts, - 'local_account' => $this->importJob->configuration['local_account'] ?? null, - 'from_date' => $this->importJob->configuration['from_date'] ?? (new Carbon('now - 1 month'))->format('Y-m-d'), - 'to_date' => $this->importJob->configuration['to_date'] ?? (new Carbon('now'))->format('Y-m-d') + 'local_account' => $this->importJob->configuration['local_account'] ?? null, + 'from_date' => $this->importJob->configuration['from_date'] ?? (new Carbon('now - 1 month'))->format('Y-m-d'), + 'to_date' => $this->importJob->configuration['to_date'] ?? (new Carbon('now'))->format('Y-m-d'), ]; + return $data; } @@ -115,6 +120,4 @@ class ChooseAccountHandler implements FinTSConfigurationInterface $this->accountRepository = app(AccountRepositoryInterface::class); $this->repository->setUser($importJob->user); } - - } \ No newline at end of file diff --git a/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php b/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php index 47bcedad33..81bfd45c8c 100644 --- a/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php +++ b/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php @@ -1,7 +1,7 @@ $this->importJob->configuration]); - if (($checkConnection = $finTS->checkConnection()) !== true) { + if (true !== ($checkConnection = $finTS->checkConnection())) { return new MessageBag([trans('import.fints_connection_failed', ['originalError' => $checkConnection])]); } @@ -84,11 +88,12 @@ class NewFinTSJobHandler implements FinTSConfigurationInterface public function getNextData(): array { $config = $this->importJob->configuration; + return [ - 'fints_url' => $config['fints_url'] ?? '', - 'fints_port' => $config['fints_port'] ?? '443', + 'fints_url' => $config['fints_url'] ?? '', + 'fints_port' => $config['fints_port'] ?? '443', 'fints_bank_code' => $config['fints_bank_code'] ?? '', - 'fints_username' => $config['fints_username'] ?? '' + 'fints_username' => $config['fints_username'] ?? '', ]; } diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index 2162b1d754..89095dac35 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -1,34 +1,92 @@ . + */ +declare(strict_types=1); namespace FireflyIII\Support\Import\Routine\FinTS; -use Fhp\Model\StatementOfAccount\Transaction as FinTSTransaction; use Fhp\Model\StatementOfAccount\Transaction; +use Fhp\Model\StatementOfAccount\Transaction as FinTSTransaction; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Account as LocalAccount; use FireflyIII\Models\AccountType; use FireflyIII\Models\ImportJob; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Support\FinTS\FinTS; -use FireflyIII\Models\Account as LocalAccount; use FireflyIII\Support\Import\Routine\File\OpposingAccountMapper; use Illuminate\Support\Facades\Log; +/** + * + * Class StageImportDataHandler + */ class StageImportDataHandler { /** @var AccountRepositoryInterface */ private $accountRepository; /** @var ImportJob */ private $importJob; + /** @var OpposingAccountMapper */ + private $mapper; /** @var ImportJobRepositoryInterface */ private $repository; /** @var array */ private $transactions; - /** @var OpposingAccountMapper */ - private $mapper; + + /** + * @return array + */ + public function getTransactions(): array + { + return $this->transactions; + } + + /** + * @throws FireflyException + */ + public function run() + { + Log::debug('Now in StageImportDataHandler::run()'); + + $localAccount = $this->accountRepository->findNull($this->importJob->configuration['local_account']); + if (null === $localAccount) { + throw new FireflyException(sprintf('Cannot find Firefly account with id #%d ' , $this->importJob->configuration['local_account'])); + } + $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); + $fintTSAccount = $finTS->getAccount($this->importJob->configuration['fints_account']); + $statementOfAccount = $finTS->getStatementOfAccount( + $fintTSAccount, new \DateTime($this->importJob->configuration['from_date']), new \DateTime($this->importJob->configuration['to_date']) + ); + $collection = []; + foreach ($statementOfAccount->getStatements() as $statement) { + foreach ($statement->getTransactions() as $transaction) { + $collection[] = $this->convertTransaction($transaction, $localAccount); + } + } + + $this->transactions = $collection; + } /** * @param ImportJob $importJob @@ -48,40 +106,23 @@ class StageImportDataHandler } /** - * @throws FireflyException + * @param FinTSTransaction $transaction + * @param LocalAccount $source + * + * @return array */ - public function run() - { - Log::debug('Now in StageImportDataHandler::run()'); - - $localAccount = $this->accountRepository->findNull($this->importJob->configuration['local_account']); - if ($localAccount === null) { - throw new FireflyException('Cannot find Firefly account with id ' . $this->importJob->configuration['local_account']); - } - $finTS = app(FinTS::class, ['config' => $this->importJob->configuration]); - $fintTSAccount = $finTS->getAccount($this->importJob->configuration['fints_account']); - $statementOfAccount = $finTS->getStatementOfAccount($fintTSAccount, new \DateTime($this->importJob->configuration['from_date']), new \DateTime($this->importJob->configuration['to_date'])); - $collection = []; - foreach ($statementOfAccount->getStatements() as $statement) { - foreach ($statement->getTransactions() as $transaction) { - $collection[] = $this->convertTransaction($transaction, $localAccount); - } - } - - $this->transactions = $collection; - } - private function convertTransaction(FinTSTransaction $transaction, LocalAccount $source): array { Log::debug(sprintf('Start converting transaction %s', $transaction->getDescription1())); - $amount = (string) $transaction->getAmount(); + $amount = (string)$transaction->getAmount(); $debitOrCredit = $transaction->getCreditDebit(); - + // assume deposit. + $type = TransactionType::DEPOSIT; Log::debug(sprintf('Amount is %s', $amount)); - if ($debitOrCredit == Transaction::CD_CREDIT) { - $type = TransactionType::DEPOSIT; - } else { + + // inverse if not. + if ($debitOrCredit !== Transaction::CD_CREDIT) { $type = TransactionType::WITHDRAWAL; $amount = bcmul($amount, '-1'); } @@ -91,7 +132,7 @@ class StageImportDataHandler $amount, ['iban' => $transaction->getAccountNumber(), 'name' => $transaction->getName()] ); - if ($debitOrCredit == Transaction::CD_CREDIT) { + if ($debitOrCredit === Transaction::CD_CREDIT) { [$source, $destination] = [$destination, $source]; } @@ -101,52 +142,44 @@ class StageImportDataHandler } $storeData = [ - 'user' => $this->importJob->user_id, - 'type' => $type, - 'date' => $transaction->getValutaDate()->format('Y-m-d'), - 'description' => $transaction->getDescription1(), - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'bill_id' => null, - 'bill_name' => null, - 'tags' => [], + 'user' => $this->importJob->user_id, + 'type' => $type, + 'date' => $transaction->getValutaDate()->format('Y-m-d'), + 'description' => $transaction->getDescription1(), + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'bill_id' => null, + 'bill_name' => null, + 'tags' => [], 'internal_reference' => null, - 'external_id' => null, - 'notes' => null, - 'bunq_payment_id' => null, - 'original-source' => sprintf('fints-v%s', config('firefly.version')), - 'transactions' => [ + 'external_id' => null, + 'notes' => null, + 'bunq_payment_id' => null, + 'original-source' => sprintf('fints-v%s', config('firefly.version')), + 'transactions' => [ // single transaction: [ - 'description' => null, - 'amount' => $amount, - 'currency_id' => null, - 'currency_code' => 'EUR', - 'foreign_amount' => null, - 'foreign_currency_id' => null, + 'description' => null, + 'amount' => $amount, + 'currency_id' => null, + 'currency_code' => 'EUR', + 'foreign_amount' => null, + 'foreign_currency_id' => null, 'foreign_currency_code' => null, - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'source_id' => $source->id, - 'source_name' => null, - 'destination_id' => $destination->id, - 'destination_name' => null, - 'reconciled' => false, - 'identifier' => 0, + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'source_id' => $source->id, + 'source_name' => null, + 'destination_id' => $destination->id, + 'destination_name' => null, + 'reconciled' => false, + 'identifier' => 0, ], ], ]; return $storeData; } - - /** - * @return array - */ - public function getTransactions(): array - { - return $this->transactions; - } } \ No newline at end of file diff --git a/composer.lock b/composer.lock index 0ee40dde37..0a1196cefc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9297702ac3c2fc200aac5fc68821bdd6", + "content-hash": "a15b5b4991745824880345223530fa9e", "packages": [ { "name": "bacon/bacon-qr-code", @@ -1022,16 +1022,16 @@ }, { "name": "laravel/framework", - "version": "v5.7.6", + "version": "v5.7.8", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "93e761bb5367166ce98ba908d5eb0edd6be76792" + "reference": "763b64a43ebb6042e463aab4214d4cc9722147be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/93e761bb5367166ce98ba908d5eb0edd6be76792", - "reference": "93e761bb5367166ce98ba908d5eb0edd6be76792", + "url": "https://api.github.com/repos/laravel/framework/zipball/763b64a43ebb6042e463aab4214d4cc9722147be", + "reference": "763b64a43ebb6042e463aab4214d4cc9722147be", "shasum": "" }, "require": { @@ -1043,6 +1043,7 @@ "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", "nesbot/carbon": "^1.26.3", + "opis/closure": "^3.1", "php": "^7.1.3", "psr/container": "^1.0", "psr/simple-cache": "^1.0", @@ -1159,7 +1160,7 @@ "framework", "laravel" ], - "time": "2018-09-25T14:29:00+00:00" + "time": "2018-10-04T14:47:20+00:00" }, { "name": "laravel/passport", @@ -1838,6 +1839,41 @@ ], "time": "2017-06-19T01:22:40+00:00" }, + { + "name": "mschindler83/fints-hbci-php", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/mschindler83/fints-hbci-php.git", + "reference": "e58cb825c178d4c39a8974a9dd93abbc8094551f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mschindler83/fints-hbci-php/zipball/e58cb825c178d4c39a8974a9dd93abbc8094551f", + "reference": "e58cb825c178d4c39a8974a9dd93abbc8094551f", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "psr/log": "~1.0" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to a variety of different handlers" + }, + "type": "library", + "autoload": { + "psr-0": { + "Fhp": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP Library for the protocols fints and hbci", + "homepage": "http://fints-hbci-php.markus-schindler.de", + "time": "2017-02-15T13:48:21+00:00" + }, { "name": "nesbot/carbon", "version": "1.34.0", @@ -1893,6 +1929,67 @@ ], "time": "2018-09-20T19:36:25+00:00" }, + { + "name": "opis/closure", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "d3209e46ad6c69a969b705df0738fd0dbe26ef9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/d3209e46ad6c69a969b705df0738fd0dbe26ef9e", + "reference": "d3209e46ad6c69a969b705df0738fd0dbe26ef9e", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "time": "2018-10-02T13:36:53+00:00" + }, { "name": "paragonie/constant_time_encoding", "version": "v2.2.2", @@ -2633,16 +2730,16 @@ }, { "name": "symfony/console", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f" + "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ca80b8ced97cf07390078b29773dc384c39eee1f", - "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f", + "url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b", + "reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b", "shasum": "" }, "require": { @@ -2697,20 +2794,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-07-26T11:24:31+00:00" + "time": "2018-10-03T08:15:46+00:00" }, { "name": "symfony/css-selector", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "2a4df7618f869b456f9096781e78c57b509d76c7" + "reference": "d67de79a70a27d93c92c47f37ece958bf8de4d8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/2a4df7618f869b456f9096781e78c57b509d76c7", - "reference": "2a4df7618f869b456f9096781e78c57b509d76c7", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/d67de79a70a27d93c92c47f37ece958bf8de4d8a", + "reference": "d67de79a70a27d93c92c47f37ece958bf8de4d8a", "shasum": "" }, "require": { @@ -2750,20 +2847,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:10:45+00:00" + "time": "2018-10-02T16:36:10+00:00" }, { "name": "symfony/debug", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "47ead688f1f2877f3f14219670f52e4722ee7052" + "reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/47ead688f1f2877f3f14219670f52e4722ee7052", - "reference": "47ead688f1f2877f3f14219670f52e4722ee7052", + "url": "https://api.github.com/repos/symfony/debug/zipball/e3f76ce6198f81994e019bb2b4e533e9de1b9b90", + "reference": "e3f76ce6198f81994e019bb2b4e533e9de1b9b90", "shasum": "" }, "require": { @@ -2806,11 +2903,11 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-08-03T11:13:38+00:00" + "time": "2018-10-02T16:36:10+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -2873,16 +2970,16 @@ }, { "name": "symfony/finder", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e162f1df3102d0b7472805a5a9d5db9fcf0a8068" + "reference": "1f17195b44543017a9c9b2d437c670627e96ad06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e162f1df3102d0b7472805a5a9d5db9fcf0a8068", - "reference": "e162f1df3102d0b7472805a5a9d5db9fcf0a8068", + "url": "https://api.github.com/repos/symfony/finder/zipball/1f17195b44543017a9c9b2d437c670627e96ad06", + "reference": "1f17195b44543017a9c9b2d437c670627e96ad06", "shasum": "" }, "require": { @@ -2918,20 +3015,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-07-26T11:24:31+00:00" + "time": "2018-10-03T08:47:56+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "3a5c91e133b220bb882b3cd773ba91bf39989345" + "reference": "d528136617ff24f530e70df9605acc1b788b08d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3a5c91e133b220bb882b3cd773ba91bf39989345", - "reference": "3a5c91e133b220bb882b3cd773ba91bf39989345", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d528136617ff24f530e70df9605acc1b788b08d4", + "reference": "d528136617ff24f530e70df9605acc1b788b08d4", "shasum": "" }, "require": { @@ -2972,20 +3069,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-08-27T17:47:02+00:00" + "time": "2018-10-03T08:48:45+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "33de0a1ff2e1720096189e3ced682d7a4e8f5e35" + "reference": "f5e7c15a5d010be0e16ce798594c5960451d4220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/33de0a1ff2e1720096189e3ced682d7a4e8f5e35", - "reference": "33de0a1ff2e1720096189e3ced682d7a4e8f5e35", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f5e7c15a5d010be0e16ce798594c5960451d4220", + "reference": "f5e7c15a5d010be0e16ce798594c5960451d4220", "shasum": "" }, "require": { @@ -3059,7 +3156,7 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-08-28T06:17:42+00:00" + "time": "2018-10-03T12:53:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3343,16 +3440,16 @@ }, { "name": "symfony/process", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "86cdb930a6a855b0ab35fb60c1504cb36184f843" + "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/86cdb930a6a855b0ab35fb60c1504cb36184f843", - "reference": "86cdb930a6a855b0ab35fb60c1504cb36184f843", + "url": "https://api.github.com/repos/symfony/process/zipball/ee33c0322a8fee0855afcc11fff81e6b1011b529", + "reference": "ee33c0322a8fee0855afcc11fff81e6b1011b529", "shasum": "" }, "require": { @@ -3388,7 +3485,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-08-03T11:13:38+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -3453,16 +3550,16 @@ }, { "name": "symfony/routing", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "a5784c2ec4168018c87b38f0e4f39d2278499f51" + "reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/a5784c2ec4168018c87b38f0e4f39d2278499f51", - "reference": "a5784c2ec4168018c87b38f0e4f39d2278499f51", + "url": "https://api.github.com/repos/symfony/routing/zipball/537803f0bdfede36b9acef052d2e4d447d9fa0e9", + "reference": "537803f0bdfede36b9acef052d2e4d447d9fa0e9", "shasum": "" }, "require": { @@ -3526,20 +3623,20 @@ "uri", "url" ], - "time": "2018-08-03T07:58:40+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/translation", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f" + "reference": "9f0b61e339160a466ebcde167a6c5521c810e304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/fa2182669f7983b7aa5f1a770d053f79f0ef144f", - "reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f", + "url": "https://api.github.com/repos/symfony/translation/zipball/9f0b61e339160a466ebcde167a6c5521c810e304", + "reference": "9f0b61e339160a466ebcde167a6c5521c810e304", "shasum": "" }, "require": { @@ -3595,20 +3692,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-08-07T12:45:11+00:00" + "time": "2018-10-02T16:36:10+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "a05426e27294bba7b0226ffc17dd01a3c6ef9777" + "reference": "60319b45653580b0cdacca499344577d87732f16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a05426e27294bba7b0226ffc17dd01a3c6ef9777", - "reference": "a05426e27294bba7b0226ffc17dd01a3c6ef9777", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/60319b45653580b0cdacca499344577d87732f16", + "reference": "60319b45653580b0cdacca499344577d87732f16", "shasum": "" }, "require": { @@ -3670,7 +3767,7 @@ "debug", "dump" ], - "time": "2018-08-02T09:24:26+00:00" + "time": "2018-10-02T16:36:10+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4656,16 +4753,16 @@ }, { "name": "mockery/mockery", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "99e29d3596b16dabe4982548527d5ddf90232e99" + "reference": "100633629bf76d57430b86b7098cd6beb996a35a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/99e29d3596b16dabe4982548527d5ddf90232e99", - "reference": "99e29d3596b16dabe4982548527d5ddf90232e99", + "url": "https://api.github.com/repos/mockery/mockery/zipball/100633629bf76d57430b86b7098cd6beb996a35a", + "reference": "100633629bf76d57430b86b7098cd6beb996a35a", "shasum": "" }, "require": { @@ -4674,8 +4771,7 @@ "php": ">=5.6.0" }, "require-dev": { - "phpdocumentor/phpdocumentor": "^2.9", - "phpunit/phpunit": "~5.7.10|~6.5" + "phpunit/phpunit": "~5.7.10|~6.5|~7.0" }, "type": "library", "extra": { @@ -4718,7 +4814,7 @@ "test double", "testing" ], - "time": "2018-05-08T08:54:48+00:00" + "time": "2018-10-02T21:52:37+00:00" }, { "name": "myclabs/deep-copy", @@ -5170,16 +5266,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "6.0.7", + "version": "6.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" + "reference": "848f78b3309780fef7ec8c4666b7ab4e6b09b22f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", - "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/848f78b3309780fef7ec8c4666b7ab4e6b09b22f", + "reference": "848f78b3309780fef7ec8c4666b7ab4e6b09b22f", "shasum": "" }, "require": { @@ -5229,7 +5325,7 @@ "testing", "xunit" ], - "time": "2018-06-01T07:51:50+00:00" + "time": "2018-10-04T03:41:23+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5422,16 +5518,16 @@ }, { "name": "phpunit/phpunit", - "version": "7.3.5", + "version": "7.4.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7b331efabbb628c518c408fdfcaf571156775de2" + "reference": "f3837fa1e07758057ae06e8ddec6d06ba183f126" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7b331efabbb628c518c408fdfcaf571156775de2", - "reference": "7b331efabbb628c518c408fdfcaf571156775de2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3837fa1e07758057ae06e8ddec6d06ba183f126", + "reference": "f3837fa1e07758057ae06e8ddec6d06ba183f126", "shasum": "" }, "require": { @@ -5456,7 +5552,7 @@ "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0", "sebastian/version": "^2.0.1" }, "conflict": { @@ -5476,7 +5572,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.3-dev" + "dev-master": "7.4-dev" } }, "autoload": { @@ -5502,7 +5598,7 @@ "testing", "xunit" ], - "time": "2018-09-08T15:14:29+00:00" + "time": "2018-10-05T04:05:24+00:00" }, { "name": "roave/security-advisories", @@ -5510,6 +5606,7 @@ "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", + "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", @@ -5677,7 +5774,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-09-17T20:20:31+00:00" + "time": "2018-10-02T16:19:22+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6159,25 +6256,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -6197,7 +6294,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" }, { "name": "sebastian/version", @@ -6337,16 +6434,16 @@ }, { "name": "symfony/config", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "76015a3cc372b14d00040ff58e18e29f69eba717" + "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/76015a3cc372b14d00040ff58e18e29f69eba717", - "reference": "76015a3cc372b14d00040ff58e18e29f69eba717", + "url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96", + "reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96", "shasum": "" }, "require": { @@ -6396,20 +6493,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-08-08T06:37:38+00:00" + "time": "2018-09-08T13:24:10+00:00" }, { "name": "symfony/filesystem", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e" + "reference": "596d12b40624055c300c8b619755b748ca5cf0b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", - "reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5", + "reference": "596d12b40624055c300c8b619755b748ca5cf0b5", "shasum": "" }, "require": { @@ -6446,20 +6543,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-08-18T16:52:46+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/stopwatch", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "966c982df3cca41324253dc0c7ffe76b6076b705" + "reference": "5bfc064125b73ff81229e19381ce1c34d3416f4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/966c982df3cca41324253dc0c7ffe76b6076b705", - "reference": "966c982df3cca41324253dc0c7ffe76b6076b705", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5bfc064125b73ff81229e19381ce1c34d3416f4b", + "reference": "5bfc064125b73ff81229e19381ce1c34d3416f4b", "shasum": "" }, "require": { @@ -6495,20 +6592,20 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-07-26T11:00:49+00:00" + "time": "2018-10-02T12:40:59+00:00" }, { "name": "symfony/yaml", - "version": "v4.1.4", + "version": "v4.1.6", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "b832cc289608b6d305f62149df91529a2ab3c314" + "reference": "367e689b2fdc19965be435337b50bc8adf2746c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/b832cc289608b6d305f62149df91529a2ab3c314", - "reference": "b832cc289608b6d305f62149df91529a2ab3c314", + "url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9", + "reference": "367e689b2fdc19965be435337b50bc8adf2746c9", "shasum": "" }, "require": { @@ -6554,7 +6651,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-08-18T16:52:46+00:00" + "time": "2018-10-02T16:36:10+00:00" }, { "name": "theseer/tokenizer", diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index fd79a7f5aa..6b4999f3f9 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -231,7 +231,7 @@ return [ 'local_account' => 'Firefly III account', 'from_date' => 'Date from', 'to_date' => 'Date to', - + 'due_date' => 'Due date', 'payment_date' => 'Payment date', diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 783b8f0a7f..30a275c585 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -47,6 +47,9 @@ return [ 'button_yodlee' => 'Import using Yodlee', 'button_quovo' => 'Import using Quovo', 'button_ynab' => 'Import from You Need A Budget', + 'button_fints' => 'Import using FinTS', + + // global config box (index) 'global_config_title' => 'Global import configuration', 'global_config_text' => 'In the future, this box will feature preferences that apply to ALL import providers above.', @@ -201,118 +204,118 @@ return [ 'spectre_extra_key_transactions_count' => 'Transaction count', //job configuration for finTS 'fints_connection_failed' => 'An error occurred while trying to connecting to your bank. Please mak sure that all the data you entered is correct. Original error message: :originalError', - 'button_fints' => 'FinTS', - 'job_config_fints_url_help' => 'E.g. https://banking-dkb.s-fints-pt-dkb.de/fints30', - 'job_config_fints_username_help' => 'For many banks this is your account number.', - 'job_config_fints_port_help' => 'The default port is 443.', - 'job_config_fints_account_help' => 'Choose the bank account for which you want to import transactions.', - 'job_config_local_account_help' => 'Choose the Firefly III account corresponding to your bank account chosen above.', + + 'job_config_fints_url_help' => 'E.g. https://banking-dkb.s-fints-pt-dkb.de/fints30', + 'job_config_fints_username_help' => 'For many banks this is your account number.', + 'job_config_fints_port_help' => 'The default port is 443.', + 'job_config_fints_account_help' => 'Choose the bank account for which you want to import transactions.', + 'job_config_local_account_help' => 'Choose the Firefly III account corresponding to your bank account chosen above.', // specifics: - 'specific_ing_name' => 'ING NL', - 'specific_ing_descr' => 'Create better descriptions in ING exports', - 'specific_sns_name' => 'SNS / Volksbank NL', - 'specific_sns_descr' => 'Trim quotes from SNS / Volksbank export files', - 'specific_abn_name' => 'ABN AMRO NL', - 'specific_abn_descr' => 'Fixes potential problems with ABN AMRO files', - 'specific_rabo_name' => 'Rabobank NL', - 'specific_rabo_descr' => 'Fixes potential problems with Rabobank files', - 'specific_pres_name' => 'President\'s Choice Financial CA', - 'specific_pres_descr' => 'Fixes potential problems with PC files', + 'specific_ing_name' => 'ING NL', + 'specific_ing_descr' => 'Create better descriptions in ING exports', + 'specific_sns_name' => 'SNS / Volksbank NL', + 'specific_sns_descr' => 'Trim quotes from SNS / Volksbank export files', + 'specific_abn_name' => 'ABN AMRO NL', + 'specific_abn_descr' => 'Fixes potential problems with ABN AMRO files', + 'specific_rabo_name' => 'Rabobank NL', + 'specific_rabo_descr' => 'Fixes potential problems with Rabobank files', + 'specific_pres_name' => 'President\'s Choice Financial CA', + 'specific_pres_descr' => 'Fixes potential problems with PC files', // job configuration for file provider (stage: roles) - 'job_config_roles_title' => 'Import setup (3/4) - Define each column\'s role', - 'job_config_roles_text' => 'Each column in your CSV file contains certain data. Please indicate what kind of data the importer should expect. The option to "map" data means that you will link each entry found in the column to a value in your database. An often mapped column is the column that contains the IBAN of the opposing account. That can be easily matched to IBAN\'s present in your database already.', - 'job_config_roles_submit' => 'Continue', - 'job_config_roles_column_name' => 'Name of column', - 'job_config_roles_column_example' => 'Column example data', - 'job_config_roles_column_role' => 'Column data meaning', - 'job_config_roles_do_map_value' => 'Map these values', - 'job_config_roles_no_example' => 'No example data available', - 'job_config_roles_fa_warning' => 'If you mark a column as containing an amount in a foreign currency, you must also set the column that contains which currency it is.', - 'job_config_roles_rwarning' => 'At the very least, mark one column as the amount-column. It is advisable to also select a column for the description, date and the opposing account.', - 'job_config_roles_colum_count' => 'Column', + 'job_config_roles_title' => 'Import setup (3/4) - Define each column\'s role', + 'job_config_roles_text' => 'Each column in your CSV file contains certain data. Please indicate what kind of data the importer should expect. The option to "map" data means that you will link each entry found in the column to a value in your database. An often mapped column is the column that contains the IBAN of the opposing account. That can be easily matched to IBAN\'s present in your database already.', + 'job_config_roles_submit' => 'Continue', + 'job_config_roles_column_name' => 'Name of column', + 'job_config_roles_column_example' => 'Column example data', + 'job_config_roles_column_role' => 'Column data meaning', + 'job_config_roles_do_map_value' => 'Map these values', + 'job_config_roles_no_example' => 'No example data available', + 'job_config_roles_fa_warning' => 'If you mark a column as containing an amount in a foreign currency, you must also set the column that contains which currency it is.', + 'job_config_roles_rwarning' => 'At the very least, mark one column as the amount-column. It is advisable to also select a column for the description, date and the opposing account.', + 'job_config_roles_colum_count' => 'Column', // job config for the file provider (stage: mapping): - 'job_config_map_title' => 'Import setup (4/4) - Connect import data to Firefly III data', - 'job_config_map_text' => 'In the following tables, the left value shows you information found in your uploaded file. It is your task to map this value, if possible, to a value already present in your database. Firefly will stick to this mapping. If there is no value to map to, or you do not wish to map the specific value, select nothing.', - 'job_config_map_nothing' => 'There is no data present in your file that you can map to existing values. Please press "Start the import" to continue.', - 'job_config_field_value' => 'Field value', - 'job_config_field_mapped' => 'Mapped to', - 'map_do_not_map' => '(do not map)', - 'job_config_map_submit' => 'Start the import', + 'job_config_map_title' => 'Import setup (4/4) - Connect import data to Firefly III data', + 'job_config_map_text' => 'In the following tables, the left value shows you information found in your uploaded file. It is your task to map this value, if possible, to a value already present in your database. Firefly will stick to this mapping. If there is no value to map to, or you do not wish to map the specific value, select nothing.', + 'job_config_map_nothing' => 'There is no data present in your file that you can map to existing values. Please press "Start the import" to continue.', + 'job_config_field_value' => 'Field value', + 'job_config_field_mapped' => 'Mapped to', + 'map_do_not_map' => '(do not map)', + 'job_config_map_submit' => 'Start the import', // import status page: - 'import_with_key' => 'Import with key \':key\'', - 'status_wait_title' => 'Please hold...', - 'status_wait_text' => 'This box will disappear in a moment.', - 'status_running_title' => 'The import is running', - 'status_job_running' => 'Please wait, running the import...', - 'status_job_storing' => 'Please wait, storing data...', - 'status_job_rules' => 'Please wait, running rules...', - 'status_fatal_title' => 'Fatal error', - 'status_fatal_text' => 'The import has suffered from an error it could not recover from. Apologies!', - 'status_fatal_more' => 'This (possibly very cryptic) error message is complemented by log files, which you can find on your hard drive, or in the Docker container where you run Firefly III from.', - 'status_finished_title' => 'Import finished', - 'status_finished_text' => 'The import has finished.', - 'finished_with_errors' => 'There were some errors during the import. Please review them carefully.', - 'unknown_import_result' => 'Unknown import result', - 'result_no_transactions' => 'No transactions have been imported. Perhaps they were all duplicates is simply no transactions where present to be imported. Perhaps the log files can tell you what happened. If you import data regularly, this is normal.', - 'result_one_transaction' => 'Exactly one transaction has been imported. It is stored under tag :tag where you can inspect it further.', - 'result_many_transactions' => 'Firefly III has imported :count transactions. They are stored under tag :tag where you can inspect them further.', + 'import_with_key' => 'Import with key \':key\'', + 'status_wait_title' => 'Please hold...', + 'status_wait_text' => 'This box will disappear in a moment.', + 'status_running_title' => 'The import is running', + 'status_job_running' => 'Please wait, running the import...', + 'status_job_storing' => 'Please wait, storing data...', + 'status_job_rules' => 'Please wait, running rules...', + 'status_fatal_title' => 'Fatal error', + 'status_fatal_text' => 'The import has suffered from an error it could not recover from. Apologies!', + 'status_fatal_more' => 'This (possibly very cryptic) error message is complemented by log files, which you can find on your hard drive, or in the Docker container where you run Firefly III from.', + 'status_finished_title' => 'Import finished', + 'status_finished_text' => 'The import has finished.', + 'finished_with_errors' => 'There were some errors during the import. Please review them carefully.', + 'unknown_import_result' => 'Unknown import result', + 'result_no_transactions' => 'No transactions have been imported. Perhaps they were all duplicates is simply no transactions where present to be imported. Perhaps the log files can tell you what happened. If you import data regularly, this is normal.', + 'result_one_transaction' => 'Exactly one transaction has been imported. It is stored under tag :tag where you can inspect it further.', + 'result_many_transactions' => 'Firefly III has imported :count transactions. They are stored under tag :tag where you can inspect them further.', // general errors and warnings: - 'bad_job_status' => 'To access this page, your import job cannot have status ":status".', + 'bad_job_status' => 'To access this page, your import job cannot have status ":status".', // column roles for CSV import: - 'column__ignore' => '(ignore this column)', - 'column_account-iban' => 'Asset account (IBAN)', - 'column_account-id' => 'Asset account ID (matching FF3)', - 'column_account-name' => 'Asset account (name)', - 'column_account-bic' => 'Asset account (BIC)', - 'column_amount' => 'Amount', - 'column_amount_foreign' => 'Amount (in foreign currency)', - 'column_amount_debit' => 'Amount (debit column)', - 'column_amount_credit' => 'Amount (credit column)', - 'column_amount_negated' => 'Amount (negated column)', - 'column_amount-comma-separated' => 'Amount (comma as decimal separator)', - 'column_bill-id' => 'Bill ID (matching FF3)', - 'column_bill-name' => 'Bill name', - 'column_budget-id' => 'Budget ID (matching FF3)', - 'column_budget-name' => 'Budget name', - 'column_category-id' => 'Category ID (matching FF3)', - 'column_category-name' => 'Category name', - 'column_currency-code' => 'Currency code (ISO 4217)', - 'column_foreign-currency-code' => 'Foreign currency code (ISO 4217)', - 'column_currency-id' => 'Currency ID (matching FF3)', - 'column_currency-name' => 'Currency name (matching FF3)', - 'column_currency-symbol' => 'Currency symbol (matching FF3)', - 'column_date-interest' => 'Interest calculation date', - 'column_date-book' => 'Transaction booking date', - 'column_date-process' => 'Transaction process date', - 'column_date-transaction' => 'Date', - 'column_date-due' => 'Transaction due date', - 'column_date-payment' => 'Transaction payment date', - 'column_date-invoice' => 'Transaction invoice date', - 'column_description' => 'Description', - 'column_opposing-iban' => 'Opposing account (IBAN)', - 'column_opposing-bic' => 'Opposing account (BIC)', - 'column_opposing-id' => 'Opposing account ID (matching FF3)', - 'column_external-id' => 'External ID', - 'column_opposing-name' => 'Opposing account (name)', - 'column_rabo-debit-credit' => 'Rabobank specific debit/credit indicator', - 'column_ing-debit-credit' => 'ING specific debit/credit indicator', - 'column_sepa-ct-id' => 'SEPA end-to-end Identifier', - 'column_sepa-ct-op' => 'SEPA Opposing Account Identifier', - 'column_sepa-db' => 'SEPA Mandate Identifier', - 'column_sepa-cc' => 'SEPA Clearing Code', - 'column_sepa-ci' => 'SEPA Creditor Identifier', - 'column_sepa-ep' => 'SEPA External Purpose', - 'column_sepa-country' => 'SEPA Country Code', - 'column_tags-comma' => 'Tags (comma separated)', - 'column_tags-space' => 'Tags (space separated)', - 'column_account-number' => 'Asset account (account number)', - 'column_opposing-number' => 'Opposing account (account number)', - 'column_note' => 'Note(s)', - 'column_internal-reference' => 'Internal reference', + 'column__ignore' => '(ignore this column)', + 'column_account-iban' => 'Asset account (IBAN)', + 'column_account-id' => 'Asset account ID (matching FF3)', + 'column_account-name' => 'Asset account (name)', + 'column_account-bic' => 'Asset account (BIC)', + 'column_amount' => 'Amount', + 'column_amount_foreign' => 'Amount (in foreign currency)', + 'column_amount_debit' => 'Amount (debit column)', + 'column_amount_credit' => 'Amount (credit column)', + 'column_amount_negated' => 'Amount (negated column)', + 'column_amount-comma-separated' => 'Amount (comma as decimal separator)', + 'column_bill-id' => 'Bill ID (matching FF3)', + 'column_bill-name' => 'Bill name', + 'column_budget-id' => 'Budget ID (matching FF3)', + 'column_budget-name' => 'Budget name', + 'column_category-id' => 'Category ID (matching FF3)', + 'column_category-name' => 'Category name', + 'column_currency-code' => 'Currency code (ISO 4217)', + 'column_foreign-currency-code' => 'Foreign currency code (ISO 4217)', + 'column_currency-id' => 'Currency ID (matching FF3)', + 'column_currency-name' => 'Currency name (matching FF3)', + 'column_currency-symbol' => 'Currency symbol (matching FF3)', + 'column_date-interest' => 'Interest calculation date', + 'column_date-book' => 'Transaction booking date', + 'column_date-process' => 'Transaction process date', + 'column_date-transaction' => 'Date', + 'column_date-due' => 'Transaction due date', + 'column_date-payment' => 'Transaction payment date', + 'column_date-invoice' => 'Transaction invoice date', + 'column_description' => 'Description', + 'column_opposing-iban' => 'Opposing account (IBAN)', + 'column_opposing-bic' => 'Opposing account (BIC)', + 'column_opposing-id' => 'Opposing account ID (matching FF3)', + 'column_external-id' => 'External ID', + 'column_opposing-name' => 'Opposing account (name)', + 'column_rabo-debit-credit' => 'Rabobank specific debit/credit indicator', + 'column_ing-debit-credit' => 'ING specific debit/credit indicator', + 'column_sepa-ct-id' => 'SEPA end-to-end Identifier', + 'column_sepa-ct-op' => 'SEPA Opposing Account Identifier', + 'column_sepa-db' => 'SEPA Mandate Identifier', + 'column_sepa-cc' => 'SEPA Clearing Code', + 'column_sepa-ci' => 'SEPA Creditor Identifier', + 'column_sepa-ep' => 'SEPA External Purpose', + 'column_sepa-country' => 'SEPA Country Code', + 'column_tags-comma' => 'Tags (comma separated)', + 'column_tags-space' => 'Tags (space separated)', + 'column_account-number' => 'Asset account (account number)', + 'column_opposing-number' => 'Opposing account (account number)', + 'column_note' => 'Note(s)', + 'column_internal-reference' => 'Internal reference', ]; From 011d8a2b9a90116d6cc8ddcb16a77cb5963cd059 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 09:45:50 +0200 Subject: [PATCH 26/94] Make stuff scale better #1040 --- .../Controllers/Budget/ShowController.php | 2 +- .../Controllers/Chart/CategoryController.php | 47 ++- app/Http/Controllers/TagController.php | 2 +- app/Repositories/Tag/TagRepository.php | 51 +++ .../Tag/TagRepositoryInterface.php | 27 ++ .../Http/Controllers/PeriodOverview.php | 306 ++++++++++-------- resources/views/list/periods.twig | 1 + resources/views/tags/show.twig | 28 +- resources/views/transactions/index.twig | 42 +-- 9 files changed, 287 insertions(+), 219 deletions(-) diff --git a/app/Http/Controllers/Budget/ShowController.php b/app/Http/Controllers/Budget/ShowController.php index 4347702490..170cf4ec19 100644 --- a/app/Http/Controllers/Budget/ShowController.php +++ b/app/Http/Controllers/Budget/ShowController.php @@ -88,7 +88,7 @@ class ShowController extends Controller 'firefly.without_budget_between', ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] ); - $periods = $this->getBudgetPeriodOverview($end); + $periods = $this->getNoBudgetPeriodOverview($end); $page = (int)$request->get('page'); $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index 7e6a17eefd..411ff6cad0 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -32,6 +32,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Support\CacheProperties; +use FireflyIII\Support\Http\Controllers\DateCalculation; use Illuminate\Http\JsonResponse; use Illuminate\Support\Collection; @@ -40,6 +41,7 @@ use Illuminate\Support\Collection; */ class CategoryController extends Controller { + use DateCalculation; /** @var GeneratorInterface Chart generation methods. */ protected $generator; @@ -97,17 +99,36 @@ class CategoryController extends Controller 'entries' => [], 'type' => 'line', 'fill' => false, ], ]; - - while ($start <= $end) { - $currentEnd = app('navigation')->endOfPeriod($start, $range); - $spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $currentEnd); - $earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $currentEnd); - $sum = bcadd($spent, $earned); - $label = app('navigation')->periodShow($start, $range); - $chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12); - $chartData[1]['entries'][$label] = round($earned, 12); - $chartData[2]['entries'][$label] = round($sum, 12); - $start = app('navigation')->addPeriod($start, $range, 0); + $step = $this->calculateStep($start, $end); + $current = clone $start; + switch ($step) { + case '1D': + while ($current <= $end) { + $spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $current, $current); + $earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $current, $current); + $sum = bcadd($spent, $earned); + $label = app('navigation')->periodShow($current, $step); + $chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12); + $chartData[1]['entries'][$label] = round($earned, 12); + $chartData[2]['entries'][$label] = round($sum, 12); + $current->addDay(); + } + break; + case '1W': + case '1M': + case '1Y': + while ($current <= $end) { + $currentEnd = app('navigation')->endOfPeriod($current, $range); + $spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $current, $currentEnd); + $earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $current, $currentEnd); + $sum = bcadd($spent, $earned); + $label = app('navigation')->periodShow($current, $step); + $chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12); + $chartData[1]['entries'][$label] = round($earned, 12); + $chartData[2]['entries'][$label] = round($sum, 12); + $current= app('navigation')->addPeriod($current, $step, 0); + } + break; } $data = $this->generator->multiSet($chartData); @@ -135,7 +156,7 @@ class CategoryController extends Controller $cache->addProperty($end); $cache->addProperty('chart.category.frontpage'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } // currency repos: @@ -168,7 +189,7 @@ class CategoryController extends Controller $noCategory = $repository->spentInPeriodPcWoCategory(new Collection, $start, $end); foreach ($noCategory as $currencyId => $spent) { $currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId); - $tempData[] = [ + $tempData[] = [ 'name' => trans('firefly.no_category'), 'spent' => bcmul($spent, '-1'), 'spent_float' => (float)bcmul($spent, '-1'), diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index a2731043dc..7dba1172fa 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -192,7 +192,7 @@ class TagController extends Controller 'firefly.journals_in_period_for_tag', ['tag' => $tag->tag, 'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat),] ); - $periods = $this->getTagPeriodOverview($tag); + $periods = $this->getTagPeriodOverview($tag, $start); $path = route('tags.show', [$tag->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); /** @var TransactionCollectorInterface $collector */ diff --git a/app/Repositories/Tag/TagRepository.php b/app/Repositories/Tag/TagRepository.php index 928bd97b0f..3a9b261bfd 100644 --- a/app/Repositories/Tag/TagRepository.php +++ b/app/Repositories/Tag/TagRepository.php @@ -92,6 +92,23 @@ class TagRepository implements TagRepositoryInterface return (string)$set->sum('transaction_amount'); } + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function expenseInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection + { + /** @var TransactionCollectorInterface $collector */ + $collector = app(TransactionCollectorInterface::class); + $collector->setUser($this->user); + $collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAllAssetAccounts()->setTag($tag); + + return $collector->getTransactions(); + } + /** * @param string $tag * @@ -151,6 +168,23 @@ class TagRepository implements TagRepositoryInterface return $tags; } + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function incomeInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection + { + /** @var TransactionCollectorInterface $collector */ + $collector = app(TransactionCollectorInterface::class); + $collector->setUser($this->user); + $collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAllAssetAccounts()->setTag($tag); + + return $collector->getTransactions(); + } + /** * @param Tag $tag * @@ -315,6 +349,23 @@ class TagRepository implements TagRepositoryInterface return $return; } + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function transferredInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection + { + /** @var TransactionCollectorInterface $collector */ + $collector = app(TransactionCollectorInterface::class); + $collector->setUser($this->user); + $collector->setRange($start, $end)->setTypes([TransactionType::TRANSFER])->setAllAssetAccounts()->setTag($tag); + + return $collector->getTransactions(); + } + /** * @param Tag $tag * @param array $data diff --git a/app/Repositories/Tag/TagRepositoryInterface.php b/app/Repositories/Tag/TagRepositoryInterface.php index bedfef3cb7..223b61e22c 100644 --- a/app/Repositories/Tag/TagRepositoryInterface.php +++ b/app/Repositories/Tag/TagRepositoryInterface.php @@ -55,6 +55,15 @@ interface TagRepositoryInterface */ public function earnedInPeriod(Tag $tag, Carbon $start, Carbon $end): string; + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function expenseInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection; + /** * @param string $tag * @@ -83,6 +92,15 @@ interface TagRepositoryInterface */ public function get(): Collection; + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function incomeInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection; + /** * @param Tag $tag * @@ -147,6 +165,15 @@ interface TagRepositoryInterface */ public function tagCloud(?int $year): array; + /** + * @param Tag $tag + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function transferredInPeriod(Tag $tag, Carbon $start, Carbon $end): Collection; + /** * Update a tag. * diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php index 93e302af63..5d92acdbf9 100644 --- a/app/Support/Http/Controllers/PeriodOverview.php +++ b/app/Support/Http/Controllers/PeriodOverview.php @@ -60,12 +60,14 @@ trait PeriodOverview * and for each period, the amount of money spent and earned. This is a complex operation which is cached for * performance reasons. * - * @param Account $account the account involved - * @param Carbon $date + * The method has been refactored recently for better performance. + * + * @param Account $account The account involved + * @param Carbon $date The start date. * * @return Collection */ - protected function getAccountPeriodOverview(Account $account, Carbon $date): Collection // period overview + protected function getAccountPeriodOverview(Account $account, Carbon $date): Collection { /** @var AccountRepositoryInterface $repository */ $repository = app(AccountRepositoryInterface::class); @@ -95,15 +97,15 @@ trait PeriodOverview $collector = app(TransactionCollectorInterface::class); $collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::DEPOSIT]) ->withOpposingAccount(); - $set = $collector->getTransactions(); - $earned = $this->groupByCurrency($set); + $earnedSet = $collector->getTransactions(); + $earned = $this->groupByCurrency($earnedSet); /** @var TransactionCollectorInterface $collector */ $collector = app(TransactionCollectorInterface::class); $collector->setAccounts(new Collection([$account]))->setRange($currentDate['start'], $currentDate['end'])->setTypes([TransactionType::WITHDRAWAL]) ->withOpposingAccount(); - $set = $collector->getTransactions(); - $spent = $this->groupByCurrency($set); + $spentSet = $collector->getTransactions(); + $spent = $this->groupByCurrency($spentSet); $title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); /** @noinspection PhpUndefinedMethodInspection */ @@ -115,7 +117,6 @@ trait PeriodOverview 'earned' => $earned, 'transferred' => '0', 'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - ] ); } @@ -126,11 +127,84 @@ trait PeriodOverview } /** - * Gets period overview used for budgets. + * Overview for single category. Has been refactored recently. + * + * @param Category $category + * @param Carbon $date * * @return Collection */ - protected function getBudgetPeriodOverview(Carbon $date): Collection + protected function getCategoryPeriodOverview(Category $category, Carbon $date): Collection + { + /** @var JournalRepositoryInterface $journalRepository */ + $journalRepository = app(JournalRepositoryInterface::class); + $range = app('preferences')->get('viewRange', '1M')->data; + $first = $journalRepository->firstNull(); + $end = null === $first ? new Carbon : $first->date; + $start = clone $date; + + if ($end < $start) { + [$start, $end] = [$end, $start]; // @codeCoverageIgnore + } + + // properties for entries with their amounts. + $cache = new CacheProperties(); + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty($range); + $cache->addProperty('category-show-period-entries'); + $cache->addProperty($category->id); + + if ($cache->has()) { + return $cache->get(); // @codeCoverageIgnore + } + /** @var array $dates */ + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = new Collection; + /** @var CategoryRepositoryInterface $categoryRepository */ + $categoryRepository = app(CategoryRepositoryInterface::class); + + foreach ($dates as $currentDate) { + $spent = $categoryRepository->spentInPeriodCollection(new Collection([$category]), new Collection, $currentDate['start'], $currentDate['end']); + $earned = $categoryRepository->earnedInPeriodCollection(new Collection([$category]), new Collection, $currentDate['start'], $currentDate['end']); + $spent = $this->groupByCurrency($spent); + $earned = $this->groupByCurrency($earned); + + // amount transferred + /** @var TransactionCollectorInterface $collector */ + $collector = app(TransactionCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->setCategory($category) + ->withOpposingAccount()->setTypes([TransactionType::TRANSFER]); + $collector->removeFilter(InternalTransferFilter::class); + $transferred = $this->groupByCurrency($collector->getTransactions()); + + $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); + $entries->push( + [ + 'transactions' => 0, + 'title' => $title, + 'spent' => $spent, + 'earned' => $earned, + 'transferred' => $transferred, + 'route' => route('categories.show', [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + ] + ); + } + $cache->store($entries); + + return $entries; + } + + /** + * Same as above, but for lists that involve transactions without a budget. + * + * This method has been refactored recently. + * + * @param Carbon $date + * + * @return Collection + */ + protected function getNoBudgetPeriodOverview(Carbon $date): Collection { /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); @@ -138,8 +212,12 @@ trait PeriodOverview $end = null === $first ? new Carbon : $first->date; $start = clone $date; $range = app('preferences')->get('viewRange', '1M')->data; - $entries = new Collection; - $cache = new CacheProperties; + + if ($end < $start) { + [$start, $end] = [$end, $start]; // @codeCoverageIgnore + } + + $cache = new CacheProperties; $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('no-budget-period-entries'); @@ -149,7 +227,8 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = new Collection; foreach ($dates as $currentDate) { /** @var TransactionCollectorInterface $collector */ $collector = app(TransactionCollectorInterface::class); @@ -162,12 +241,12 @@ trait PeriodOverview $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $entries->push( [ - 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), 'transactions' => $count, 'title' => $title, 'spent' => $spent, 'earned' => '0', 'transferred' => '0', + 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), ] ); } @@ -177,133 +256,70 @@ trait PeriodOverview } /** - * Get a period overview for category. - * - * TODO refactor me. - * - * @param Category $category - * @param Carbon $date - * - * @return Collection - */ - protected function getCategoryPeriodOverview(Category $category, Carbon $date): Collection // periodOverview method - { - /** @var JournalRepositoryInterface $journalRepository */ - $journalRepository = app(JournalRepositoryInterface::class); - /** @var CategoryRepositoryInterface $categoryRepository */ - $categoryRepository = app(CategoryRepositoryInterface::class); - - - $range = app('preferences')->get('viewRange', '1M')->data; - $first = $journalRepository->firstNull(); - $end = null === $first ? new Carbon : $first->date; - $start = clone $date; - - // properties for entries with their amounts. - $cache = new CacheProperties(); - $cache->addProperty($start); - $cache->addProperty($end); - $cache->addProperty($range); - $cache->addProperty('categories.entries'); - $cache->addProperty($category->id); - - if ($cache->has()) { - //return $cache->get(); // @codeCoverageIgnore - } - /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = new Collection; - - foreach ($dates as $currentDate) { - $spent = $categoryRepository->spentInPeriodCollection(new Collection([$category]), new Collection, $currentDate['start'], $currentDate['end']); - $earned = $categoryRepository->earnedInPeriodCollection(new Collection([$category]), new Collection, $currentDate['start'], $currentDate['end']); - $spent = $this->groupByCurrency($spent); - $earned = $this->groupByCurrency($earned); - // amount transferred - /** @var TransactionCollectorInterface $collector */ - $collector = app(TransactionCollectorInterface::class); - $collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->setCategory($category) - ->withOpposingAccount()->setTypes([TransactionType::TRANSFER]); - $collector->removeFilter(InternalTransferFilter::class); - $transferred = $this->groupByCurrency($collector->getTransactions()); - $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries->push( - [ - 'route' => route('categories.show', [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'title' => $title, - 'spent' => $spent, - 'earned' => $earned, - 'transferred' => $transferred, - ] - ); - } - $cache->store($entries); - - return $entries; - } - - /** - * Get overview of periods for tag. - * - * TODO refactor this. + * This shows a period overview for a tag. It goes back in time and lists all relevant transactions and sums. * * @param Tag $tag * * @return Collection */ - protected function getTagPeriodOverview(Tag $tag): Collection // period overview for tags. + protected function getTagPeriodOverview(Tag $tag, Carbon $date): Collection // period overview for tags. { /** @var TagRepositoryInterface $repository */ $repository = app(TagRepositoryInterface::class); - // get first and last tag date from tag: - $range = app('preferences')->get('viewRange', '1M')->data; + $range = app('preferences')->get('viewRange', '1M')->data; /** @var Carbon $end */ - $end = app('navigation')->endOfX($repository->lastUseDate($tag) ?? new Carbon, $range, null); - $start = $repository->firstUseDate($tag) ?? new Carbon; + $start = clone $date; + $end = $repository->firstUseDate($tag) ?? new Carbon; + if ($end < $start) { + [$start, $end] = [$end, $start]; // @codeCoverageIgnore + } + // properties for entries with their amounts. $cache = new CacheProperties; $cache->addProperty($start); $cache->addProperty($end); - $cache->addProperty('tag.entries'); + $cache->addProperty('tag-period-entries'); $cache->addProperty($tag->id); if ($cache->has()) { return $cache->get(); // @codeCoverageIgnore } - $collection = new Collection; - $currentEnd = clone $end; + /** @var array $dates */ + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = new Collection; // while end larger or equal to start - while ($currentEnd >= $start) { - $currentStart = app('navigation')->startOfPeriod($currentEnd, $range); + foreach ($dates as $currentDate) { - // get expenses and what-not in this period and this tag. - $arr = [ - 'string' => $end->format('Y-m-d'), - 'name' => app('navigation')->periodShow($currentEnd, $range), - 'start' => clone $currentStart, - 'end' => clone $currentEnd, - 'date' => clone $end, - 'spent' => $repository->spentInPeriod($tag, $currentStart, $currentEnd), - 'earned' => $repository->earnedInPeriod($tag, $currentStart, $currentEnd), - ]; - $collection->push($arr); + $spentSet = $repository->expenseInPeriod($tag, $currentDate['start'], $currentDate['end']); + $spent = $this->groupByCurrency($spentSet); + $earnedSet = $repository->incomeInPeriod($tag, $currentDate['start'], $currentDate['end']); + $earned = $this->groupByCurrency($earnedSet); + $transferredSet = $repository->transferredInPeriod($tag, $currentDate['start'], $currentDate['end']); + $transferred = $this->groupByCurrency($transferredSet); + $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); + + $entries->push( + [ + 'transactions' => $spentSet->count() + $earnedSet->count() + $transferredSet->count(), + 'title' => $title, + 'spent' => $spent, + 'earned' => $earned, + 'transferred' => $transferred, + 'route' => route('tags.show', [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + ] + ); - /** @var Carbon $currentEnd */ - $currentEnd = clone $currentStart; - $currentEnd->subDay(); } - $cache->store($collection); + $cache->store($entries); - return $collection; + return $entries; } /** - * Get period overview for index. - * - * TODO refactor me. + * This list shows the overview of a type of transaction, for the period blocks on the list of transactions. * * @param string $what * @param Carbon $date @@ -315,42 +331,60 @@ trait PeriodOverview /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); $range = app('preferences')->get('viewRange', '1M')->data; - $first = $repository->firstNull(); - $start = Carbon::now()->subYear(); + $endJournal = $repository->firstNull(); + $end = null === $endJournal ? new Carbon : $endJournal->date; + $start = clone $date; $types = config('firefly.transactionTypesByWhat.' . $what); - $entries = new Collection; - if (null !== $first) { - $start = $first->date; - } - if ($date < $start) { - [$start, $date] = [$date, $start]; // @codeCoverageIgnore + + + if ($end < $start) { + [$start, $end] = [$end, $start]; // @codeCoverageIgnore } + // properties for entries with their amounts. + $cache = new CacheProperties; + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty('transactions-period-entries'); + $cache->addProperty($what); + + /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $date, $range); + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = new Collection; foreach ($dates as $currentDate) { + + // get all expenses, income or transfers: /** @var TransactionCollectorInterface $collector */ $collector = app(TransactionCollectorInterface::class); $collector->setAllAssetAccounts()->setRange($currentDate['start'], $currentDate['end'])->withOpposingAccount()->setTypes($types); $collector->removeFilter(InternalTransferFilter::class); $transactions = $collector->getTransactions(); - - if ($transactions->count() > 0) { - $sums = $this->sumPerCurrency($transactions); - $dateName = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); - $sum = $transactions->sum('transaction_amount'); - /** @noinspection PhpUndefinedMethodInspection */ - $entries->push( - [ - 'name' => $dateName, - 'sums' => $sums, - 'sum' => $sum, - 'start' => $currentDate['start']->format('Y-m-d'), - 'end' => $currentDate['end']->format('Y-m-d'), - ] - ); + $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); + $grouped = $this->groupByCurrency($transactions); + $spent = []; + $earned = []; + $transferred = []; + if ('expenses' === $what || 'withdrawal' === $what) { + $spent = $grouped; } + if ('revenue' === $what || 'deposit' === $what) { + $earned = $grouped; + } + if ('transfer' === $what || 'transfers' === $what) { + $transferred = $grouped; + } + $entries->push( + [ + 'transactions' => $transactions->count(), + 'title' => $title, + 'spent' => $spent, + 'earned' => $earned, + 'transferred' => $transferred, + 'route' => route('transactions.index', [$what, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + ] + ); } return $entries; diff --git a/resources/views/list/periods.twig b/resources/views/list/periods.twig index 7e8f9cd72c..c718663582 100644 --- a/resources/views/list/periods.twig +++ b/resources/views/list/periods.twig @@ -41,4 +41,5 @@ + {% endfor %} \ No newline at end of file diff --git a/resources/views/tags/show.twig b/resources/views/tags/show.twig index 42f8b48b7f..1a8e1ca4b7 100644 --- a/resources/views/tags/show.twig +++ b/resources/views/tags/show.twig @@ -154,33 +154,7 @@ {% if periods.count > 0 %}
- {% for period in periods %} - {% if period.spent != 0 or period.earned != 0 %} -
- -
- - {% if period.spent != 0 %} - - - - - {% endif %} - {% if period.earned != 0 %} - - - - - {% endif %} -
{{ 'spent'|_ }}{{ period.spent|formatAmount }}
{{ 'earned'|_ }}{{ period.earned|formatAmount }}
-
-
- {% endif %} - - {% endfor %} + {% include 'list.periods' %}
{% endif %} diff --git a/resources/views/transactions/index.twig b/resources/views/transactions/index.twig index 5a55f2d527..310582b7fc 100644 --- a/resources/views/transactions/index.twig +++ b/resources/views/transactions/index.twig @@ -58,47 +58,7 @@ {# boxes with info #} {% if periods.count > 0 %}
- {% for period in periods %} - - {% if period.sum != 0 %} -
- -
- - - {% for sum in period.sums %} - - - - - {% endfor %} - -
- {% if what == 'withdrawal' %} - {{ 'spent'|_ }} - {% endif %} - {% if what == 'deposit' %} - {{ 'earned'|_ }} - {% endif %} - {% if what == 'transfers' or what == 'transfer' %} - {{ 'transferred'|_ }} - {% endif %} - - {% if what == 'transfers' or what == 'transfer' %} - - {{ formatAmountBySymbol(Steam.positive(sum.sum), sum.currency.symbol, sum.currency.dp, false) }} - - {% else %} - {{ formatAmountBySymbol(sum.sum, sum.currency.symbol, sum.currency.dp) }} - {% endif %} -
-
-
- {% endif %} - {% endfor %} + {% include 'list.periods' %}
{% endif %} From 209c42b316c26cf579d0cd8767b2d1ae533361b0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 09:46:15 +0200 Subject: [PATCH 27/94] Re-enable cache on various charts. --- app/Http/Controllers/Chart/AccountController.php | 4 ++-- app/Http/Controllers/Chart/BillController.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index ddbe34b07c..498d60fd75 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -375,7 +375,7 @@ class AccountController extends Controller $cache->addProperty($end); $cache->addProperty('chart.account.income-category'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } // grab all journals: @@ -531,7 +531,7 @@ class AccountController extends Controller $cache->addProperty($end); $cache->addProperty('chart.account.revenue-accounts'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } $start->subDay(); diff --git a/app/Http/Controllers/Chart/BillController.php b/app/Http/Controllers/Chart/BillController.php index 3472335bec..e0af3ad201 100644 --- a/app/Http/Controllers/Chart/BillController.php +++ b/app/Http/Controllers/Chart/BillController.php @@ -68,7 +68,7 @@ class BillController extends Controller $cache->addProperty($end); $cache->addProperty('chart.bill.frontpage'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } /** @var CurrencyRepositoryInterface $currencyRepository */ $currencyRepository = app(CurrencyRepositoryInterface::class); From 788765507741da499dbdef145310d17d6fd98058 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 09:46:32 +0200 Subject: [PATCH 28/94] Fix spelling error --- resources/lang/en_US/import.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 30a275c585..a8e7d5986d 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -202,8 +202,9 @@ return [ 'spectre_extra_key_units' => 'Units', 'spectre_extra_key_unit_price' => 'Unit price', 'spectre_extra_key_transactions_count' => 'Transaction count', + //job configuration for finTS - 'fints_connection_failed' => 'An error occurred while trying to connecting to your bank. Please mak sure that all the data you entered is correct. Original error message: :originalError', + 'fints_connection_failed' => 'An error occurred while trying to connecting to your bank. Please make sure that all the data you entered is correct. Original error message: :originalError', 'job_config_fints_url_help' => 'E.g. https://banking-dkb.s-fints-pt-dkb.de/fints30', 'job_config_fints_username_help' => 'For many banks this is your account number.', From d8addc3175d62a206f986af1ab1bc120d7b04b95 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 10:46:11 +0200 Subject: [PATCH 29/94] Tag controller tests. --- tests/Feature/Controllers/TagControllerTest.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/Feature/Controllers/TagControllerTest.php b/tests/Feature/Controllers/TagControllerTest.php index f9a0d3848a..7c96c76982 100644 --- a/tests/Feature/Controllers/TagControllerTest.php +++ b/tests/Feature/Controllers/TagControllerTest.php @@ -31,6 +31,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; use Log; use Mockery; use Tests\TestCase; @@ -173,12 +174,14 @@ class TagControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true); $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - $repository->shouldReceive('spentInPeriod')->andReturn('-1')->times(1); + $repository->shouldReceive('firstUseDate')->andReturn(new Carbon)->once(); - $repository->shouldReceive('lastUseDate')->andReturn(new Carbon)->once(); - $repository->shouldReceive('earnedInPeriod')->andReturn('1')->times(1); $repository->shouldReceive('sumsOfTag')->andReturn($amounts)->once(); + $repository->shouldReceive('expenseInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $repository->shouldReceive('incomeInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $repository->shouldReceive('transferredInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $collector->shouldReceive('removeFilter')->andReturnSelf()->once(); $collector->shouldReceive('setAllAssetAccounts')->andReturnSelf()->once(); $collector->shouldReceive('setLimit')->andReturnSelf()->once(); @@ -248,10 +251,12 @@ class TagControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true); $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - $repository->shouldReceive('spentInPeriod')->andReturn('-1')->times(1); $repository->shouldReceive('firstUseDate')->andReturn(new Carbon)->once(); - $repository->shouldReceive('lastUseDate')->andReturn(new Carbon)->once(); - $repository->shouldReceive('earnedInPeriod')->andReturn('1')->times(1); + + $repository->shouldReceive('expenseInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $repository->shouldReceive('incomeInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $repository->shouldReceive('transferredInPeriod')->andReturn(new Collection)->atLeast()->times(1); + $collector->shouldReceive('removeFilter')->andReturnSelf()->once(); $collector->shouldReceive('setAllAssetAccounts')->andReturnSelf()->once(); From 2ec310da18b538c35b3733394430a48f133c0713 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 15:55:44 +0200 Subject: [PATCH 30/94] Make sure user ID is an integer #1774 --- app/Import/Storage/ImportArrayStorage.php | 2 +- app/Models/ImportJob.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Import/Storage/ImportArrayStorage.php b/app/Import/Storage/ImportArrayStorage.php index 9568c31f32..9cc5ab6871 100644 --- a/app/Import/Storage/ImportArrayStorage.php +++ b/app/Import/Storage/ImportArrayStorage.php @@ -116,7 +116,7 @@ class ImportArrayStorage app('preferences')->mark(); // email about this: - event(new RequestedReportOnJournals($this->importJob->user_id, $collection)); + event(new RequestedReportOnJournals((int)$this->importJob->user_id, $collection)); return $collection; } diff --git a/app/Models/ImportJob.php b/app/Models/ImportJob.php index aebbf35b45..82de695919 100644 --- a/app/Models/ImportJob.php +++ b/app/Models/ImportJob.php @@ -56,6 +56,7 @@ class ImportJob extends Model */ protected $casts = [ + 'user_id' => 'int', 'created_at' => 'datetime', 'updated_at' => 'datetime', 'configuration' => 'array', From 8088c28235e38ab764b9f95452e210740f101e0e Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 7 Oct 2018 18:41:02 +0200 Subject: [PATCH 31/94] Solve a problem with inline displaying of file attachments. --- app/Http/Middleware/SecureHeaders.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Middleware/SecureHeaders.php b/app/Http/Middleware/SecureHeaders.php index 016e40c0a9..39168deabe 100644 --- a/app/Http/Middleware/SecureHeaders.php +++ b/app/Http/Middleware/SecureHeaders.php @@ -37,7 +37,6 @@ class SecureHeaders * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @param string|null $guard * * @return mixed */ @@ -51,6 +50,7 @@ class SecureHeaders } $csp = [ "default-src 'none'", + "object-src 'self'", sprintf("script-src 'self' 'unsafe-eval' 'unsafe-inline' %s", $google), "style-src 'self' 'unsafe-inline'", "base-uri 'self'", From 7f9b5e1e5e704a59d6871b5d6b3503e02ef1ee7f Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 8 Oct 2018 19:54:37 +0200 Subject: [PATCH 32/94] Small updates for Sandstorm release. --- .sandstorm/sandstorm-files.list | 123 ++++++++++++++++++++++++++++++++ composer.lock | 5 +- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/.sandstorm/sandstorm-files.list b/.sandstorm/sandstorm-files.list index 77c8159158..15c1aaac96 100644 --- a/.sandstorm/sandstorm-files.list +++ b/.sandstorm/sandstorm-files.list @@ -553,6 +553,8 @@ opt/app/app/Import/Converter/RabobankDebitCredit.php opt/app/app/Import/JobConfiguration/BunqJobConfiguration.php opt/app/app/Import/JobConfiguration/FakeJobConfiguration.php opt/app/app/Import/JobConfiguration/FileJobConfiguration.php +opt/app/app/Import/JobConfiguration/FinTSConfigurationSteps.php +opt/app/app/Import/JobConfiguration/FinTSJobConfiguration.php opt/app/app/Import/JobConfiguration/JobConfigurationInterface.php opt/app/app/Import/JobConfiguration/SpectreJobConfiguration.php opt/app/app/Import/JobConfiguration/YnabJobConfiguration.php @@ -578,6 +580,7 @@ opt/app/app/Import/Prerequisites/YnabPrerequisites.php opt/app/app/Import/Routine/BunqRoutine.php opt/app/app/Import/Routine/FakeRoutine.php opt/app/app/Import/Routine/FileRoutine.php +opt/app/app/Import/Routine/FinTSRoutine.php opt/app/app/Import/Routine/RoutineInterface.php opt/app/app/Import/Routine/SpectreRoutine.php opt/app/app/Import/Routine/YnabRoutine.php @@ -782,6 +785,7 @@ opt/app/app/Support/Facades/FireflyConfig.php opt/app/app/Support/Facades/Navigation.php opt/app/app/Support/Facades/Preferences.php opt/app/app/Support/Facades/Steam.php +opt/app/app/Support/FinTS/FinTS.php opt/app/app/Support/FireflyConfig.php opt/app/app/Support/Http/Controllers/AugumentData.php opt/app/app/Support/Http/Controllers/BasicDataSupport.php @@ -805,6 +809,9 @@ opt/app/app/Support/Import/JobConfiguration/File/ConfigureRolesHandler.php opt/app/app/Support/Import/JobConfiguration/File/ConfigureUploadHandler.php opt/app/app/Support/Import/JobConfiguration/File/FileConfigurationInterface.php opt/app/app/Support/Import/JobConfiguration/File/NewFileJobHandler.php +opt/app/app/Support/Import/JobConfiguration/FinTS/ChooseAccountHandler.php +opt/app/app/Support/Import/JobConfiguration/FinTS/FinTSConfigurationInterface.php +opt/app/app/Support/Import/JobConfiguration/FinTS/NewFinTSJobHandler.php opt/app/app/Support/Import/JobConfiguration/Spectre/AuthenticatedHandler.php opt/app/app/Support/Import/JobConfiguration/Spectre/ChooseAccountsHandler.php opt/app/app/Support/Import/JobConfiguration/Spectre/ChooseLoginHandler.php @@ -833,6 +840,7 @@ opt/app/app/Support/Import/Routine/File/MappedValuesValidator.php opt/app/app/Support/Import/Routine/File/MappingConverger.php opt/app/app/Support/Import/Routine/File/OFXProcessor.php opt/app/app/Support/Import/Routine/File/OpposingAccountMapper.php +opt/app/app/Support/Import/Routine/FinTS/StageImportDataHandler.php opt/app/app/Support/Import/Routine/Spectre/StageAuthenticatedHandler.php opt/app/app/Support/Import/Routine/Spectre/StageImportDataHandler.php opt/app/app/Support/Import/Routine/Spectre/StageNewHandler.php @@ -1201,6 +1209,7 @@ opt/app/public/images/logos/bunq.png opt/app/public/images/logos/csv.png opt/app/public/images/logos/fake.png opt/app/public/images/logos/file.png +opt/app/public/images/logos/fints.png opt/app/public/images/logos/plaid.png opt/app/public/images/logos/quovo.png opt/app/public/images/logos/spectre.png @@ -1718,6 +1727,8 @@ opt/app/resources/views/import/file/configure-upload.twig opt/app/resources/views/import/file/map.twig opt/app/resources/views/import/file/new.twig opt/app/resources/views/import/file/roles.twig +opt/app/resources/views/import/fints/choose_account.twig +opt/app/resources/views/import/fints/new.twig opt/app/resources/views/import/index.twig opt/app/resources/views/import/spectre/accounts.twig opt/app/resources/views/import/spectre/choose-login.twig @@ -3030,6 +3041,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Support/MessageBag.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Support/MessageProvider.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Support/Renderable.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Support/Responsable.php +opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Translation/HasLocalePreference.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Translation/Loader.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Translation/Translator.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Validation/Factory.php @@ -3099,6 +3111,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/QueueEntityRes opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/RelationNotFoundException.php opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php opt/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasMany.php @@ -3485,6 +3498,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php opt/app/vendor/laravel/framework/src/Illuminate/Pipeline/PipelineServiceProvider.php opt/app/vendor/laravel/framework/src/Illuminate/Pipeline/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Queue/BeanstalkdQueue.php +opt/app/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedClosure.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/Capsule/Manager.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/Connectors/BeanstalkdConnector.php @@ -3537,6 +3551,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Queue/QueueManager.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/QueueServiceProvider.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/README.md opt/app/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php +opt/app/vendor/laravel/framework/src/Illuminate/Queue/SerializableClosure.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/SerializesModels.php opt/app/vendor/laravel/framework/src/Illuminate/Queue/SqsQueue.php @@ -4373,6 +4388,94 @@ opt/app/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php opt/app/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php opt/app/vendor/monolog/monolog/tests/Monolog/RegistryTest.php opt/app/vendor/monolog/monolog/tests/Monolog/TestCase.php +opt/app/vendor/mschindler83/fints-hbci-php/COMPATIBILITY.md +opt/app/vendor/mschindler83/fints-hbci-php/LICENSE +opt/app/vendor/mschindler83/fints-hbci-php/README.md +opt/app/vendor/mschindler83/fints-hbci-php/Samples/saldo.php +opt/app/vendor/mschindler83/fints-hbci-php/Samples/statement_of_account.php +opt/app/vendor/mschindler83/fints-hbci-php/composer.json +opt/app/vendor/mschindler83/fints-hbci-php/composer.lock +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Adapter/AdapterInterface.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Adapter/Curl.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Adapter/Debug.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Adapter/Exception/AdapterException.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Adapter/Exception/CurlException.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Connection.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/EncryptionAlgorithm.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/HashAlgorithm.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/KeyName.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/SecurityDateTime.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/SecurityIdentificationDetails.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/SecurityProfile.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataElementGroups/SignatureAlgorithm.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataTypes/Bin.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataTypes/Dat.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataTypes/Kik.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataTypes/Kti.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/DataTypes/Ktv.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Deg.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Dialog/Dialog.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Dialog/Exception/FailedRequestException.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/FinTs.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Message/AbstractMessage.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Message/Message.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/Account.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/SEPAAccount.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/Saldo.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/StatementOfAccount/Statement.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/StatementOfAccount/StatementOfAccount.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Model/StatementOfAccount/Transaction.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Parser/Exception/MT940Exception.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Parser/MT940.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/GetAccounts.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/GetSEPAAccounts.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/GetSaldo.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/GetStatementOfAccount.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/Initialization.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Response/Response.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/AbstractSegment.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKEND.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKIDN.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKKAZ.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKSAL.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKSPA.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKSYN.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HKVVB.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNHBK.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNHBS.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNSHA.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNSHK.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNVSD.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/HNVSK.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/NameMapping.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/Segment.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Fhp/Segment/SegmentInterface.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/ConnectionTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/EncryptionAlgorithmTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/HashAlgorithmTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/KeyNameTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/SecurityDateTimeTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/SecurityIdentificationDetailsTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/SecurityProfileTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataElementGroups/SignatureAlgorithmTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataTypes/BinTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataTypes/DatTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataTypes/KikTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataTypes/KtiTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DataTypes/KtvTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/DegTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/FinTsTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Message/MessageTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/AccountTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/SEPAAccountTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/SaldoTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/StatementOfAccount/StatementOfAccountTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/StatementOfAccount/StatementTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/Model/StatementOfAccount/TransactionTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/Fhp/ResponseTest/ResponseTest.php +opt/app/vendor/mschindler83/fints-hbci-php/lib/Tests/TestInit.php +opt/app/vendor/mschindler83/fints-hbci-php/phplint.sh +opt/app/vendor/mschindler83/fints-hbci-php/phpunit.xml.dist opt/app/vendor/nesbot/carbon/LICENSE opt/app/vendor/nesbot/carbon/composer.json opt/app/vendor/nesbot/carbon/readme.md @@ -4456,6 +4559,23 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh_TW.php opt/app/vendor/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php opt/app/vendor/nesbot/carbon/src/Carbon/Translator.php opt/app/vendor/nesbot/carbon/src/JsonSerializable.php +opt/app/vendor/opis/closure/CHANGELOG.md +opt/app/vendor/opis/closure/LICENSE +opt/app/vendor/opis/closure/NOTICE +opt/app/vendor/opis/closure/README.md +opt/app/vendor/opis/closure/autoload.php +opt/app/vendor/opis/closure/composer.json +opt/app/vendor/opis/closure/functions.php +opt/app/vendor/opis/closure/src/Analyzer.php +opt/app/vendor/opis/closure/src/ClosureContext.php +opt/app/vendor/opis/closure/src/ClosureScope.php +opt/app/vendor/opis/closure/src/ClosureStream.php +opt/app/vendor/opis/closure/src/ISecurityProvider.php +opt/app/vendor/opis/closure/src/ReflectionClosure.php +opt/app/vendor/opis/closure/src/SecurityException.php +opt/app/vendor/opis/closure/src/SecurityProvider.php +opt/app/vendor/opis/closure/src/SelfReference.php +opt/app/vendor/opis/closure/src/SerializableClosure.php opt/app/vendor/paragonie/constant_time_encoding/LICENSE.txt opt/app/vendor/paragonie/constant_time_encoding/README.md opt/app/vendor/paragonie/constant_time_encoding/composer.json @@ -5458,6 +5578,7 @@ opt/app/vendor/symfony/debug/Tests/Fixtures/DeprecatedInterface.php opt/app/vendor/symfony/debug/Tests/Fixtures/ExtendedFinalMethod.php opt/app/vendor/symfony/debug/Tests/Fixtures/FinalClass.php opt/app/vendor/symfony/debug/Tests/Fixtures/FinalMethod.php +opt/app/vendor/symfony/debug/Tests/Fixtures/FinalMethod2Trait.php opt/app/vendor/symfony/debug/Tests/Fixtures/InternalClass.php opt/app/vendor/symfony/debug/Tests/Fixtures/InternalInterface.php opt/app/vendor/symfony/debug/Tests/Fixtures/InternalTrait.php @@ -5466,6 +5587,7 @@ opt/app/vendor/symfony/debug/Tests/Fixtures/NonDeprecatedInterface.php opt/app/vendor/symfony/debug/Tests/Fixtures/PEARClass.php opt/app/vendor/symfony/debug/Tests/Fixtures/Throwing.php opt/app/vendor/symfony/debug/Tests/Fixtures/ToStringThrower.php +opt/app/vendor/symfony/debug/Tests/Fixtures/TraitWithInternalMethod.php opt/app/vendor/symfony/debug/Tests/Fixtures/casemismatch.php opt/app/vendor/symfony/debug/Tests/Fixtures/notPsr0Bis.php opt/app/vendor/symfony/debug/Tests/Fixtures/psr4/Psr4CaseMismatch.php @@ -6539,6 +6661,7 @@ opt/app/vendor/symfony/var-dumper/Tests/Caster/XmlReaderCasterTest.php opt/app/vendor/symfony/var-dumper/Tests/Cloner/DataTest.php opt/app/vendor/symfony/var-dumper/Tests/Cloner/VarClonerTest.php opt/app/vendor/symfony/var-dumper/Tests/Dumper/CliDumperTest.php +opt/app/vendor/symfony/var-dumper/Tests/Dumper/FunctionsTest.php opt/app/vendor/symfony/var-dumper/Tests/Dumper/HtmlDumperTest.php opt/app/vendor/symfony/var-dumper/Tests/Dumper/ServerDumperTest.php opt/app/vendor/symfony/var-dumper/Tests/Fixtures/FooInterface.php diff --git a/composer.lock b/composer.lock index 0a1196cefc..8912d13e11 100644 --- a/composer.lock +++ b/composer.lock @@ -5678,6 +5678,7 @@ "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", + "robrichards/xmlseclibs": ">=1,<3.0.2", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", @@ -5718,7 +5719,7 @@ "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", @@ -5774,7 +5775,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-10-02T16:19:22+00:00" + "time": "2018-10-05T18:14:02+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", From 429bec66f2a2c18d2453ab393b2a4066be32b424 Mon Sep 17 00:00:00 2001 From: Luca Bognolo Date: Tue, 9 Oct 2018 17:38:23 +0200 Subject: [PATCH 33/94] Fixed locales lang error on Heroku build platform Starting from heroku 16 stack the language packs are not included by default: https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-locale Signed-off-by: Luca Bognolo --- .locales | 9 +++++++++ app.json | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 .locales diff --git a/.locales b/.locales new file mode 100644 index 0000000000..c7badfc286 --- /dev/null +++ b/.locales @@ -0,0 +1,9 @@ +en_US +de_DE +fr_FR +it_IT +nl_NL +pl_PL +pt_BR +ru_RU +tr_TR diff --git a/app.json b/app.json index 82677845eb..366ce7bf04 100644 --- a/app.json +++ b/app.json @@ -51,6 +51,9 @@ "buildpacks": [ { "url": "heroku/php" + }, + { + "url": "https://github.com/heroku/heroku-buildpack-locale" } ], "env": { From 9f768396c2c994b23d82f02c99a074b16d5894d0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 10 Oct 2018 06:09:25 +0200 Subject: [PATCH 34/94] Code for #1698 --- .deploy/docker/cacert.pem | 3314 +++++++++++++++++++++++++++++++++++++ Dockerfile | 3 + 2 files changed, 3317 insertions(+) create mode 100644 .deploy/docker/cacert.pem diff --git a/.deploy/docker/cacert.pem b/.deploy/docker/cacert.pem new file mode 100644 index 0000000000..ee25bee119 --- /dev/null +++ b/.deploy/docker/cacert.pem @@ -0,0 +1,3314 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Wed Jun 20 03:12:06 2018 GMT +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.27. +## SHA256: c80f571d9f4ebca4a91e0ad3a546f263153d71afffc845c6f8f52ce9d1a2e8ec +## + + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +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 +66+KAQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +=============================== +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w +DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls +ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw +NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx +QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl +cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD +DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd +hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K +CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g +ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ +BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 +E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz +rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq +jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 +dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG +MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK +kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO +XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 +VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo +a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc +dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV +KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT +Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 +8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G +C7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +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 +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +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 +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl +OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV +MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF +JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G3 +================================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y +olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t +x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy +EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K +Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur +mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 +1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp +07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo +FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE +41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu +yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq +KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 +v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA +8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b +8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r +mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq +1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI +JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV +tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +================================ +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M +MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl +cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk +SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW +O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r +0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 +Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV +XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr +08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV +0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd +74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx +fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa +ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu +c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq +5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN +b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN +f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi +5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 +WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK +DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy +eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +Certinomis - Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg +LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx +EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD +ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos +P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo +d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap +z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00 +8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x +RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE +6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t +FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV +PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH +i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj +YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I +6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV +WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw +Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX +lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ +y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9 +Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng +DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi +I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM +cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr +hkIGuUE= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +Certplus Root CA G1 +=================== +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV +BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe +Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD +ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN +r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx +Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj +BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv +LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2 +z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc +4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd +4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj +jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+ +ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G +A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY +lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh +66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG +YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/ +2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F +6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX +CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe +tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC +VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/ ++mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+ +qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= +-----END CERTIFICATE----- + +Certplus Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT +AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x +NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0 +cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN +Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud +IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV +HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl +vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw== +-----END CERTIFICATE----- + +OpenTrust Root CA G1 +==================== +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx +MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM +CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa +Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87 +ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO +YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9 +xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO +9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq +3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi +n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9 +URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr +TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px +N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E +PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv +uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK +n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh +X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80 +nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm +GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/ +bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o +4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA +OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx +-----END CERTIFICATE----- + +OpenTrust Root CA G2 +==================== +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy +MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM +CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+ +Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz +4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV +eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt +UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz +3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj +3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz +9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0 +0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT +y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59 +M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz +Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI +mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG +S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp +EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ +6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr +gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo +SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0 +YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm +u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK +-----END CERTIFICATE----- + +OpenTrust Root CA G3 +==================== +-----BEGIN CERTIFICATE----- +MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X +DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w +ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B +ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf +BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM +BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta +3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +LuxTrust Global Root 2 +====================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +TrustCor RootCert CA-1 +====================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx +MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu +YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe +VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy +dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq +jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 +pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 +JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h +gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw +/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j +BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 +mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C +qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P +3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +TrustCor RootCert CA-2 +====================== +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +TrustCor ECA-1 +============== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP +MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig +U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw +N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 +MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y +IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR +MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 +xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc +p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ +fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj +YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL +f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF +AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u +/ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs +J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC +jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- diff --git a/Dockerfile b/Dockerfile index 4b62a179e0..27d2734c21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,6 +66,9 @@ COPY ./.deploy/docker/firefly-iii.conf /etc/supervisor/conf.d/firefly-iii.conf # copy cron job supervisor conf file. COPY ./.deploy/docker/cronjob.conf /etc/supervisor/conf.d/cronjob.conf +# copy ca certs to correct location +COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem + # test crons added via crontab RUN echo "0 3 * * * /usr/local/bin/php /var/www/firefly-iii/artisan firefly:cron" | crontab - #RUN (crontab -l ; echo "*/1 * * * * free >> /var/www/firefly-iii/public/cron.html") 2>&1 | crontab - From 940323c0b72c9a77f32b77adac1e7eab91a0f090 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 12 Oct 2018 07:39:05 +0200 Subject: [PATCH 35/94] Small fix in auto complete controller. --- app/Http/Controllers/Json/AutoCompleteController.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index 2aaeb29c03..975395635a 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -99,6 +99,7 @@ class AutoCompleteController extends Controller $search = (string)$request->get('search'); $unfiltered = null; $filtered = null; + $cache = new CacheProperties; $cache->addProperty($subject); // very unlikely a user will actually search for this string. @@ -156,7 +157,9 @@ class AutoCompleteController extends Controller if ('transaction_types' === $subject) { $unfiltered = $this->getTransactionTypes(); } - + if ('transaction-types' === $subject) { + $unfiltered = $this->getTransactionTypes(); + } // filter results $filtered = $this->filterResult($unfiltered, $search); From cf11dfe73b5eb267c05fcfb75f6eb1a2c24ec820 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 12 Oct 2018 07:57:26 +0200 Subject: [PATCH 36/94] Remove cache for #1778 --- app/Http/Controllers/Json/AutoCompleteController.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index 975395635a..dbd993aedd 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -100,14 +100,6 @@ class AutoCompleteController extends Controller $unfiltered = null; $filtered = null; - $cache = new CacheProperties; - $cache->addProperty($subject); - // very unlikely a user will actually search for this string. - $key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search; - $cache->addProperty($key); - if ($cache->has()) { - return response()->json($cache->get()); // @codeCoverageIgnore - } // search for all accounts. if ('all-accounts' === $subject) { $unfiltered = $this->getAccounts( @@ -167,7 +159,6 @@ class AutoCompleteController extends Controller if (null === $filtered) { throw new FireflyException(sprintf('Auto complete handler cannot handle "%s"', $subject)); // @codeCoverageIgnore } - $cache->store($filtered); return response()->json($filtered); } From f696353e2c74edcecf230361190527af71a5f1ad Mon Sep 17 00:00:00 2001 From: HamuZ HamuZ <550499+hamuz@users.noreply.github.com> Date: Sat, 13 Oct 2018 09:56:26 +0300 Subject: [PATCH 37/94] fix local references in upload/export disk. first step for #1727. --- app/Console/Commands/CreateExport.php | 12 ++++++--- app/Console/Commands/EncryptFile.php | 2 +- app/Export/ExpandedProcessor.php | 8 +++--- app/Export/Exporter/CsvExporter.php | 25 +++++-------------- app/Helpers/Attachments/AttachmentHelper.php | 7 +++--- .../Attachment/AttachmentRepository.php | 6 ++--- .../ExportJob/ExportJobRepository.php | 12 +++++---- app/Services/Internal/File/EncryptService.php | 6 ++--- .../Attachments/AttachmentHelperTest.php | 2 +- 9 files changed, 36 insertions(+), 44 deletions(-) diff --git a/app/Console/Commands/CreateExport.php b/app/Console/Commands/CreateExport.php index 73b4d3384f..4c66cceb91 100644 --- a/app/Console/Commands/CreateExport.php +++ b/app/Console/Commands/CreateExport.php @@ -33,7 +33,7 @@ use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Illuminate\Console\Command; -use Storage; +use Illuminate\Support\Facades\Storage; /** * Class CreateExport. @@ -136,10 +136,14 @@ class CreateExport extends Command $processor->createZipFile(); $disk = Storage::disk('export'); $fileName = sprintf('export-%s.zip', date('Y-m-d_H-i-s')); - $disk->move($job->key . '.zip', $fileName); + $localPath = storage_path('export') . '/' . $job->key . '.zip'; - $this->line('The export has finished! You can find the ZIP file in this location:'); - $this->line(storage_path(sprintf('export/%s', $fileName))); + // "move" from local to export disk + $disk->put($fileName, file_get_contents($localPath)); + unlink($localPath); + + $this->line('The export has finished! You can find the ZIP file in export disk with file name:'); + $this->line($fileName); return 0; } diff --git a/app/Console/Commands/EncryptFile.php b/app/Console/Commands/EncryptFile.php index 08d9683afa..6c0e6d4272 100644 --- a/app/Console/Commands/EncryptFile.php +++ b/app/Console/Commands/EncryptFile.php @@ -39,7 +39,7 @@ class EncryptFile extends Command * * @var string */ - protected $description = 'Encrypts a file and places it in the storage/upload directory.'; + protected $description = 'Encrypts a file and places it in the upload disk.'; /** * The name and signature of the console command. diff --git a/app/Export/ExpandedProcessor.php b/app/Export/ExpandedProcessor.php index 4adb9499cf..ba5feceb21 100644 --- a/app/Export/ExpandedProcessor.php +++ b/app/Export/ExpandedProcessor.php @@ -42,7 +42,7 @@ use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Illuminate\Support\Collection; use Log; -use Storage; +use Illuminate\Support\Facades\Storage; use ZipArchive; /** @@ -184,7 +184,7 @@ class ExpandedProcessor implements ProcessorInterface } /** - * Create a ZIP file. + * Create a ZIP file locally (!) in storage_path('export'). * * @return bool * @@ -195,9 +195,9 @@ class ExpandedProcessor implements ProcessorInterface { $zip = new ZipArchive; $file = $this->job->key . '.zip'; - $fullPath = storage_path('export') . '/' . $file; + $localPath = storage_path('export') . '/' . $file; - if (true !== $zip->open($fullPath, ZipArchive::CREATE)) { + if (true !== $zip->open($localPath, ZipArchive::CREATE)) { throw new FireflyException('Cannot store zip file.'); } // for each file in the collection, add it to the zip file. diff --git a/app/Export/Exporter/CsvExporter.php b/app/Export/Exporter/CsvExporter.php index 6e4a7b96d1..f7d57c26b8 100644 --- a/app/Export/Exporter/CsvExporter.php +++ b/app/Export/Exporter/CsvExporter.php @@ -26,7 +26,7 @@ namespace FireflyIII\Export\Exporter; use FireflyIII\Export\Entry\Entry; use League\Csv\Writer; -use Storage; +use Illuminate\Support\Facades\Storage; /** * Class CsvExporter. @@ -57,15 +57,11 @@ class CsvExporter extends BasicExporter implements ExporterInterface */ public function run(): bool { - // create temporary file: - $this->tempFile(); - - // necessary for CSV writer: - $fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName; - + // choose file name: + $this->fileName = $this->job->key . '-records.csv'; //we create the CSV into memory - $writer = Writer::createFromPath($fullPath); + $writer = Writer::createFromString(''); $rows = []; // get field names for header row: @@ -86,18 +82,9 @@ class CsvExporter extends BasicExporter implements ExporterInterface $rows[] = $line; } $writer->insertAll($rows); + $disk = Storage::disk('export'); + $disk->put($this->fileName, $writer->getContent()); return true; } - - /** - * Make a temp file. - */ - private function tempFile() - { - $this->fileName = $this->job->key . '-records.csv'; - // touch file in export directory: - $disk = Storage::disk('export'); - $disk->put($this->fileName, ''); - } } diff --git a/app/Helpers/Attachments/AttachmentHelper.php b/app/Helpers/Attachments/AttachmentHelper.php index 09f22838f1..34a15813a5 100644 --- a/app/Helpers/Attachments/AttachmentHelper.php +++ b/app/Helpers/Attachments/AttachmentHelper.php @@ -30,7 +30,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; use Log; -use Storage; +use Illuminate\Support\Facades\Storage; use Symfony\Component\HttpFoundation\File\UploadedFile; /** @@ -94,7 +94,7 @@ class AttachmentHelper implements AttachmentHelperInterface } /** - * Returns the file location for an attachment, + * Returns the file path relative to upload disk for an attachment, * * @param Attachment $attachment * @@ -102,8 +102,7 @@ class AttachmentHelper implements AttachmentHelperInterface */ public function getAttachmentLocation(Attachment $attachment): string { - $path = sprintf('%s%sat-%d.data', storage_path('upload'), DIRECTORY_SEPARATOR, (int)$attachment->id); - + $path = sprintf('%sat-%d.data', DIRECTORY_SEPARATOR, (int)$attachment->id); return $path; } diff --git a/app/Repositories/Attachment/AttachmentRepository.php b/app/Repositories/Attachment/AttachmentRepository.php index 501c846a0c..c3b9987639 100644 --- a/app/Repositories/Attachment/AttachmentRepository.php +++ b/app/Repositories/Attachment/AttachmentRepository.php @@ -34,7 +34,7 @@ use FireflyIII\User; use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Collection; use Log; -use Storage; +use Illuminate\Support\Facades\Storage; /** * Class AttachmentRepository. @@ -66,9 +66,9 @@ class AttachmentRepository implements AttachmentRepositoryInterface /** @var AttachmentHelperInterface $helper */ $helper = app(AttachmentHelperInterface::class); - $file = $helper->getAttachmentLocation($attachment); + $path = $helper->getAttachmentLocation($attachment); try { - unlink($file); + Storage::disk('upload')->delete($path); } catch (Exception $e) { Log::error(sprintf('Could not delete file for attachment %d: %s', $attachment->id, $e->getMessage())); } diff --git a/app/Repositories/ExportJob/ExportJobRepository.php b/app/Repositories/ExportJob/ExportJobRepository.php index 9ffd1b11b7..735e4e45f5 100644 --- a/app/Repositories/ExportJob/ExportJobRepository.php +++ b/app/Repositories/ExportJob/ExportJobRepository.php @@ -28,8 +28,8 @@ use FireflyIII\Models\ExportJob; use FireflyIII\User; use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Storage; use Log; -use Storage; /** * Class ExportJobRepository. @@ -74,15 +74,17 @@ class ExportJobRepository implements ExportJobRepositoryInterface ->whereIn('status', ['never_started', 'export_status_finished', 'export_downloaded']) ->get(); + $disk = Storage::disk('export'); + $files = $disk->files(); + // loop set: /** @var ExportJob $entry */ foreach ($set as $entry) { $key = $entry->key; - $files = scandir(storage_path('export'), SCANDIR_SORT_NONE); - /** @var string $file */ + /** @var array $file */ foreach ($files as $file) { - if (0 === strpos($file, $key)) { - unlink(storage_path('export') . DIRECTORY_SEPARATOR . $file); + if (0 === strpos($file['basename'], $key)) { + $disk->delete($file['path']); } } try { diff --git a/app/Services/Internal/File/EncryptService.php b/app/Services/Internal/File/EncryptService.php index 5380efcd83..50558c8586 100644 --- a/app/Services/Internal/File/EncryptService.php +++ b/app/Services/Internal/File/EncryptService.php @@ -26,6 +26,7 @@ namespace FireflyIII\Services\Internal\File; use Crypt; use FireflyIII\Exceptions\FireflyException; use Illuminate\Contracts\Encryption\EncryptException; +use Illuminate\Support\Facades\Storage; use Log; /** @@ -63,9 +64,8 @@ class EncryptService throw new FireflyException($message); } $newName = sprintf('%s.upload', $key); - $path = storage_path('upload') . '/' . $newName; - - file_put_contents($path, $content); + $disk = Storage::disk('upload'); + $disk->put($newName, $content); } } diff --git a/tests/Unit/Helpers/Attachments/AttachmentHelperTest.php b/tests/Unit/Helpers/Attachments/AttachmentHelperTest.php index 50483d0065..f6e3d86e47 100644 --- a/tests/Unit/Helpers/Attachments/AttachmentHelperTest.php +++ b/tests/Unit/Helpers/Attachments/AttachmentHelperTest.php @@ -56,7 +56,7 @@ class AttachmentHelperTest extends TestCase { $attachment = Attachment::first(); $helper = new AttachmentHelper; - $path = $path = sprintf('%s%sat-%d.data', storage_path('upload'), DIRECTORY_SEPARATOR, (int)$attachment->id); + $path = $path = sprintf('%sat-%d.data', DIRECTORY_SEPARATOR, (int)$attachment->id); $this->assertEquals($helper->getAttachmentLocation($attachment), $path); } From a5a012738e7dae6447f953306309e795a446a8e9 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 13:19:41 +0200 Subject: [PATCH 38/94] Code for #1733 --- .env.docker | 3 +++ .env.example | 3 +++ .env.heroku | 2 ++ .env.sandstorm | 2 ++ .env.testing | 2 ++ app/Handlers/Events/AutomationHandler.php | 6 ++++++ 6 files changed, 18 insertions(+) diff --git a/.env.docker b/.env.docker index 381c961798..e492ce875e 100644 --- a/.env.docker +++ b/.env.docker @@ -74,6 +74,9 @@ SPARKPOST_SECRET=${SPARKPOST_SECRET} SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=false +# These messages contain (sensitive) transaction information: +SEND_REPORT_JOURNALS=${SEND_REPORT_JOURNALS} + # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY=${MAPBOX_API_KEY} diff --git a/.env.example b/.env.example index b8c33e380e..e53df1a9ca 100644 --- a/.env.example +++ b/.env.example @@ -74,6 +74,9 @@ SPARKPOST_SECRET= SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=true +# These messages contain (sensitive) transaction information: +SEND_REPORT_JOURNALS=true + # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= diff --git a/.env.heroku b/.env.heroku index c16376ea76..c4db28823b 100644 --- a/.env.heroku +++ b/.env.heroku @@ -73,6 +73,8 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=true +# These messages contain (sensitive) transaction information: +SEND_REPORT_JOURNALS=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= diff --git a/.env.sandstorm b/.env.sandstorm index ce73089fe8..aa7b70b1ff 100755 --- a/.env.sandstorm +++ b/.env.sandstorm @@ -73,6 +73,8 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=true +# These messages contain (sensitive) transaction information: +SEND_REPORT_JOURNALS=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= diff --git a/.env.testing b/.env.testing index 224ed8711a..67757f6e23 100644 --- a/.env.testing +++ b/.env.testing @@ -73,6 +73,8 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=false +# These messages contain (sensitive) transaction information: +SEND_REPORT_JOURNALS=true # Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places. MAPBOX_API_KEY= diff --git a/app/Handlers/Events/AutomationHandler.php b/app/Handlers/Events/AutomationHandler.php index 2b1464010c..75d04fbc2d 100644 --- a/app/Handlers/Events/AutomationHandler.php +++ b/app/Handlers/Events/AutomationHandler.php @@ -45,6 +45,12 @@ class AutomationHandler */ public function reportJournals(RequestedReportOnJournals $event): bool { + $sendReport = envNonEmpty('SEND_REPORT_JOURNALS', true); + + if (false === $sendReport) { + return true; + } + Log::debug('In reportJournals.'); /** @var UserRepositoryInterface $repository */ $repository = app(UserRepositoryInterface::class); From 0d36d43edac9b66bdded00701df9e1289dab88aa Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 15:06:56 +0200 Subject: [PATCH 39/94] Initial code for LDAP authentication. --- .env.example | 43 +++ .../Auth/ForgotPasswordController.php | 14 + app/Http/Controllers/Auth/LoginController.php | 14 +- .../Controllers/Auth/RegisterController.php | 40 ++- .../Auth/ResetPasswordController.php | 49 ++- app/Http/Controllers/ProfileController.php | 52 ++- bootstrap/app.php | 2 +- composer.json | 3 + composer.lock | 127 ++++++- config/adldap.php | 259 ++++++++++++++ config/adldap_auth.php | 317 ++++++++++++++++++ config/auth.php | 8 +- config/firefly.php | 1 + resources/lang/en_US/firefly.php | 2 + resources/lang/en_US/form.php | 1 + resources/views/auth/login.twig | 10 +- 16 files changed, 905 insertions(+), 37 deletions(-) create mode 100644 config/adldap.php create mode 100644 config/adldap_auth.php diff --git a/.env.example b/.env.example index e53df1a9ca..3a450e42b8 100644 --- a/.env.example +++ b/.env.example @@ -92,9 +92,52 @@ ANALYTICS_ID= # This makes it easier to migrate your database. Not that some fields will never be decrypted. USE_ENCRYPTION=true +# Firefly III has two options for user authentication. "eloquent" is the default, +# and "adldap" for LDAP servers. +# For full instructions on these settings please visit: +# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html +LOGIN_PROVIDER=eloquent + +# LDAP connection configuration +ADLDAP_CONNECTION_SCHEME=OpenLDAP # or FreeIPA or ActiveDirectory +ADLDAP_AUTO_CONNECT=true + +# LDAP connection settings +ADLDAP_CONTROLLERS= +ADLDAP_PORT=389 +ADLDAP_TIMEOUT=5 +ADLDAP_BASEDN="" +ADLDAP_FOLLOW_REFFERALS=false +ADLDAP_USE_SSL=false +ADLDAP_USE_TLS=false + +ADLDAP_ADMIN_USERNAME= +ADLDAP_ADMIN_PASSWORD= + +ADLDAP_ACCOUNT_PREFIX= +ADLDAP_ACCOUNT_SUFFIX= +ADLDAP_ADMIN_ACCOUNT_PREFIX= +ADLDAP_ADMIN_ACCOUNT_SUFFIX= + +# LDAP authentication settings. +ADLDAP_PASSWORD_SYNC=false +ADLDAP_LOGIN_FALLBACK=false + +ADLDAP_SYNC_FIELD=userprincipalname +ADLDAP_DISCOVER_FIELD=distinguishedname +ADLDAP_AUTH_FIELD=distinguishedname + +# Will allow SSO if your server provides an AUTH_USER field. +WINDOWS_SSO_DISCOVER=samaccountname +WINDOWS_SSO_KEY=AUTH_USER + +# field to sync as local username. +ADLDAP_SYNC_FIELD=uid + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. APP_NAME=FireflyIII +ADLDAP_CONNECTION=default BROADCAST_DRIVER=log QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index ccdb13e75c..466c0dc67e 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -58,6 +58,13 @@ class ForgotPasswordController extends Controller */ public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository) { + $loginProvider = getenv('LOGIN_PROVIDER'); + if ('eloquent' !== $loginProvider) { + $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); + + return view('error', compact('message')); + } + $this->validateEmail($request); // verify if the user is not a demo user. If so, we give him back an error. @@ -90,6 +97,13 @@ class ForgotPasswordController extends Controller */ public function showLinkRequestForm() { + $loginProvider = getenv('LOGIN_PROVIDER'); + if ('eloquent' !== $loginProvider) { + $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); + + return view('error', compact('message')); + } + // is allowed to? $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 0ca4c9f6b7..6d57c321b6 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -129,8 +129,9 @@ class LoginController extends Controller */ public function showLoginForm(Request $request) { - $count = DB::table('users')->count(); - if (0 === $count) { + $count = DB::table('users')->count(); + $loginProvider = getenv('LOGIN_PROVIDER'); + if (0 === $count && 'eloquent' === $loginProvider) { return redirect(route('register')); // @codeCoverageIgnore } @@ -141,13 +142,20 @@ class LoginController extends Controller $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); $allowRegistration = true; + $allowReset = true; if (true === $singleUserMode && $userCount > 0) { $allowRegistration = false; } + // single user mode is ignored when the user is not using eloquent: + if ('eloquent' !== $loginProvider) { + $allowRegistration = false; + $allowReset = false; + } + $email = $request->old('email'); $remember = $request->old('remember'); - return view('auth.login', compact('allowRegistration', 'email', 'remember')); + return view('auth.login', compact('allowRegistration', 'email', 'remember','allowReset')); } } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 2ece879132..7976eb5d62 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -71,9 +71,19 @@ class RegisterController extends Controller public function register(Request $request) { // is allowed to? - $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; - $userCount = User::count(); - if (true === $singleUserMode && $userCount > 0) { + $allowRegistration = true; + $loginProvider = getenv('LOGIN_PROVIDER'); + $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; + $userCount = User::count(); + if (true === $singleUserMode && $userCount > 0 && 'eloquent' === $loginProvider) { + $allowRegistration = false; + } + + if ('eloquent' !== $loginProvider) { + $allowRegistration = false; + } + + if (false === $allowRegistration) { $message = 'Registration is currently not available.'; return view('error', compact('message')); @@ -102,13 +112,25 @@ class RegisterController extends Controller */ public function showRegistrationForm(Request $request) { - // is demo site? - $isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data; + $allowRegistration = true; + $loginProvider = getenv('LOGIN_PROVIDER'); + $isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data; + $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; + $userCount = User::count(); - // is allowed to? - $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; - $userCount = User::count(); - if (true === $singleUserMode && $userCount > 0) { + if (true === $isDemoSite) { + $allowRegistration = false; + } + + if (true === $singleUserMode && $userCount > 0 && 'eloquent' === $loginProvider) { + $allowRegistration = false; + } + + if ('eloquent' !== $loginProvider) { + $allowRegistration = false; + } + + if (false === $allowRegistration) { $message = 'Registration is currently not available.'; return view('error', compact('message')); diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index a5401c488d..3f26235867 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -28,6 +28,7 @@ use FireflyIII\Http\Controllers\Controller; use FireflyIII\User; use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Password; /** * Class ResetPasswordController @@ -70,7 +71,15 @@ class ResetPasswordController extends Controller */ public function showResetForm(Request $request, $token = null) { - // is allowed to? + $loginProvider = getenv('LOGIN_PROVIDER'); + if ('eloquent' !== $loginProvider) { + $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); + + return view('error', compact('message')); + } + + + // is allowed to register? $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); $allowRegistration = true; @@ -83,4 +92,42 @@ class ResetPasswordController extends Controller ['token' => $token, 'email' => $request->email, 'allowRegistration' => $allowRegistration] ); } + + /** + * Reset the given user's password. + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse + * @throws \Illuminate\Validation\ValidationException + */ + public function reset(Request $request) + { + $loginProvider = getenv('LOGIN_PROVIDER'); + if ('eloquent' !== $loginProvider) { + $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); + + return view('error', compact('message')); + } + + $this->validate($request, $this->rules(), $this->validationErrorMessages()); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $response = $this->broker()->reset( + $this->credentials($request), function ($user, $password) { + $this->resetPassword($user, $password); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $response === Password::PASSWORD_RESET + ? $this->sendResetResponse($request, $response) + : $this->sendResetFailedResponse($request, $response); + } + + } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index a22196b051..755e2f4df1 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -41,6 +41,7 @@ use FireflyIII\User; use Google2FA; use Hash; use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; use Illuminate\Support\Collection; use Laravel\Passport\ClientRepository; use Log; @@ -71,6 +72,7 @@ class ProfileController extends Controller return $next($request); } ); + $this->middleware(IsDemoUser::class)->except(['index']); $this->middleware(IsSandStormUser::class)->except('index'); } @@ -80,8 +82,15 @@ class ProfileController extends Controller * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function changeEmail() + public function changeEmail(Request $request) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + + return redirect(route('profile.index')); + } + $title = auth()->user()->email; $email = auth()->user()->email; $subTitle = (string)trans('firefly.change_your_email'); @@ -95,8 +104,15 @@ class ProfileController extends Controller * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function changePassword() + public function changePassword(Request $request) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + + return redirect(route('profile.index')); + } + $title = auth()->user()->email; $subTitle = (string)trans('firefly.change_your_password'); $subTitleIcon = 'fa-key'; @@ -132,6 +148,10 @@ class ProfileController extends Controller */ public function confirmEmailChange(UserRepositoryInterface $repository, string $token) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + throw new FireflyException('Cannot confirm email change when authentication provider is not local.'); + } // find preference with this token value. /** @var Collection $set */ $set = app('preferences')->findByName('email_change_confirm_token'); @@ -163,8 +183,12 @@ class ProfileController extends Controller * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function deleteAccount() + public function deleteAccount(Request $request) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + $request->session()->flash('warning', trans('firefly.delete_local_info_only', ['login_provider' => $loginProvider])); + } $title = auth()->user()->email; $subTitle = (string)trans('firefly.delete_account'); $subTitleIcon = 'fa-trash'; @@ -216,6 +240,7 @@ class ProfileController extends Controller */ public function index() { + $loginProvider = config('firefly.login_provider'); // check if client token thing exists (default one) $count = DB::table('oauth_clients') ->where('personal_access_client', 1) @@ -241,7 +266,7 @@ class ProfileController extends Controller $accessToken = app('preferences')->set('access_token', $token); } - return view('profile.index', compact('subTitle', 'userId', 'accessToken', 'enabled2FA')); + return view('profile.index', compact('subTitle', 'userId', 'accessToken', 'enabled2FA', 'loginProvider')); } /** @@ -254,6 +279,13 @@ class ProfileController extends Controller */ public function postChangeEmail(EmailFormRequest $request, UserRepositoryInterface $repository) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + + return redirect(route('profile.index')); + } + /** @var User $user */ $user = auth()->user(); $newEmail = $request->string('email'); @@ -299,6 +331,13 @@ class ProfileController extends Controller */ public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + + return redirect(route('profile.index')); + } + // the request has already validated both new passwords must be equal. $current = $request->get('current_password'); $new = $request->get('new_password'); @@ -396,6 +435,11 @@ class ProfileController extends Controller */ public function undoEmailChange(UserRepositoryInterface $repository, string $token, string $hash) { + $loginProvider = config('firefly.login_provider'); + if ('eloquent' !== $loginProvider) { + throw new FireflyException('Cannot confirm email change when authentication provider is not local.'); + } + // find preference with this token value. $set = app('preferences')->findByName('email_change_undo_token'); $user = null; diff --git a/bootstrap/app.php b/bootstrap/app.php index 0abe08a8d8..a2f85126e0 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -46,7 +46,7 @@ if (!function_exists('envNonEmpty')) { function envNonEmpty(string $key, $default = null) { $result = env($key, $default); - if (is_string($result) && $result === '') { + if (is_string($result) && '' === $result) { $result = $default; } diff --git a/composer.json b/composer.json index 66d610c88b..aa51f3bb78 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,9 @@ "ext-intl": "*", "ext-xml": "*", "ext-zip": "*", + "ext-json": "*", + "ext-ldap": "*", + "adldap2/adldap2-laravel": "^4.0", "bacon/bacon-qr-code": "1.*", "bunq/sdk_php": "dev-master#8c1faefc111d9b970168a1837ca165d854954941", "davejamesmiller/laravel-breadcrumbs": "5.*", diff --git a/composer.lock b/composer.lock index 8912d13e11..624a0fc83c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,113 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a15b5b4991745824880345223530fa9e", + "content-hash": "f8b29d89e3421b9a03cbaf4c1ae3fba4", "packages": [ + { + "name": "adldap2/adldap2", + "version": "v8.1.5", + "source": { + "type": "git", + "url": "https://github.com/Adldap2/Adldap2.git", + "reference": "54722408c68f12942fcbf4a1b666d90a178ddc5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Adldap2/Adldap2/zipball/54722408c68f12942fcbf4a1b666d90a178ddc5c", + "reference": "54722408c68f12942fcbf4a1b666d90a178ddc5c", + "shasum": "" + }, + "require": { + "ext-ldap": "*", + "illuminate/support": "~5.0", + "php": ">=5.5.9" + }, + "require-dev": { + "mockery/mockery": "~0.9|~1.0", + "phpunit/phpunit": "~4.8|~5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Adldap\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Steve Bauman", + "email": "steven_bauman@outlook.com", + "role": "Developer" + } + ], + "description": "A PHP LDAP Package for humans.", + "keywords": [ + "active directory", + "ad", + "adLDAP", + "adldap2", + "directory", + "ldap", + "windows" + ], + "time": "2018-04-19T15:06:54+00:00" + }, + { + "name": "adldap2/adldap2-laravel", + "version": "v4.0.10", + "source": { + "type": "git", + "url": "https://github.com/Adldap2/Adldap2-Laravel.git", + "reference": "a5196cce3b5394d7b5e84eb68b38260cb9f0fd3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Adldap2/Adldap2-Laravel/zipball/a5196cce3b5394d7b5e84eb68b38260cb9f0fd3c", + "reference": "a5196cce3b5394d7b5e84eb68b38260cb9f0fd3c", + "shasum": "" + }, + "require": { + "adldap2/adldap2": "^8.0", + "php": ">=7.0" + }, + "require-dev": { + "mockery/mockery": "~1.0", + "orchestra/testbench": "~3.2", + "phpunit/phpunit": "~6.0" + }, + "type": "project", + "extra": { + "laravel": { + "providers": [ + "Adldap\\Laravel\\AdldapServiceProvider", + "Adldap\\Laravel\\AdldapAuthServiceProvider" + ], + "aliases": { + "Adldap": "Adldap\\Laravel\\Facades\\Adldap" + } + } + }, + "autoload": { + "psr-4": { + "Adldap\\Laravel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "LDAP Authentication & Management for Laravel.", + "keywords": [ + "adLDAP", + "adldap2", + "laravel", + "ldap" + ], + "time": "2018-09-18T14:27:05+00:00" + }, { "name": "bacon/bacon-qr-code", "version": "1.0.3", @@ -114,7 +219,7 @@ "payment", "sepa" ], - "time": "2018-09-01T12:54:04+00:00" + "time": "2018-10-05T13:50:22+00:00" }, { "name": "davejamesmiller/laravel-breadcrumbs", @@ -1022,16 +1127,16 @@ }, { "name": "laravel/framework", - "version": "v5.7.8", + "version": "v5.7.9", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "763b64a43ebb6042e463aab4214d4cc9722147be" + "reference": "172f69f86bb86e107fb9fafff293b4b01291cf05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/763b64a43ebb6042e463aab4214d4cc9722147be", - "reference": "763b64a43ebb6042e463aab4214d4cc9722147be", + "url": "https://api.github.com/repos/laravel/framework/zipball/172f69f86bb86e107fb9fafff293b4b01291cf05", + "reference": "172f69f86bb86e107fb9fafff293b4b01291cf05", "shasum": "" }, "require": { @@ -1160,7 +1265,7 @@ "framework", "laravel" ], - "time": "2018-10-04T14:47:20+00:00" + "time": "2018-10-09T13:28:28+00:00" }, { "name": "laravel/passport", @@ -5660,7 +5765,7 @@ "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "magento/magento1ce": "<1.9.3.9", "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/product-community-edition": ">=2,<2.2.5", + "magento/product-community-edition": ">=2,<2.2.6", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -5775,7 +5880,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-10-05T18:14:02+00:00" + "time": "2018-10-12T22:19:58+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6760,7 +6865,9 @@ "ext-gd": "*", "ext-intl": "*", "ext-xml": "*", - "ext-zip": "*" + "ext-zip": "*", + "ext-json": "*", + "ext-ldap": "*" }, "platform-dev": [] } diff --git a/config/adldap.php b/config/adldap.php new file mode 100644 index 0000000000..4b879bcc0c --- /dev/null +++ b/config/adldap.php @@ -0,0 +1,259 @@ + [ + + 'default' => [ + + /* + |-------------------------------------------------------------------------- + | Auto Connect + |-------------------------------------------------------------------------- + | + | If auto connect is true, Adldap will try to automatically connect to + | your LDAP server in your configuration. This allows you to assume + | connectivity rather than having to connect manually + | in your application. + | + | If this is set to false, you **must** connect manually before running + | LDAP operations. + | + */ + + 'auto_connect' => env('ADLDAP_AUTO_CONNECT', true), + + /* + |-------------------------------------------------------------------------- + | Connection + |-------------------------------------------------------------------------- + | + | The connection class to use to run raw LDAP operations on. + | + | Custom connection classes must implement: + | + | Adldap\Connections\ConnectionInterface + | + */ + + 'connection' => Adldap\Connections\Ldap::class, + + /* + |-------------------------------------------------------------------------- + | Schema + |-------------------------------------------------------------------------- + | + | The schema class to use for retrieving attributes and generating models. + | + | You can also set this option to `null` to use the default schema class. + | + | For OpenLDAP, you must use the schema: + | + | Adldap\Schemas\OpenLDAP::class + | + | For FreeIPA, you must use the schema: + | + | Adldap\Schemas\FreeIPA::class + | + | Custom schema classes must implement Adldap\Schemas\SchemaInterface + | + */ + + 'schema' => $schema, + + /* + |-------------------------------------------------------------------------- + | Connection Settings + |-------------------------------------------------------------------------- + | + | This connection settings array is directly passed into the Adldap constructor. + | + | Feel free to add or remove settings you don't need. + | + */ + + 'connection_settings' => [ + + /* + |-------------------------------------------------------------------------- + | Account Prefix + |-------------------------------------------------------------------------- + | + | The account prefix option is the prefix of your user accounts in LDAP directory. + | + | This string is prepended to authenticating users usernames. + | + */ + + 'account_prefix' => env('ADLDAP_ACCOUNT_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Account Suffix + |-------------------------------------------------------------------------- + | + | The account suffix option is the suffix of your user accounts in your LDAP directory. + | + | This string is appended to authenticating users usernames. + | + */ + + 'account_suffix' => env('ADLDAP_ACCOUNT_SUFFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Domain Controllers + |-------------------------------------------------------------------------- + | + | The domain controllers option is an array of servers located on your + | network that serve Active Directory. You can insert as many servers or + | as little as you'd like depending on your forest (with the + | minimum of one of course). + | + | These can be IP addresses of your server(s), or the host name. + | + */ + + 'domain_controllers' => explode(' ', env('ADLDAP_CONTROLLERS', '127.0.0.1')), + + /* + |-------------------------------------------------------------------------- + | Port + |-------------------------------------------------------------------------- + | + | The port option is used for authenticating and binding to your LDAP server. + | + */ + + 'port' => env('ADLDAP_PORT', 389), + + /* + |-------------------------------------------------------------------------- + | Timeout + |-------------------------------------------------------------------------- + | + | The timeout option allows you to configure the amount of time in + | seconds that your application waits until a response + | is received from your LDAP server. + | + */ + + 'timeout' => env('ADLDAP_TIMEOUT', 5), + + /* + |-------------------------------------------------------------------------- + | Base Distinguished Name + |-------------------------------------------------------------------------- + | + | The base distinguished name is the base distinguished name you'd + | like to perform query operations on. An example base DN would be: + | + | dc=corp,dc=acme,dc=org + | + | A correct base DN is required for any query results to be returned. + | + */ + + 'base_dn' => env('ADLDAP_BASEDN', 'dc=temp'), + + /* + |-------------------------------------------------------------------------- + | Administrator Account Suffix / Prefix + |-------------------------------------------------------------------------- + | + | This option allows you to set a different account prefix and suffix + | for your configured administrator account upon binding. + | + | If left empty or set to `null`, your `account_prefix` and + | `account_suffix` options above will be used. + | + */ + + 'admin_account_prefix' => env('ADLDAP_ADMIN_ACCOUNT_PREFIX', ''), + 'admin_account_suffix' => env('ADLDAP_ADMIN_ACCOUNT_SUFFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Administrator Username & Password + |-------------------------------------------------------------------------- + | + | When connecting to your LDAP server, a username and password is required + | to be able to query and run operations on your server(s). You can + | use any user account that has these permissions. This account + | does not need to be a domain administrator unless you + | require changing and resetting user passwords. + | + */ + + 'admin_username' => env('ADLDAP_ADMIN_USERNAME', ''), + 'admin_password' => env('ADLDAP_ADMIN_PASSWORD', ''), + + /* + |-------------------------------------------------------------------------- + | Follow Referrals + |-------------------------------------------------------------------------- + | + | The follow referrals option is a boolean to tell active directory + | to follow a referral to another server on your network if the + | server queried knows the information your asking for exists, + | but does not yet contain a copy of it locally. + | + | This option is defaulted to false. + | + */ + + 'follow_referrals' => env('ADLDAP_FOLLOW_REFFERALS', false), + + /* + |-------------------------------------------------------------------------- + | SSL & TLS + |-------------------------------------------------------------------------- + | + | If you need to be able to change user passwords on your server, then an + | SSL or TLS connection is required. All other operations are allowed + | on unsecured protocols. + | + | One of these options are definitely recommended if you + | have the ability to connect to your server securely. + | + */ + + 'use_ssl' => env('ADLDAP_USE_SSL', false), + 'use_tls' => env('ADLDAP_USE_TLS', false), + + ], + + ], + + ], + +]; diff --git a/config/adldap_auth.php b/config/adldap_auth.php new file mode 100644 index 0000000000..ec1ce2674c --- /dev/null +++ b/config/adldap_auth.php @@ -0,0 +1,317 @@ + envNonEmpty('ADLDAP_CONNECTION', 'default'), + + /* + |-------------------------------------------------------------------------- + | Provider + |-------------------------------------------------------------------------- + | + | The LDAP authentication provider to use depending + | if you require database synchronization. + | + | For synchronizing LDAP users to your local applications database, use the provider: + | + | Adldap\Laravel\Auth\DatabaseUserProvider::class + | + | Otherwise, if you just require LDAP authentication, use the provider: + | + | Adldap\Laravel\Auth\NoDatabaseUserProvider::class + | + */ + + 'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class, + //'provider' => Adldap\Laravel\Auth\NoDatabaseUserProvider::class, + /* + |-------------------------------------------------------------------------- + | Rules + |-------------------------------------------------------------------------- + | + | Rules allow you to control user authentication requests depending on scenarios. + | + | You can create your own rules and insert them here. + | + | All rules must extend from the following class: + | + | Adldap\Laravel\Validation\Rules\Rule + | + */ + + 'rules' => [ + + // Denys deleted users from authenticating. + Adldap\Laravel\Validation\Rules\DenyTrashed::class, + + // Allows only manually imported users to authenticate. + // Adldap\Laravel\Validation\Rules\OnlyImported::class, + + ], + + /* + |-------------------------------------------------------------------------- + | Scopes + |-------------------------------------------------------------------------- + | + | Scopes allow you to restrict the LDAP query that locates + | users upon import and authentication. + | + | All scopes must implement the following interface: + | + | Adldap\Laravel\Scopes\ScopeInterface + |[ + + // Only allows users with a user principal name to authenticate. + // Remove this if you're using OpenLDAP. + //Adldap\Laravel\Scopes\UpnScope::class, + + // Only allows users with a uid to authenticate. + // Uncomment if you're using OpenLDAP. + Adldap\Laravel\Scopes\UidScope::class, + + ], + */ + + 'scopes' => $scopes, + + 'usernames' => [ + + /* + |-------------------------------------------------------------------------- + | LDAP + |-------------------------------------------------------------------------- + | + | Discover: + | + | The discover value is the users attribute you would + | like to locate LDAP users by in your directory. + | + | For example, using the default configuration below, if you're + | authenticating users with an email address, your LDAP server + | will be queried for a user with the a `userprincipalname` + | equal to the entered email address. + | + | Authenticate: + | + | The authenticate value is the users attribute you would + | like to use to bind to your LDAP server. + | + | For example, when a user is located by the above 'discover' + | attribute, the users attribute you specify below will + | be used as the username to bind to your LDAP server. + | + */ + + 'ldap' => [ + + 'discover' => envNonEmpty('ADLDAP_DISCOVER_FIELD', 'userprincipalname'), + 'authenticate' => envNonEmpty('ADLDAP_AUTH_FIELD', 'distinguishedname'), + + ], + + /* + |-------------------------------------------------------------------------- + | Eloquent + |-------------------------------------------------------------------------- + | + | The value you enter is the database column name used for locating + | the local database record of the authenticating user. + | + | If you're using a `username` column instead, change this to `username`. + | + | This option is only applicable to the DatabaseUserProvider. + | + */ + + 'eloquent' => 'email', + + /* + |-------------------------------------------------------------------------- + | Windows Authentication Middleware (SSO) + |-------------------------------------------------------------------------- + | + | Discover: + | + | The 'discover' value is the users attribute you would + | like to locate LDAP users by in your directory. + | + | For example, if 'samaccountname' is the value, then your LDAP server is + | queried for a user with the 'samaccountname' equal to the value of + | $_SERVER['AUTH_USER']. + | + | If a user is found, they are imported (if using the DatabaseUserProvider) + | into your local database, then logged in. + | + | Key: + | + | The 'key' value represents the 'key' of the $_SERVER + | array to pull the users account name from. + | + | For example, $_SERVER['AUTH_USER']. + | + */ + + 'windows' => [ + 'discover' => envNonEmpty('WINDOWS_SSO_DISCOVER', 'samaccountname'), + 'key' => envNonEmpty('WINDOWS_SSO_KEY', 'AUTH_USER'), + ], + ], + + 'passwords' => [ + + /* + |-------------------------------------------------------------------------- + | Password Sync + |-------------------------------------------------------------------------- + | + | The password sync option allows you to automatically synchronize users + | LDAP passwords to your local database. These passwords are hashed + | natively by Laravel using the bcrypt() method. + | + | Enabling this option would also allow users to login to their accounts + | using the password last used when an LDAP connection was present. + | + | If this option is disabled, the local database account is applied a + | random 16 character hashed password upon every login, and will + | lose access to this account upon loss of LDAP connectivity. + | + | This option must be true or false and is only applicable + | to the DatabaseUserProvider. + | + */ + + 'sync' => env('ADLDAP_PASSWORD_SYNC', false), + + /* + |-------------------------------------------------------------------------- + | Column + |-------------------------------------------------------------------------- + | + | This is the column of your users database table + | that is used to store passwords. + | + | Set this to `null` if you do not have a password column. + | + | This option is only applicable to the DatabaseUserProvider. + | + */ + + 'column' => 'password', + + ], + + /* + |-------------------------------------------------------------------------- + | Login Fallback + |-------------------------------------------------------------------------- + | + | The login fallback option allows you to login as a user located on the + | local database if active directory authentication fails. + | + | Set this to true if you would like to enable it. + | + | This option must be true or false and is only + | applicable to the DatabaseUserProvider. + | + */ + + 'login_fallback' => env('ADLDAP_LOGIN_FALLBACK', false), + + /* + |-------------------------------------------------------------------------- + | Sync Attributes + |-------------------------------------------------------------------------- + | + | Attributes specified here will be added / replaced on the user model + | upon login, automatically synchronizing and keeping the attributes + | up to date. + | + | The array key represents the users Laravel model key, and + | the value represents the users LDAP attribute. + | + | This option must be an array and is only applicable + | to the DatabaseUserProvider. + | + */ + + 'sync_attributes' => [ + + 'email' => envNonEmpty('ADLDAP_SYNC_FIELD', 'userprincipalname'), + //'name' => 'cn', + + ], + + /* + |-------------------------------------------------------------------------- + | Logging + |-------------------------------------------------------------------------- + | + | User authentication attempts will be logged using Laravel's + | default logger if this setting is enabled. + | + | No credentials are logged, only usernames. + | + | This is usually stored in the '/storage/logs' directory + | in the root of your application. + | + | This option is useful for debugging as well as auditing. + | + | You can freely remove any events you would not like to log below, + | as well as use your own listeners if you would prefer. + | + */ + + 'logging' => [ + 'enabled' => true, + 'events' => [ + + \Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class, + \Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class, + \Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class, + \Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class, + \Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class, + \Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class, + \Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class, + \Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class, + \Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class, + \Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class, + \Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class, + + ], + ], + +]; diff --git a/config/auth.php b/config/auth.php index fec9f2f764..66afef9de3 100644 --- a/config/auth.php +++ b/config/auth.php @@ -62,7 +62,6 @@ return [ 'driver' => 'session', 'provider' => 'users', ], - 'api' => [ 'driver' => 'passport', 'provider' => 'users', @@ -88,14 +87,9 @@ return [ 'providers' => [ 'users' => [ - 'driver' => 'eloquent', + 'driver' => envNonEmpty('LOGIN_PROVIDER', 'eloquent'),//'adldap', 'model' => FireflyIII\User::class, ], - - // 'users' => [ - // 'driver' => 'database', - // 'table' => 'users', - // ], ], /* diff --git a/config/firefly.php b/config/firefly.php index 3168d62dfe..d8811e0999 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -95,6 +95,7 @@ return [ 'api_version' => '0.8', 'db_version' => 5, 'maxUploadSize' => 15242880, + 'login_provider' => env('LOGIN_PROVIDER', 'eloquent'), 'allowedMimes' => [ /* plain files */ 'text/plain', diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index be826d4688..1c53b1c8b1 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -551,6 +551,8 @@ return [ 'email_changed_logout' => 'Until you verify your email address, you cannot login.', 'login_with_new_email' => 'You can now login with your new email address.', 'login_with_old_email' => 'You can now login with your old email address again.', + 'login_provider_local_only' => 'This action is not available when authenticating through ":login_provider".', + 'delete_local_info_only' => 'Because you authenticate through ":login_provider", this will only delete local Firefly III information.', // attachments 'nr_of_attachments' => 'One attachment|:count attachments', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 6b4999f3f9..ee637199ba 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -191,6 +191,7 @@ return [ 'password_confirmation' => 'Password (again)', 'blocked' => 'Is blocked?', 'blocked_code' => 'Reason for block', + 'login_name' => 'Login', // import 'apply_rules' => 'Apply rules', diff --git a/resources/views/auth/login.twig b/resources/views/auth/login.twig index 094375048e..3308e41329 100644 --- a/resources/views/auth/login.twig +++ b/resources/views/auth/login.twig @@ -54,7 +54,11 @@
- + {% if env('LOGIN_PROVIDER', '') == 'eloquent' %} + + {% else %} + + {% endif %}
@@ -75,7 +79,9 @@ {% if allowRegistration %} {{ 'register_new_account'|_ }}
{% endif %} - {{ 'forgot_my_password'|_ }} + {% if allowReset %} + {{ 'forgot_my_password'|_ }} + {% endif %}
{% endblock %} From 3bc38570a2dc860a8887550cd648e8083ecc9d28 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 21:32:20 +0200 Subject: [PATCH 40/94] Code for #1071 --- app/Console/Commands/ApplyRules.php | 350 +++++++++++++++++++ app/Console/Commands/VerifiesAccessToken.php | 20 ++ 2 files changed, 370 insertions(+) create mode 100644 app/Console/Commands/ApplyRules.php diff --git a/app/Console/Commands/ApplyRules.php b/app/Console/Commands/ApplyRules.php new file mode 100644 index 0000000000..8569c149be --- /dev/null +++ b/app/Console/Commands/ApplyRules.php @@ -0,0 +1,350 @@ +accounts = new Collection; + $this->rules = new Collection; + } + + /** + * Execute the console command. + * + * @return int + * @throws \FireflyIII\Exceptions\FireflyException + */ + public function handle(): int + { + if (!$this->verifyAccessToken()) { + $this->error('Invalid access token.'); + + return 1; + } + + $result = $this->verifyInput(); + if (false === $result) { + return 1; + } + + // get transactions from asset accounts. + /** @var TransactionCollectorInterface $collector */ + $collector = app(TransactionCollectorInterface::class); + $collector->setUser($this->getUser()); + $collector->setAccounts($this->accounts); + $collector->setRange($this->startDate, $this->endDate); + $transactions = $collector->getTransactions(); + $count = $transactions->count(); + $bar = $this->output->createProgressBar($count * $this->rules->count()); + $results = new Collection; + $this->line(sprintf('Will apply %d rules to %d transactions', $this->rules->count(), $transactions->count())); + + + foreach ($this->rules as $rule) { + /** @var Processor $processor */ + $processor = app(Processor::class); + $processor->make($rule, true); + + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + /** @var Rule $rule */ + $bar->advance(); + $result = $processor->handleTransaction($transaction); + if (true === $result) { + $results->push($transaction); + } + } + } + $results = $results->unique( + function (Transaction $transaction) { + return (int)$transaction->journal_id; + } + ); + + $bar->finish(); + $this->line(''); + if (0 === \count($results)) { + $this->line('The rules were fired but did not influence any transactions.'); + } + if (\count($results) > 0) { + $this->line(sprintf('The rules were fired, and influences %d transaction(s).', \count($results))); + foreach ($results as $result) { + $this->line( + vsprintf( + 'Transaction #%d: "%s" (%s %s)', + [ + $result->journal_id, + $result->description, + $result->transaction_currency_code, + round($result->transaction_amount, $result->transaction_currency_dp), + ] + ) + ); + } + } + + return 0; + } + + /** + * + */ + private function grabAllRules(): void + { + if (true === $this->option('all_rules')) { + /** @var RuleRepositoryInterface $ruleRepos */ + $ruleRepos = app(RuleRepositoryInterface::class); + $ruleRepos->setUser($this->getUser()); + $this->rules = $ruleRepos->getAll(); + } + } + + /** + * + */ + private function parseDates(): void + { + // parse start date. + $startDate = Carbon::create()->startOfMonth(); + $startString = $this->option('start_date'); + if (null === $startString) { + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + $repository->setUser($this->getUser()); + $first = $repository->firstNull(); + if (null !== $first) { + $startDate = $first->date; + } + } + if (null !== $startString && '' !== $startString) { + $startDate = Carbon::createFromFormat('Y-m-d', $startString); + } + + // parse end date + $endDate = Carbon::now(); + $endString = $this->option('end_date'); + if (null !== $endString && '' !== $endString) { + $endDate = Carbon::createFromFormat('Y-m-d', $endString); + } + + if ($startDate > $endDate) { + [$endDate, $startDate] = [$startDate, $endDate]; + } + + $this->startDate = $startDate; + $this->endDate = $endDate; + } + + /** + * @return bool + * @throws \FireflyIII\Exceptions\FireflyException + */ + private function verifyInput(): bool + { + // verify account. + $result = $this->verifyInputAccounts(); + if (false === $result) { + return $result; + } + + // verify rule groups. + $result = $this->verifyRuleGroups(); + if (false === $result) { + return $result; + } + + // verify rules. + $result = $this->verifyRules(); + if (false === $result) { + return $result; + } + + $this->grabAllRules(); + $this->parseDates(); + + //$this->line('Number of rules found: ' . $this->rules->count()); + $this->line('Start date is ' . $this->startDate->format('Y-m-d')); + $this->line('End date is ' . $this->endDate->format('Y-m-d')); + + return true; + } + + /** + * @return bool + * @throws \FireflyIII\Exceptions\FireflyException + */ + private function verifyInputAccounts(): bool + { + $accountString = $this->option('accounts'); + if (null === $accountString || '' === $accountString) { + $this->error('Please use the --accounts to indicate the accounts to apply rules to.'); + + return false; + } + $finalList = new Collection; + $accountList = explode(',', $accountString); + + if (0 === \count($accountList)) { + $this->error('Please use the --accounts to indicate the accounts to apply rules to.'); + + return false; + } + + /** @var AccountRepositoryInterface $accountRepository */ + $accountRepository = app(AccountRepositoryInterface::class); + $accountRepository->setUser($this->getUser()); + + foreach ($accountList as $accountId) { + $accountId = (int)$accountId; + $account = $accountRepository->findNull($accountId); + if (null !== $account + && \in_array( + $account->accountType->type, [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE], true + )) { + $finalList->push($account); + } + } + + if (0 === $finalList->count()) { + $this->error('Please make sure all accounts in --accounts are asset accounts or liabilities.'); + + return false; + } + $this->accounts = $finalList; + + return true; + + } + + /** + * @return bool + * @throws \FireflyIII\Exceptions\FireflyException + */ + private function verifyRuleGroups(): bool + { + $ruleGroupString = $this->option('rule_groups'); + if (null === $ruleGroupString || '' === $ruleGroupString) { + // can be empty. + return true; + } + $finalList = new Collection; + $ruleGroupList = explode(',', $ruleGroupString); + + if (0 === \count($ruleGroupList)) { + // can be empty. + + return true; + } + /** @var RuleGroupRepositoryInterface $ruleGroupRepos */ + $ruleGroupRepos = app(RuleGroupRepositoryInterface::class); + $ruleGroupRepos->setUser($this->getUser()); + + foreach ($ruleGroupList as $ruleGroupId) { + $ruleGroupId = (int)$ruleGroupId; + $ruleGroup = $ruleGroupRepos->find($ruleGroupId); + if (null !== $ruleGroup) { + $rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup); + $finalList = $finalList->merge($rules); + } + } + $this->rules = $finalList; + + return true; + } + + /** + * @return bool + * @throws \FireflyIII\Exceptions\FireflyException + */ + private function verifyRules(): bool + { + $ruleString = $this->option('rules'); + if (null === $ruleString || '' === $ruleString) { + // can be empty. + return true; + } + $finalList = new Collection; + $ruleList = explode(',', $ruleString); + + if (0 === \count($ruleList)) { + // can be empty. + + return true; + } + /** @var RuleRepositoryInterface $ruleRepos */ + $ruleRepos = app(RuleRepositoryInterface::class); + $ruleRepos->setUser($this->getUser()); + + foreach ($ruleList as $ruleId) { + $ruleId = (int)$ruleId; + $rule = $ruleRepos->find($ruleId); + if (null !== $rule) { + $finalList->push($rule); + } + } + if ($finalList->count() > 0) { + $this->rules = $finalList; + } + + return true; + } + + +} diff --git a/app/Console/Commands/VerifiesAccessToken.php b/app/Console/Commands/VerifiesAccessToken.php index a0224ae0d6..39f300d796 100644 --- a/app/Console/Commands/VerifiesAccessToken.php +++ b/app/Console/Commands/VerifiesAccessToken.php @@ -23,17 +23,37 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\User; use Log; /** * Trait VerifiesAccessToken. * * Verifies user access token for sensitive commands. + * * @codeCoverageIgnore */ trait VerifiesAccessToken { + /** + * @return User + * @throws FireflyException + */ + public function getUser(): User + { + $userId = (int)$this->option('user'); + /** @var UserRepositoryInterface $repository */ + $repository = app(UserRepositoryInterface::class); + $user = $repository->findNull($userId); + if (null === $user) { + throw new FireflyException('User is unexpectedly NULL'); + } + + return $user; + } + /** * Abstract method to make sure trait knows about method "option". * From c6370ebe480544b5ec4c2aba2e593ceb55961d16 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 21:45:12 +0200 Subject: [PATCH 41/94] Fix tests for login providers when dealing with LDAP. --- app/Http/Controllers/Auth/ForgotPasswordController.php | 7 ++++--- app/Http/Controllers/Auth/LoginController.php | 2 +- app/Http/Controllers/Auth/RegisterController.php | 4 ++-- app/Http/Controllers/Auth/ResetPasswordController.php | 4 ++-- resources/views/auth/login.twig | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 466c0dc67e..1ea84b992b 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -30,6 +30,7 @@ use FireflyIII\User; use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Http\Request; use Illuminate\Support\Facades\Password; +use Log; /** * Class ForgotPasswordController @@ -58,10 +59,10 @@ class ForgotPasswordController extends Controller */ public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository) { - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); if ('eloquent' !== $loginProvider) { $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); - + Log::error($message); return view('error', compact('message')); } @@ -97,7 +98,7 @@ class ForgotPasswordController extends Controller */ public function showLinkRequestForm() { - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); if ('eloquent' !== $loginProvider) { $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 6d57c321b6..74d37f86ea 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -130,7 +130,7 @@ class LoginController extends Controller public function showLoginForm(Request $request) { $count = DB::table('users')->count(); - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); if (0 === $count && 'eloquent' === $loginProvider) { return redirect(route('register')); // @codeCoverageIgnore } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 7976eb5d62..2078d1e1e4 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -72,7 +72,7 @@ class RegisterController extends Controller { // is allowed to? $allowRegistration = true; - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); if (true === $singleUserMode && $userCount > 0 && 'eloquent' === $loginProvider) { @@ -113,7 +113,7 @@ class RegisterController extends Controller public function showRegistrationForm(Request $request) { $allowRegistration = true; - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); $isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data; $singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data; $userCount = User::count(); diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 3f26235867..de1979c590 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -71,7 +71,7 @@ class ResetPasswordController extends Controller */ public function showResetForm(Request $request, $token = null) { - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); if ('eloquent' !== $loginProvider) { $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); @@ -103,7 +103,7 @@ class ResetPasswordController extends Controller */ public function reset(Request $request) { - $loginProvider = getenv('LOGIN_PROVIDER'); + $loginProvider = env('LOGIN_PROVIDER','eloquent'); if ('eloquent' !== $loginProvider) { $message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider); diff --git a/resources/views/auth/login.twig b/resources/views/auth/login.twig index 3308e41329..53c545a1a6 100644 --- a/resources/views/auth/login.twig +++ b/resources/views/auth/login.twig @@ -54,7 +54,7 @@
- {% if env('LOGIN_PROVIDER', '') == 'eloquent' %} + {% if env('LOGIN_PROVIDER', 'eloquent') == 'eloquent' %} {% else %} From 2575f618282f921a47244201c4e7ab10f2fe80ef Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 21:45:23 +0200 Subject: [PATCH 42/94] Remove test script from root of Firefly III. --- test.sh | 150 -------------------------------------------------------- 1 file changed, 150 deletions(-) delete mode 100755 test.sh diff --git a/test.sh b/test.sh deleted file mode 100755 index bcf4487379..0000000000 --- a/test.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash - -DATABASE=./storage/database/database.sqlite -DATABASECOPY=./storage/database/databasecopy.sqlite -ORIGINALENV=./.env -BACKUPENV=./.env.current -TESTINGENV=./.env.testing - -# do something with flags: -resetTestFlag='' -testflag='' -coverageflag='' - -featureflag='' -featuretestclass='' - -unitflag='' -unittestclass='' - -apiflag='' -apitestclass='' - -verbalflag='' -testsuite='' -suiteflag='' -configfile='phpunit.xml'; - -while getopts 'vcrtf:u:s:a:' flag; do - case "${flag}" in - r) - resetTestFlag='true' - ;; - t) - testflag='true' - ;; - c) - coverageflag='true' - configfile='phpunit.coverage.xml'; - ;; - v) - verbalflag=' -v --debug' - echo "Will be verbal about it" - ;; - f) - featureflag='true' - featuretestclass=./tests/Feature/$OPTARG - echo "Will only run Feature test $OPTARG" - ;; - u) - unitflag='true' - unittestclass=./tests/Unit/$OPTARG - echo "Will only run Unit test $OPTARG" - ;; - a) - apiflag='true' - apitestclass=./tests/Api/$OPTARG - echo "Will only run Api test $OPTARG" - ;; - s) - suiteflag='true' - testsuite="--testsuite $OPTARG" - echo "Will only run test suite '$OPTARG'" - ;; - *) error "Unexpected option ${flag}" ;; - esac -done - -if [[ $coverageflag == "true" && ($suiteflag == "true" || $featureflag == "true" || $unitflag == "true" || $apiflag == "true") ]] -then - echo "Use config file specific.xml" - configfile='phpunit.coverage.specific.xml' -fi - -# backup current config (if it exists): -if [ -f $ORIGINALENV ]; then - mv $ORIGINALENV $BACKUPENV -fi - -# enable testing config -cp $TESTINGENV $ORIGINALENV - -# reset database (optional) -if [[ $resetTestFlag == "true" ]] -then - echo "Must reset database" - - # touch files to make sure they exist. - touch $DATABASE - touch $DATABASECOPY - - # truncate original database file - truncate $DATABASE --size 0 - - # run migration - php artisan migrate:refresh --seed - - # call test data generation script - $(which php) /sites/FF3/test-data/artisan generate:data local sqlite - - # also run upgrade routine: - $(which php) /sites/FF3/firefly-iii/artisan firefly:upgrade-database - - # copy new database over backup (resets backup) - cp $DATABASE $DATABASECOPY - - # copy new database to test-data repository: - cp $DATABASE /sites/FF3/test-data/storage/database.sqlite -fi - -# do not reset database (optional) -if [[ $resetTestFlag == "" ]] -then - echo "Will not reset database" -fi - -echo "Copy test database over original" -# take database from copy: -cp $DATABASECOPY $DATABASE - -echo "clear caches and what-not.." -php artisan cache:clear -# php artisan config:clear -# php artisan route:clear -# php artisan twig:clean -# php artisan view:clear - -# run PHPUnit -if [[ $testflag == "" ]] -then - echo "Must not run PHPUnit" -else - echo "Must run PHPUnit" - - if [[ $coverageflag == "" ]] - then - echo "Must run PHPUnit without coverage:" - else - echo "Must run PHPUnit with coverage" - fi - - echo "./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite" - ./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite - -fi - - -# restore current config: -if [ -f $BACKUPENV ]; then - mv $BACKUPENV $ORIGINALENV -fi From d8ecc63e66f5d853d6dc822275a191761aae0f57 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 13 Oct 2018 22:15:06 +0200 Subject: [PATCH 43/94] Fix Spectre test. --- .../Import/Routine/Spectre/StageImportDataHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Support/Import/Routine/Spectre/StageImportDataHandlerTest.php b/tests/Unit/Support/Import/Routine/Spectre/StageImportDataHandlerTest.php index 82d11562fd..af9ff5e92b 100644 --- a/tests/Unit/Support/Import/Routine/Spectre/StageImportDataHandlerTest.php +++ b/tests/Unit/Support/Import/Routine/Spectre/StageImportDataHandlerTest.php @@ -123,7 +123,7 @@ class StageImportDataHandlerTest extends TestCase $revenue = $this->user()->accounts()->where('account_type_id', 5)->first(); $job = new ImportJob; $job->user_id = $this->user()->id; - $job->key = 'sid_a_' . random_int(1, 10000); + $job->key = 'sid_a__' . random_int(1, 100000); $job->status = 'new'; $job->stage = 'new'; $job->provider = 'spectre'; From 7b68716a3dac05aff746fed50daea61a7fabd913 Mon Sep 17 00:00:00 2001 From: HamuZ HamuZ <550499+hamuz@users.noreply.github.com> Date: Sat, 13 Oct 2018 20:05:53 +0300 Subject: [PATCH 44/94] allow sftp host as backing storage using env --- composer.json | 4 + composer.lock | 305 ++++++++++++++++++++++++++++++- config/filesystems.php | 400 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 702 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index aa51f3bb78..1c59e3ac14 100644 --- a/composer.json +++ b/composer.json @@ -58,6 +58,7 @@ "adldap2/adldap2-laravel": "^4.0", "bacon/bacon-qr-code": "1.*", "bunq/sdk_php": "dev-master#8c1faefc111d9b970168a1837ca165d854954941", + "danhunsaker/laravel-flysystem-others": "^1.3", "davejamesmiller/laravel-breadcrumbs": "5.*", "doctrine/dbal": "2.*", "fideloper/proxy": "4.*", @@ -66,7 +67,10 @@ "laravelcollective/html": "5.7.*", "league/commonmark": "0.*", "league/csv": "9.*", + "league/flysystem-replicate-adapter": "^1.0", + "league/flysystem-sftp": "^1.0", "league/fractal": "^0.17.0", + "litipk/flysystem-fallback-adapter": "^0.1.3", "mschindler83/fints-hbci-php": "^1.0", "pragmarx/google2fa": "3.*", "pragmarx/google2fa-laravel": "0.*", diff --git a/composer.lock b/composer.lock index 624a0fc83c..5ada4c8269 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f8b29d89e3421b9a03cbaf4c1ae3fba4", + "content-hash": "f28fdf6ec034460c012d2734231029b7", "packages": [ { "name": "adldap2/adldap2", @@ -219,7 +219,179 @@ "payment", "sepa" ], - "time": "2018-10-05T13:50:22+00:00" + "time": "2018-09-01T12:54:04+00:00" + }, + { + "name": "danhunsaker/laravel-flysystem-others", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/danhunsaker/laravel-flysystem-others.git", + "reference": "43c5e3bf8cbb9bc22a2e228cb644882f0be52f29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danhunsaker/laravel-flysystem-others/zipball/43c5e3bf8cbb9bc22a2e228cb644882f0be52f29", + "reference": "43c5e3bf8cbb9bc22a2e228cb644882f0be52f29", + "shasum": "" + }, + "require": { + "danhunsaker/laravel-flysystem-service": "^1.1", + "illuminate/filesystem": "^5.0", + "illuminate/support": "^5.0", + "league/flysystem": "^1.0" + }, + "suggest": { + "aliyuncs/aliyun-oss-flysystem": "One of the options to use the 'oss' adapter (^1.2)", + "aobozhang/aliyun-oss-adapter": "One of the options to use the 'oss' adapter (^1.0)", + "apollopy/flysystem-aliyun-oss": "One of the options to use the 'oss' adapter (^1.2)", + "argentcrusade/flysystem-selectel": "Required to use the 'selectel' adapter (^1.2)", + "arhitector/yandex-disk-flysystem": "Required to use the 'yandex' adapter (^1.0)", + "boofw/flysystem-qiniu": "One of the options to use the 'qiniu' adapter (^1.0)", + "carlosocarvalho/flysystem-cloudinary": "One of the options to use the 'cloudinary' adapter (^1.0)", + "cedricziel/flysystem-gcs": "One of the options to use the 'google' adapter (^2.0)", + "danhunsaker/flysystem-redis": "Required to use the 'redis' adapter (^1.0)", + "emgag/flysystem-tempdir": "Required to use the 'temp' adapter (^0.1)", + "engineor/flysystem-runabove": "Required to use the 'runabove' adapter (^1.0)", + "enl/flysystem-cloudinary": "One of the options to use the 'cloudinary' adapter (^1.1)", + "eqingdan/flysystem-qiniu": "One of the options to use the 'qiniu' adapter (^0.1)", + "freyo/flysystem-qcloud-cos-v3": "One of the options to use the 'qcloud' adapter (^)", + "freyo/flysystem-qcloud-cos-v4": "One of the options to use the 'qcloud' adapter (^)", + "freyo/flysystem-qcloud-cos-v5": "One of the options to use the 'qcloud' adapter (^)", + "ignited/flysystem-google-drive": "One of the options to use the 'gdrive' adapter (dev-master)", + "ignited/flysystem-onedrive": "One of the options to use the 'onedrive' adapter (dev-master)", + "integral/flysystem-pdo-adapter": "One of the options to use the 'pdo' adapter (^1.0)", + "jacekbarecki/flysystem-onedrive": "One of the options to use the 'onedrive' adapter (^1.0)", + "jellybool/flysystem-upyun": "Required to use the 'upyun' adapter (^1.0)", + "kapersoft/flysystem-sharefile": "Required to use the 'sharefile' adapter (^1.1)", + "litipk/flysystem-fallback-adapter": "Required to use the 'fallback' adapter, and with league/flysystem-replicate-adapter, the 'mirror' adapter (^0.1)", + "mgriego/flysystem-clamav": "Scans files for viruses before storing them on an actual filesystem (^1.0)", + "mhetreramesh/flysystem-backblaze": "Required to use the 'backblaze' adapter (^1.1)", + "monster/flysystem-aliyun-oss": "One of the options to use the 'oss' adapter, but not recommended, since it uses the League namespace without being a Leage package (^1.0)", + "nao-pon/flysystem-google-drive": "One of the options to use the 'gdrive' adapter (^1.1)", + "nicolasbeauvais/flysystem-onedrive": "One of the options to use the 'onedrive' adapter (^1.0)", + "nimbusoft/flysystem-openstack-swift": "Required to use the 'openstack' adapter (^0.2)", + "orzcc/aliyun-oss": "One of the options to use the 'oss' adapter (dev-master)", + "overtrue/flysystem-qiniu": "One of the options to use the 'qiniu' adapter (^1.0)", + "phlib/flysystem-pdo": "One of the options to use the 'pdo' adapter (^1.1)", + "potherca/flysystem-github": "Required to use the 'github' adapter (^0.2)", + "private-it/flysystem-google-drive": "One of the options to use the 'gdrive' adapter (dev-master)", + "robgridley/flysystem-smb": "Required to use the 'smb' adapter (dev-master)", + "rokde/flysystem-local-database-adapter": "Required to use the 'eloquent' adapter (^0.0)", + "shion/aliyun-oss": "One of the options to use the 'oss' adapter (dev-master)", + "spatie/flysystem-dropbox": "Required to use the 'dropbox' adapter in PHP 7 (^1.0)", + "srmklive/flysystem-dropbox-v2": "Required to use the 'dropbox' adapter in PHP 5 (^1.0)", + "superbalist/flysystem-google-storage": "One of the options to use the 'google' adapter (^7.0)", + "t3chnik/flysystem-cloudinary-adapter": "One of the options to use the 'cloudinary' adapter (dev-master)", + "twistor/flysystem-guzzle": "One of the options to use the (read-only) 'http' adapter (^6.0)", + "twistor/flysystem-http": "One of the options to use the (read-only) 'http' adapter (^0.2)", + "twistor/flysystem-stream-wrapper": "Allows access to Flysystem drives using 'drive://path' streams (^1.0)", + "xxtime/flysystem-aliyun-oss": "One of the options to use the 'oss' adapter (^1.2)", + "zhuxiaoqiao/flysystem-baidu-bos": "Required to use the 'bos' adapter (^1.0)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + }, + "laravel": { + "providers": [ + "Danhunsaker\\Laravel\\Flysystem\\FlysystemOtherServiceProvider" + ], + "dont-discover": [ + "danhunsaker/laravel-flysystem-service" + ] + } + }, + "autoload": { + "psr-4": { + "Danhunsaker\\Laravel\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Hunsaker", + "email": "danhunsaker@gmail.com" + } + ], + "description": "Automatically registers every third-party Flysystem adapter it recognizes as a Laravel Filesystem Driver.", + "keywords": [ + "Flysystem", + "laravel" + ], + "time": "2018-08-16T11:20:15+00:00" + }, + { + "name": "danhunsaker/laravel-flysystem-service", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/danhunsaker/laravel-flysystem-service.git", + "reference": "0d077a0ddadc08e80fa2f152da2ee7aaaea37735" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danhunsaker/laravel-flysystem-service/zipball/0d077a0ddadc08e80fa2f152da2ee7aaaea37735", + "reference": "0d077a0ddadc08e80fa2f152da2ee7aaaea37735", + "shasum": "" + }, + "require": { + "illuminate/filesystem": "^5.0", + "illuminate/support": "^5.0", + "league/flysystem": "^1.0" + }, + "suggest": { + "league/flysystem-aws-s3-v3": "Required to use the 's3' adapter (^1.0)", + "league/flysystem-azure-blob-storage": "Required to use the 'azure' adapter (^1.0)", + "league/flysystem-cached-adapter": "Required to use metadata caching (^1.0)", + "league/flysystem-eventable-filesystem": "Required to hook into filesystem Events (^1.0)", + "league/flysystem-gridfs": "Required to use the 'gridfs' adapter (^1.0)", + "league/flysystem-memory": "Required to use the 'memory' adapter (^1.0)", + "league/flysystem-phpcr": "Required to use the 'phpcr' adapter (^1.0)", + "league/flysystem-rackspace": "Required to use the 'rackspace' adapter (^1.0)", + "league/flysystem-replicate-adapter": "Required to use the 'replicate' adapter (^1.0)", + "league/flysystem-sftp": "Required to use the 'sftp' adapter (^1.0)", + "league/flysystem-vfs": "Required to use the 'vfs' adapter (^1.0)", + "league/flysystem-webdav": "Required to use the 'webdav' adapter (^1.0)", + "league/flysystem-ziparchive": "Required to use the 'zip' adapter (^1.0)", + "madewithlove/illuminate-psr-cache-bridge": "Required to use Laravel's cache implementation for Flysystem caching (^1.0)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + }, + "laravel": { + "providers": [ + "Danhunsaker\\Laravel\\Flysystem\\FlysystemServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Danhunsaker\\Laravel\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Hunsaker", + "email": "danhunsaker@gmail.com" + } + ], + "description": "Automatically registers every Flysystem adapter it recognizes as a Laravel Filesystem Driver.", + "keywords": [ + "Flysystem", + "laravel" + ], + "time": "2018-08-13T22:27:45+00:00" }, { "name": "davejamesmiller/laravel-breadcrumbs", @@ -1732,6 +1904,94 @@ ], "time": "2018-09-14T15:30:29+00:00" }, + { + "name": "league/flysystem-replicate-adapter", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-replicate-adapter.git", + "reference": "864e80409c0918b0ed6921c3941247017d9db77c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-replicate-adapter/zipball/864e80409c0918b0ed6921c3941247017d9db77c", + "reference": "864e80409c0918b0ed6921c3941247017d9db77c", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\Replicate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Flysystem adapter for Replica's", + "time": "2015-08-18T21:07:17+00:00" + }, + { + "name": "league/flysystem-sftp", + "version": "1.0.16", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-sftp.git", + "reference": "322839636847e0dba0f714e9ad0db813d65efcf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-sftp/zipball/322839636847e0dba0f714e9ad0db813d65efcf2", + "reference": "322839636847e0dba0f714e9ad0db813d65efcf2", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "php": ">=5.6.0", + "phpseclib/phpseclib": "~2.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "^5.7.25" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Sftp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Flysystem adapter for SFTP", + "time": "2018-07-08T21:01:51+00:00" + }, { "name": "league/fractal", "version": "0.17.0", @@ -1866,6 +2126,47 @@ ], "time": "2018-06-23T16:57:59+00:00" }, + { + "name": "litipk/flysystem-fallback-adapter", + "version": "0.1.3", + "source": { + "type": "git", + "url": "https://github.com/Litipk/flysystem-fallback-adapter.git", + "reference": "1fdeb9352990deb8cba2a2c57cc94e2ff7e1381b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Litipk/flysystem-fallback-adapter/zipball/1fdeb9352990deb8cba2a2c57cc94e2ff7e1381b", + "reference": "1fdeb9352990deb8cba2a2c57cc94e2ff7e1381b", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Litipk\\Flysystem\\Fallback\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrés Correa Casablanca", + "email": "castarco@litipk.com" + } + ], + "description": "Flysystem adapter for fallback filesystems", + "time": "2016-06-23T00:18:01+00:00" + }, { "name": "monolog/monolog", "version": "1.23.0", diff --git a/config/filesystems.php b/config/filesystems.php index 1633b48e06..d08f7a3804 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -21,6 +21,21 @@ declare(strict_types=1); +$upload_disk = [ + 'driver' => 'mirror', + 'disks' => ['local-upload'], +]; + +$export_disk = [ + 'driver' => 'mirror', + 'disks' => ['local-upload'], +]; + +if ('' !== env('SFTP_HOST','') && '' !== env('SFTP_FIREFLY_ROOT','')) { + $upload_disk['disks'][] = "sftp-upload"; + $export_disk['disks'][] = "sftp-export"; +} + return [ @@ -59,7 +74,11 @@ return [ | may even configure multiple disks of the same driver. Defaults have | been setup for each driver as an example of the required options. | - | Supported Drivers: "local", "ftp", "s3", "rackspace" + | Supported: "local", "ftp", "s3", "rackspace", "null", "azure", "copy", + | "dropbox", "gridfs", "memory", "phpcr", "replicate", "sftp", + | "vfs", "webdav", "zip", "bos", "cloudinary", "eloquent", + | "fallback", "github", "gdrive", "google", "mirror", "onedrive", + | "oss", "qiniu", "redis", "runabove", "sae", "smb", "temp" | */ @@ -69,15 +88,16 @@ return [ 'driver' => 'local', 'root' => storage_path('app'), ], - - 'upload' => [ + + 'local-upload' => [ 'driver' => 'local', 'root' => storage_path('upload'), ], - 'export' => [ + 'local-export' => [ 'driver' => 'local', 'root' => storage_path('export'), ], + 'database' => [ 'driver' => 'local', 'root' => storage_path('database'), @@ -105,7 +125,377 @@ return [ 'region' => env('AWS_REGION'), 'bucket' => env('AWS_BUCKET'), ], + + 'sftp-upload' => [ + 'driver' => 'sftp', + 'host' => env('SFTP_HOST'), + 'port' => env('SFTP_PORT', 22), + 'username' => env('SFTP_USERNAME'), + 'password' => env('SFTP_PASSWORD'), + 'root' => env('SFTP_FIREFLY_ROOT') . '/upload', + // Optional SFTP Settings + // 'privateKey' => 'path/to/or/contents/of/privatekey', + // 'port' => 22, + // 'timeout' => 30, + // 'directoryPerm' => 0755, + // 'permPublic' => 0644, + // 'permPrivate' => 0600, + ], + + 'upload' => $upload_disk, + + 'sftp-export' => [ + 'driver' => 'sftp', + 'host' => env('SFTP_HOST'), + 'port' => env('SFTP_PORT', 22), + 'username' => env('SFTP_USERNAME'), + 'password' => env('SFTP_PASSWORD'), + 'root' => env('SFTP_FIREFLY_ROOT') . '/export', + // Optional SFTP Settings + // 'privateKey' => 'path/to/or/contents/of/privatekey', + // 'timeout' => 30, + // 'directoryPerm' => 0755, + // 'permPublic' => 0644, + // 'permPrivate' => 0600, + ], + + 'export' => $upload_export, + /* + 'sftp' => [ + 'driver' => 'sftp', + 'host' => 'sftp.example.com', + 'username' => 'username', + 'password' => 'password', + // Optional SFTP Settings + // 'privateKey' => 'path/to/or/contents/of/privatekey', + // 'port' => 22, + // 'root' => '/path/to/root', + // 'timeout' => 30, + // 'directoryPerm' => 0755, + // 'permPublic' => 0644, + // 'permPrivate' => 0600, + ], + + 'rackspace' => [ + 'driver' => 'rackspace', + 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', + 'username' => 'your-username', + 'key' => 'your-key', + 'region' => 'IAD', + 'url_type' => 'publicURL', + 'container' => 'your-container', + ], + + 'null' => [ + 'driver' => 'null', + ], + + 'azure' => [ + 'driver' => 'azure', + 'accountName' => 'your-account-name', + 'apiKey' => 'your-api-key', + 'container' => 'your-container', + ], + + 'gridfs' => [ + 'driver' => 'gridfs', + 'server' => 'your-server', + 'context' => 'your-context', + 'dbName' => 'your-db-name', + // You can also provide other MongoDB connection options here + ], + + 'memory' => [ + 'driver' => 'memory', + ], + + 'phpcr-jackrabbit' => [ + 'driver' => 'phpcr', + 'jackrabbit_url' => 'your-jackrabbit-url', + 'workspace' => 'your-workspace', + 'root' => 'your-root', + // Optional PHPCR Settings + // 'userId' => 'your-user-id', + // 'password' => 'your-password', + ], + + 'phpcr-dbal' => [ + 'driver' => 'phpcr', + 'database' => 'mysql', + 'workspace' => 'your-workspace', + 'root' => 'your-root', + // Optional PHPCR Settings + // 'userId' => 'your-user-id', + // 'password' => 'your-password', + ], + + 'phpcr-prismic' => [ + 'driver' => 'phpcr', + 'prismic_uri' => 'your-prismic-uri', + 'workspace' => 'your-workspace', + 'root' => 'your-root', + // Optional PHPCR Settings + // 'userId' => 'your-user-id', + // 'password' => 'your-password', + ], + + 'replicate' => [ + 'driver' => 'replicate', + 'master' => 'local', + 'replica' => 's3', + ], + + 'vfs' => [ + 'driver' => 'vfs', + ], + + 'webdav' => [ + 'driver' => 'webdav', + 'baseUri' => 'http://example.org/dav/', + // Optional WebDAV Settings + // 'userName' => 'user', + // 'password' => 'password', + // 'proxy' => 'locahost:8888', + // 'authType' => 'digest', // alternately 'ntlm' or 'basic' + // 'encoding' => 'all', // same as ['deflate', 'gzip', 'identity'] + ], + + 'zip' => [ + 'driver' => 'zip', + 'path' => 'path/to/file.zip', + // Alternate value if twistor/flysystem-stream-wrapper is available + // 'path' => 'local://path/to/file.zip', + ], + + 'backblaze' => [ + 'driver' => 'backblaze', + 'account_id' => 'your-account-id', + 'application_key' => 'your-app-key', + 'bucket' => 'your-bucket', + ], + + 'bos' => [ + 'driver' => 'bos', + 'credentials' => [ + 'ak' => 'your-access-key-id', + 'sk' => 'your-secret-access-key', + ], + 'bucket' => 'your-bucket', + // Optional BOS Settings + // 'endpoint' => 'http://bj.bcebos.com', + ], + + 'clamav' => [ + 'driver' => 'clamav', + 'server' => 'tcp://127.0.0.1:3310', + 'drive' => 'local', + // Optional ClamAV Settings + // 'copy_scan' => false, + ], + + 'cloudinary' => [ + 'driver' => 'cloudinary', + 'api_key' => env('CLOUDINARY_API_KEY'), + 'api_secret' => env('CLOUDINARY_API_SECRET'), + 'cloud_name' => env('CLOUDINARY_CLOUD_NAME'), + ], + + 'dropbox' => [ + 'driver' => 'dropbox', + 'authToken' => 'your-auth-token', + ], + + 'eloquent' => [ + 'driver' => 'eloquent', + // Optional Eloquent Settings + // 'model' => '\Rokde\Flysystem\Adapter\Model\FileModel', + ], + + 'fallback' => [ + 'driver' => 'fallback', + 'main' => 'local', + 'fallback' => 's3', + ], + + 'gdrive' => [ + 'driver' => 'gdrive', + 'client_id' => 'your-client-id', + 'secret' => 'your-secret', + 'token' => 'your-token', + // Optional GDrive Settings + // 'root' => 'your-root-directory', + // 'paths_sheet' => 'your-paths-sheet', + // 'paths_cache_drive' => 'local', + ], + + 'github' => [ + 'driver' => 'github', + 'project' => 'yourname/project', + 'token' => 'your-github-token', + ], + + 'google' => [ + 'driver' => 'google', + 'project_id' => 'your-project-id', + 'bucket' => 'your-bucket', + // Optional Google Cloud Storage Settings + // 'prefix' => 'prefix/path/for/drive', + // 'url' => 'http://your.custom.cname/', + // 'key_file' => 'path/to/file.json', + // + // Alternate value if twistor/flysystem-stream-wrapper is available + // 'key_file' => 'local://path/to/file.json', + ], + + 'http' => [ + 'driver' => 'http', + 'root' => 'http://example.com', + // Optional HTTP Settings + // 'use_head' => true, + // 'context' => [], + ], + + 'onedrive' => [ + 'driver' => 'onedrive', + 'access_token' => 'your-access-token', + // Options only needed for ignited/flysystem-onedrive + // 'base_url' => 'https://api.onedrive.com/v1.0/', + // 'use_logger' => false, + // Option only used by nicolasbeauvais/flysystem-onedrive + // 'root' => 'root', + ], + + 'openstack' => [ + 'driver' => 'openstack', + 'auth_url' => 'your-auth-url', + 'region' => 'your-region', + 'user_id' => 'your-user-id', + 'password' => 'your-password', + 'project_id' => 'your-project-id', + 'container' => 'your-container', + ], + + 'oss' => [ + 'driver' => 'oss', + 'access_id' => env('OSS_ACCESS_KEY_ID'), + 'access_key' => env('OSS_ACCESS_KEY_SECRET'), + 'endpoint' => env('OSS_ENDPOINT'), + 'bucket' => env('OSS_BUCKET'), + // Optional OSS Settings + // 'prefix' => '', + // 'region' => '', // One of 'hangzhou', 'qingdao', 'beijing', 'hongkong', + // // 'shenzhen', 'shanghai', 'west-1' and 'southeast-1' + ], + + 'pdo' => [ + 'driver' => 'pdo', + 'database' => 'default', + ], + + 'qcloud' => [ + 'driver' => 'qcloud', + 'app_id' => 'your-app-id', + 'secret_id' => 'your-secret-id', + 'secret_key' => 'your-secret-key', + 'bucket' => 'your-bucket-name', + 'protocol' => 'https', + // Optional Tencent/Qcloud COS Settings + // 'domain' => 'your-domain', + // 'timeout' => 60, + // 'region' => 'gz', + ], + + 'qiniu' => [ + 'driver' => 'qiniu', + 'accessKey' => 'your-access-key', + 'secretKey' => 'your-secret-key', + 'bucket' => 'your-bucket', + 'domain' => 'xxxx.qiniudn.com', + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + 'runabove' => [ + 'driver' => 'runabove', + 'username' => 'your-username', + 'password' => 'your-password', + 'tenantId' => 'your-tenantId', + // Optional Runabove Settings + // 'container' => 'container', + // 'region' => 'SBG1', // One of 'SBG1', 'BHS1', and 'GRA1' + ], + + 'selectel' => [ + 'driver' => 'selectel', + 'username' => 'your-username', + 'password' => 'your-password', + 'container' => 'your-container', + // Optional Selectel Settings + // 'domain' => '', + ], + + 'sharefile' => [ + 'driver' => 'sharefile', + 'hostname' => 'sharefile.example.com', + 'client_id' => 'your-client-id', + 'secret' => 'your-secret', + 'username' => 'your-username', + 'password' => 'your-password', + ], + + 'smb' => [ + 'driver' => 'smb', + 'host' => 'smb.example.com', + 'username' => 'your-username', + 'password' => 'your-password', + 'path' => 'path/to/shared/directory/for/root', + ], + + 'temp' => [ + 'driver' => 'temp', + // Optional TempDir Settings + // 'prefix' => '', + // 'tempdir' => '/tmp', + ], + + 'upyun' => [ + 'driver' => 'upyun', + 'bucket' => 'your-bucket', + 'operator' => 'operator-name', + 'password' => 'operator-password', + 'protocol' => 'https', + 'domain' => 'example.b0.upaiyun.com', + ], + + 'yandex' => [ + 'driver' => 'yandex', + 'access_token' => 'your-access-token', + // Optional Yandex Settings + // 'prefix' => 'app:/', + ], + */ ], - + + /* + |-------------------------------------------------------------------------- + | Automatically Register Stream Wrappers + |-------------------------------------------------------------------------- + | + | This is a list of the filesystem "disks" to automatically register the + | stream wrappers for on application start. Any "disk" you don't want to + | register on every application load will have to be manually referenced + | before attempting stream access, as the stream wrapper is otherwise only + | registered when used. + | + */ + /* + // Disabled, pending "twistor/flysystem-stream-wrapper" dependency + 'autowrap' => [ + 'local', + ], + */ ]; From 8fd6f8177f755da68b4e3ffb7a96968f5d544dd9 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 08:38:03 +0200 Subject: [PATCH 45/94] Update readme. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 0ba4bdc4e4..549a96c5b2 100644 --- a/readme.md +++ b/readme.md @@ -95,8 +95,8 @@ There are many ways to run Firefly III 1. There is a [demo site](https://demo.firefly-iii.org) with an example financial administration already present. 2. You can [install it on your server](https://firefly-iii.readthedocs.io/en/latest/installation/server.html). 3. You can [run it using Docker](https://firefly-iii.readthedocs.io/en/latest/installation/docker.html). -4. You can [deploy to Heroku](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master) -5. You can [deploy to Sandstorm.io](https://apps.sandstorm.io/app/uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70) +4. You can [deploy to Heroku](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master). Please read the [considerations when using Heroku](https://firefly-iii.readthedocs.io/en/latest/installation/hosted.html#considerations-when-using-heroku) first though. +5. You can [deploy to Sandstorm.io](https://apps.sandstorm.io/app/uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70). Note that you must have a paid Sandstorm account for this to work. 6. You can [install it using Softaculous](https://softaculous.com/). These guys even have made [another demo site](https://www.softaculous.com/softaculous/apps/others/Firefly_III)! 7. You can [install it using AMPPS](https://www.ampps.com/) 8. You can [install it with YunoHost](https://install-app.yunohost.org/?app=firefly-iii). From 5196bb9281e6dde6da9c1dcf7e6aa4168bca9bcb Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 08:38:11 +0200 Subject: [PATCH 46/94] Remove code climate configuration. --- .codeclimate.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index ce3bc33e17..0000000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -exclude_patterns: - - public/lib/ - - public/js/lib/ - - public/fonts/ - - public/css/jquery-ui/ - - public/css/bootstrap-multiselect.css - - public/css/bootstrap-sortable.css - - public/css/bootstrap-tagsinput.css - - public/css/daterangepicker.css - - public/css/google-fonts.css - - .sandstorm/ From 5b1153ab652233d48db92038437c2427c40d0635 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 08:40:10 +0200 Subject: [PATCH 47/94] Considerations on new line. --- readme.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 549a96c5b2..c20701fbae 100644 --- a/readme.md +++ b/readme.md @@ -95,8 +95,12 @@ There are many ways to run Firefly III 1. There is a [demo site](https://demo.firefly-iii.org) with an example financial administration already present. 2. You can [install it on your server](https://firefly-iii.readthedocs.io/en/latest/installation/server.html). 3. You can [run it using Docker](https://firefly-iii.readthedocs.io/en/latest/installation/docker.html). -4. You can [deploy to Heroku](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master). Please read the [considerations when using Heroku](https://firefly-iii.readthedocs.io/en/latest/installation/hosted.html#considerations-when-using-heroku) first though. -5. You can [deploy to Sandstorm.io](https://apps.sandstorm.io/app/uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70). Note that you must have a paid Sandstorm account for this to work. +4. You can [deploy to Heroku](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master). + + Please read the [considerations when using Heroku](https://firefly-iii.readthedocs.io/en/latest/installation/hosted.html#considerations-when-using-heroku) first though. +5. You can [deploy to Sandstorm.io](https://apps.sandstorm.io/app/uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70). + + Note that you must have a paid Sandstorm account for this to work, or you must self-host your Sandstorm server. 6. You can [install it using Softaculous](https://softaculous.com/). These guys even have made [another demo site](https://www.softaculous.com/softaculous/apps/others/Firefly_III)! 7. You can [install it using AMPPS](https://www.ampps.com/) 8. You can [install it with YunoHost](https://install-app.yunohost.org/?app=firefly-iii). From 53db8912d6c02fee01ffab0da9726f4d95bec954 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 08:53:00 +0200 Subject: [PATCH 48/94] Some mild refactoring for #1787 --- .env.example | 15 ++++++ config/filesystems.php | 106 ++++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 50 deletions(-) diff --git a/.env.example b/.env.example index 3a450e42b8..b5834c0238 100644 --- a/.env.example +++ b/.env.example @@ -49,6 +49,21 @@ DB_PASSWORD=secret CACHE_DRIVER=file SESSION_DRIVER=file +# You can configure another file storage backend if you cannot use the local storage option. +# To set this up, fill in the following variables. The upload path is used to store uploaded +# files and the export path is to store exported data (before download). +SFTP_HOST= +SFTP_PORT= +SFTP_UPLOAD_PATH= +SFTP_EXPORT_PATH= + +# SFTP uses either the username/password combination or the private key to authenticate. +SFTP_USERNAME= +SFTP_PASSWORD= +SFTP_PRIV_KEY= + + + # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= diff --git a/config/filesystems.php b/config/filesystems.php index d08f7a3804..83e95a4515 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -21,19 +21,20 @@ declare(strict_types=1); -$upload_disk = [ - 'driver' => 'mirror', - 'disks' => ['local-upload'], +$uploadDisk = [ + 'driver' => 'mirror', + 'disks' => ['local-upload'], ]; -$export_disk = [ - 'driver' => 'mirror', - 'disks' => ['local-upload'], +$exportDisk = [ + 'driver' => 'mirror', + 'disks' => ['local-upload'], ]; -if ('' !== env('SFTP_HOST','') && '' !== env('SFTP_FIREFLY_ROOT','')) { - $upload_disk['disks'][] = "sftp-upload"; - $export_disk['disks'][] = "sftp-export"; +// setting the SFTP host is enough to trigger the SFTP option. +if ('' !== env('SFTP_HOST', '')) { + $uploadDisk['disks'][] = 'sftp-upload'; + $exportDisk['disks'][] = 'sftp-export'; } @@ -83,21 +84,59 @@ return [ */ 'disks' => [ - 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), ], - - 'local-upload' => [ + + // local storage configuration for upload and export: + 'local-upload' => [ 'driver' => 'local', 'root' => storage_path('upload'), ], - 'local-export' => [ + 'local-export' => [ 'driver' => 'local', 'root' => storage_path('export'), ], + // SFTP storage configuration for upload and export: + 'sftp-upload' => [ + 'driver' => 'sftp', + 'host' => env('SFTP_HOST', '127.0.0.1'), + 'port' => env('SFTP_PORT', 22), + 'username' => env('SFTP_USERNAME', 'anonymous'), + 'password' => env('SFTP_PASSWORD', ''), + 'root' => env('SFTP_UPLOAD_PATH', ''), + 'privateKey' => env('SFTP_PRIV_KEY'), + + // Optional SFTP Settings + // 'timeout' => 30, + // 'directoryPerm' => 0755, + // 'permPublic' => 0644, + // 'permPrivate' => 0600, + ], + + 'sftp-export' => [ + 'driver' => 'sftp', + 'host' => env('SFTP_HOST', '127.0.0.1'), + 'port' => env('SFTP_PORT', 22), + 'username' => env('SFTP_USERNAME', 'anonymous'), + 'password' => env('SFTP_PASSWORD', ''), + 'root' => env('SFTP_EXPORT_PATH', ''), + 'privateKey' => env('SFTP_PRIV_KEY'), + + // Optional SFTP Settings + // 'timeout' => 30, + // 'directoryPerm' => 0755, + // 'permPublic' => 0644, + // 'permPrivate' => 0600, + ], + + // final configuration of upload disk and export disk. + 'upload' => $uploadDisk, + 'export' => $exportDisk, + + // various other paths: 'database' => [ 'driver' => 'local', 'root' => storage_path('database'), @@ -118,6 +157,9 @@ return [ 'visibility' => 'public', ], + // unused storage backends. + /* + 's3' => [ 'driver' => 's3', 'key' => env('AWS_KEY'), @@ -125,43 +167,7 @@ return [ 'region' => env('AWS_REGION'), 'bucket' => env('AWS_BUCKET'), ], - - 'sftp-upload' => [ - 'driver' => 'sftp', - 'host' => env('SFTP_HOST'), - 'port' => env('SFTP_PORT', 22), - 'username' => env('SFTP_USERNAME'), - 'password' => env('SFTP_PASSWORD'), - 'root' => env('SFTP_FIREFLY_ROOT') . '/upload', - // Optional SFTP Settings - // 'privateKey' => 'path/to/or/contents/of/privatekey', - // 'port' => 22, - // 'timeout' => 30, - // 'directoryPerm' => 0755, - // 'permPublic' => 0644, - // 'permPrivate' => 0600, - ], - - 'upload' => $upload_disk, - - 'sftp-export' => [ - 'driver' => 'sftp', - 'host' => env('SFTP_HOST'), - 'port' => env('SFTP_PORT', 22), - 'username' => env('SFTP_USERNAME'), - 'password' => env('SFTP_PASSWORD'), - 'root' => env('SFTP_FIREFLY_ROOT') . '/export', - // Optional SFTP Settings - // 'privateKey' => 'path/to/or/contents/of/privatekey', - // 'timeout' => 30, - // 'directoryPerm' => 0755, - // 'permPublic' => 0644, - // 'permPrivate' => 0600, - ], - - 'export' => $upload_export, - /* 'sftp' => [ 'driver' => 'sftp', 'host' => 'sftp.example.com', @@ -479,7 +485,7 @@ return [ ], */ ], - + /* |-------------------------------------------------------------------------- | Automatically Register Stream Wrappers From 2f1760f358da546c2c47d3b9a3517e0583cfee66 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 09:05:02 +0200 Subject: [PATCH 49/94] Sync up config files #1787 --- .env.docker | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-- .env.example | 2 -- .env.heroku | 57 +++++++++++++++++++++++++++++++++++++++++++++++ .env.sandstorm | 57 +++++++++++++++++++++++++++++++++++++++++++++++ .env.testing | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 4 deletions(-) diff --git a/.env.docker b/.env.docker index e492ce875e..0e98690fc7 100644 --- a/.env.docker +++ b/.env.docker @@ -43,12 +43,25 @@ DB_HOST=${FF_DB_HOST} DB_PORT=${FF_DB_PORT} DB_DATABASE=${FF_DB_NAME} DB_USERNAME=${FF_DB_USER} -DB_PASSWORD=${FF_DB_PASSWORD} +DB_PASSWORD="${FF_DB_PASSWORD}" # If you're looking for performance improvements, you could install memcached. CACHE_DRIVER=file SESSION_DRIVER=file +# You can configure another file storage backend if you cannot use the local storage option. +# To set this up, fill in the following variables. The upload path is used to store uploaded +# files and the export path is to store exported data (before download). +SFTP_HOST=${SFTP_HOST} +SFTP_PORT=${SFTP_PORT} +SFTP_UPLOAD_PATH=${SFTP_UPLOAD_PATH} +SFTP_EXPORT_PATH=${SFTP_EXPORT_PATH} + +# SFTP uses either the username/password combination or the private key to authenticate. +SFTP_USERNAME=${SFTP_USERNAME} +SFTP_PASSWORD="${SFTP_PASSWORD}" +SFTP_PRIV_KEY=${SFTP_PRIV_KEY} + # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= @@ -61,7 +74,7 @@ MAIL_HOST=${MAIL_HOST} MAIL_PORT=${MAIL_PORT} MAIL_FROM=${MAIL_FROM} MAIL_USERNAME=${MAIL_USERNAME} -MAIL_PASSWORD=${MAIL_PASSWORD} +MAIL_PASSWORD="${MAIL_PASSWORD}" MAIL_ENCRYPTION=${MAIL_ENCRYPTION} # Other mail drivers: @@ -92,9 +105,52 @@ ANALYTICS_ID=${ANALYTICS_ID} # This makes it easier to migrate your database. Not that some fields will never be decrypted. USE_ENCRYPTION=true +# Firefly III has two options for user authentication. "eloquent" is the default, +# and "adldap" for LDAP servers. +# For full instructions on these settings please visit: +# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html +LOGIN_PROVIDER=${LOGIN_PROVIDER} + +# LDAP connection configuration +ADLDAP_CONNECTION_SCHEME=${ADLDAP_CONNECTION_SCHEME} +ADLDAP_AUTO_CONNECT=${ADLDAP_AUTO_CONNECT} + +# LDAP connection settings +ADLDAP_CONTROLLERS=${ADLDAP_CONTROLLERS} +ADLDAP_PORT=${ADLDAP_PORT} +ADLDAP_TIMEOUT=${ADLDAP_TIMEOUT} +ADLDAP_BASEDN="${ADLDAP_BASEDN}" +ADLDAP_FOLLOW_REFFERALS=${ADLDAP_FOLLOW_REFFERALS} +ADLDAP_USE_SSL=${ADLDAP_USE_SSL} +ADLDAP_USE_TLS=${ADLDAP_USE_TLS} + +ADLDAP_ADMIN_USERNAME=${ADLDAP_ADMIN_USERNAME} +ADLDAP_ADMIN_PASSWORD="${ADLDAP_ADMIN_PASSWORD}" + +ADLDAP_ACCOUNT_PREFIX="${ADLDAP_ACCOUNT_PREFIX}" +ADLDAP_ACCOUNT_SUFFIX="${ADLDAP_ACCOUNT_SUFFIX}" +ADLDAP_ADMIN_ACCOUNT_PREFIX="${ADLDAP_ADMIN_ACCOUNT_PREFIX}" +ADLDAP_ADMIN_ACCOUNT_SUFFIX="${ADLDAP_ADMIN_ACCOUNT_SUFFIX}" + +# LDAP authentication settings. +ADLDAP_PASSWORD_SYNC=${ADLDAP_PASSWORD_SYNC} +ADLDAP_LOGIN_FALLBACK=${ADLDAP_LOGIN_FALLBACK} + +ADLDAP_SYNC_FIELD=${ADLDAP_SYNC_FIELD} +ADLDAP_DISCOVER_FIELD=${ADLDAP_DISCOVER_FIELD} +ADLDAP_AUTH_FIELD=${ADLDAP_AUTH_FIELD} + +# Will allow SSO if your server provides an AUTH_USER field. +WINDOWS_SSO_DISCOVER=${WINDOWS_SSO_DISCOVER} +WINDOWS_SSO_KEY=${WINDOWS_SSO_KEY} + +# field to sync as local username. +ADLDAP_SYNC_FIELD=${ADLDAP_SYNC_FIELD} + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. APP_NAME=FireflyIII +ADLDAP_CONNECTION=default BROADCAST_DRIVER=log QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 diff --git a/.env.example b/.env.example index b5834c0238..a5a2d85f48 100644 --- a/.env.example +++ b/.env.example @@ -62,8 +62,6 @@ SFTP_USERNAME= SFTP_PASSWORD= SFTP_PRIV_KEY= - - # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= diff --git a/.env.heroku b/.env.heroku index c4db28823b..426a8900ca 100644 --- a/.env.heroku +++ b/.env.heroku @@ -49,6 +49,19 @@ DB_CONNECTION=pgsql CACHE_DRIVER=file SESSION_DRIVER=file +# You can configure another file storage backend if you cannot use the local storage option. +# To set this up, fill in the following variables. The upload path is used to store uploaded +# files and the export path is to store exported data (before download). +SFTP_HOST= +SFTP_PORT= +SFTP_UPLOAD_PATH= +SFTP_EXPORT_PATH= + +# SFTP uses either the username/password combination or the private key to authenticate. +SFTP_USERNAME= +SFTP_PASSWORD= +SFTP_PRIV_KEY= + # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= @@ -73,6 +86,7 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=true + # These messages contain (sensitive) transaction information: SEND_REPORT_JOURNALS=true @@ -91,9 +105,52 @@ ANALYTICS_ID= # This makes it easier to migrate your database. Not that some fields will never be decrypted. USE_ENCRYPTION=true +# Firefly III has two options for user authentication. "eloquent" is the default, +# and "adldap" for LDAP servers. +# For full instructions on these settings please visit: +# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html +LOGIN_PROVIDER=eloquent + +# LDAP connection configuration +ADLDAP_CONNECTION_SCHEME=OpenLDAP # or FreeIPA or ActiveDirectory +ADLDAP_AUTO_CONNECT=true + +# LDAP connection settings +ADLDAP_CONTROLLERS= +ADLDAP_PORT=389 +ADLDAP_TIMEOUT=5 +ADLDAP_BASEDN="" +ADLDAP_FOLLOW_REFFERALS=false +ADLDAP_USE_SSL=false +ADLDAP_USE_TLS=false + +ADLDAP_ADMIN_USERNAME= +ADLDAP_ADMIN_PASSWORD= + +ADLDAP_ACCOUNT_PREFIX= +ADLDAP_ACCOUNT_SUFFIX= +ADLDAP_ADMIN_ACCOUNT_PREFIX= +ADLDAP_ADMIN_ACCOUNT_SUFFIX= + +# LDAP authentication settings. +ADLDAP_PASSWORD_SYNC=false +ADLDAP_LOGIN_FALLBACK=false + +ADLDAP_SYNC_FIELD=userprincipalname +ADLDAP_DISCOVER_FIELD=distinguishedname +ADLDAP_AUTH_FIELD=distinguishedname + +# Will allow SSO if your server provides an AUTH_USER field. +WINDOWS_SSO_DISCOVER=samaccountname +WINDOWS_SSO_KEY=AUTH_USER + +# field to sync as local username. +ADLDAP_SYNC_FIELD=uid + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. APP_NAME=FireflyIII +ADLDAP_CONNECTION=default BROADCAST_DRIVER=log QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 diff --git a/.env.sandstorm b/.env.sandstorm index aa7b70b1ff..83062e9530 100755 --- a/.env.sandstorm +++ b/.env.sandstorm @@ -49,6 +49,19 @@ DB_PASSWORD=firefly CACHE_DRIVER=file SESSION_DRIVER=file +# You can configure another file storage backend if you cannot use the local storage option. +# To set this up, fill in the following variables. The upload path is used to store uploaded +# files and the export path is to store exported data (before download). +SFTP_HOST= +SFTP_PORT= +SFTP_UPLOAD_PATH= +SFTP_EXPORT_PATH= + +# SFTP uses either the username/password combination or the private key to authenticate. +SFTP_USERNAME= +SFTP_PASSWORD= +SFTP_PRIV_KEY= + # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= @@ -73,6 +86,7 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=true + # These messages contain (sensitive) transaction information: SEND_REPORT_JOURNALS=true @@ -91,9 +105,52 @@ ANALYTICS_ID= # This makes it easier to migrate your database. Not that some fields will never be decrypted. USE_ENCRYPTION=true +# Firefly III has two options for user authentication. "eloquent" is the default, +# and "adldap" for LDAP servers. +# For full instructions on these settings please visit: +# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html +LOGIN_PROVIDER=eloquent + +# LDAP connection configuration +ADLDAP_CONNECTION_SCHEME=OpenLDAP # or FreeIPA or ActiveDirectory +ADLDAP_AUTO_CONNECT=true + +# LDAP connection settings +ADLDAP_CONTROLLERS= +ADLDAP_PORT=389 +ADLDAP_TIMEOUT=5 +ADLDAP_BASEDN="" +ADLDAP_FOLLOW_REFFERALS=false +ADLDAP_USE_SSL=false +ADLDAP_USE_TLS=false + +ADLDAP_ADMIN_USERNAME= +ADLDAP_ADMIN_PASSWORD= + +ADLDAP_ACCOUNT_PREFIX= +ADLDAP_ACCOUNT_SUFFIX= +ADLDAP_ADMIN_ACCOUNT_PREFIX= +ADLDAP_ADMIN_ACCOUNT_SUFFIX= + +# LDAP authentication settings. +ADLDAP_PASSWORD_SYNC=false +ADLDAP_LOGIN_FALLBACK=false + +ADLDAP_SYNC_FIELD=userprincipalname +ADLDAP_DISCOVER_FIELD=distinguishedname +ADLDAP_AUTH_FIELD=distinguishedname + +# Will allow SSO if your server provides an AUTH_USER field. +WINDOWS_SSO_DISCOVER=samaccountname +WINDOWS_SSO_KEY=AUTH_USER + +# field to sync as local username. +ADLDAP_SYNC_FIELD=uid + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. APP_NAME=FireflyIII +ADLDAP_CONNECTION=default BROADCAST_DRIVER=log QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 diff --git a/.env.testing b/.env.testing index 67757f6e23..312d28a9ec 100644 --- a/.env.testing +++ b/.env.testing @@ -49,6 +49,19 @@ DB_CONNECTION=sqlite CACHE_DRIVER=file SESSION_DRIVER=file +# You can configure another file storage backend if you cannot use the local storage option. +# To set this up, fill in the following variables. The upload path is used to store uploaded +# files and the export path is to store exported data (before download). +SFTP_HOST= +SFTP_PORT= +SFTP_UPLOAD_PATH= +SFTP_EXPORT_PATH= + +# SFTP uses either the username/password combination or the private key to authenticate. +SFTP_USERNAME= +SFTP_PASSWORD= +SFTP_PRIV_KEY= + # Cookie settings. Should not be necessary to change these. COOKIE_PATH="/" COOKIE_DOMAIN= @@ -73,6 +86,7 @@ SPARKPOST_SECRET= # Firefly III can send you the following messages SEND_REGISTRATION_MAIL=true SEND_ERROR_MESSAGE=false + # These messages contain (sensitive) transaction information: SEND_REPORT_JOURNALS=true @@ -91,9 +105,52 @@ ANALYTICS_ID= # This makes it easier to migrate your database. Not that some fields will never be decrypted. USE_ENCRYPTION=false +# Firefly III has two options for user authentication. "eloquent" is the default, +# and "adldap" for LDAP servers. +# For full instructions on these settings please visit: +# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html +LOGIN_PROVIDER=eloquent + +# LDAP connection configuration +ADLDAP_CONNECTION_SCHEME=OpenLDAP # or FreeIPA or ActiveDirectory +ADLDAP_AUTO_CONNECT=true + +# LDAP connection settings +ADLDAP_CONTROLLERS= +ADLDAP_PORT=389 +ADLDAP_TIMEOUT=5 +ADLDAP_BASEDN="" +ADLDAP_FOLLOW_REFFERALS=false +ADLDAP_USE_SSL=false +ADLDAP_USE_TLS=false + +ADLDAP_ADMIN_USERNAME= +ADLDAP_ADMIN_PASSWORD= + +ADLDAP_ACCOUNT_PREFIX= +ADLDAP_ACCOUNT_SUFFIX= +ADLDAP_ADMIN_ACCOUNT_PREFIX= +ADLDAP_ADMIN_ACCOUNT_SUFFIX= + +# LDAP authentication settings. +ADLDAP_PASSWORD_SYNC=false +ADLDAP_LOGIN_FALLBACK=false + +ADLDAP_SYNC_FIELD=userprincipalname +ADLDAP_DISCOVER_FIELD=distinguishedname +ADLDAP_AUTH_FIELD=distinguishedname + +# Will allow SSO if your server provides an AUTH_USER field. +WINDOWS_SSO_DISCOVER=samaccountname +WINDOWS_SSO_KEY=AUTH_USER + +# field to sync as local username. +ADLDAP_SYNC_FIELD=uid + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. APP_NAME=FireflyIII +ADLDAP_CONNECTION=default BROADCAST_DRIVER=log QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 From ac6c3496d43a6270ee13e3e0a5521b81cdfb85c4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 11:42:49 +0200 Subject: [PATCH 50/94] Fix LDAP in Dockerfile. --- Dockerfile | 8 +++++--- composer.lock | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 27d2734c21..adbe63bd93 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,9 @@ ENV CORES ${CORES:-1} ENV FIREFLY_PATH /var/www/firefly-iii/ ENV CURL_VERSION 7.60.0 ENV OPENSSL_VERSION 1.1.1-pre6 +ENV COMPOSER_ALLOW_SUPERUSER 1 -LABEL version="1.0" maintainer="thegrumpydictator@gmail.com" - +LABEL version="1.1" maintainer="thegrumpydictator@gmail.com" # install packages RUN apt-get update -y && \ @@ -20,6 +20,7 @@ RUN apt-get update -y && \ wget \ libpng-dev \ libicu-dev \ + libldap2-dev \ libedit-dev \ libtidy-dev \ libxml2-dev \ @@ -35,6 +36,8 @@ RUN apt-get update -y && \ locales && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* +# LDAP install +RUN docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && docker-php-ext-install ldap # Install latest curl RUN cd /tmp && \ @@ -107,7 +110,6 @@ ADD . $FIREFLY_PATH RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4 # Run composer -ENV COMPOSER_ALLOW_SUPERUSER 1 RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest # Expose port 80 diff --git a/composer.lock b/composer.lock index 5ada4c8269..aa4ebbba92 100644 --- a/composer.lock +++ b/composer.lock @@ -219,7 +219,7 @@ "payment", "sepa" ], - "time": "2018-09-01T12:54:04+00:00" + "time": "2018-10-05T13:50:22+00:00" }, { "name": "danhunsaker/laravel-flysystem-others", From 26c03552c6908d08ab7cf67927de23335c4487b8 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 14:38:13 +0200 Subject: [PATCH 51/94] Fix for #1159 --- app/Support/Import/Routine/FinTS/StageImportDataHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php index 89095dac35..1a5c1a911e 100644 --- a/app/Support/Import/Routine/FinTS/StageImportDataHandler.php +++ b/app/Support/Import/Routine/FinTS/StageImportDataHandler.php @@ -69,7 +69,7 @@ class StageImportDataHandler { Log::debug('Now in StageImportDataHandler::run()'); - $localAccount = $this->accountRepository->findNull($this->importJob->configuration['local_account']); + $localAccount = $this->accountRepository->findNull((int)$this->importJob->configuration['local_account']); if (null === $localAccount) { throw new FireflyException(sprintf('Cannot find Firefly account with id #%d ' , $this->importJob->configuration['local_account'])); } From 4e9456b33b900eac9c35b8bc1baae84abeba6176 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 14:49:03 +0200 Subject: [PATCH 52/94] Make SFTP primary. --- config/filesystems.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/filesystems.php b/config/filesystems.php index 83e95a4515..db7a7286df 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -33,11 +33,10 @@ $exportDisk = [ // setting the SFTP host is enough to trigger the SFTP option. if ('' !== env('SFTP_HOST', '')) { - $uploadDisk['disks'][] = 'sftp-upload'; - $exportDisk['disks'][] = 'sftp-export'; + array_unshift($uploadDisk['disks'], 'sftp-upload'); + array_unshift($exportDisk['disks'], 'sftp-upload'); } - return [ /* From 20bebeb7decb88a44a3f93135ee253cc154dd79f Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 16:27:26 +0200 Subject: [PATCH 53/94] Fix in file system configuration [skip ci] --- config/filesystems.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/filesystems.php b/config/filesystems.php index db7a7286df..67e8165fc4 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -34,7 +34,7 @@ $exportDisk = [ // setting the SFTP host is enough to trigger the SFTP option. if ('' !== env('SFTP_HOST', '')) { array_unshift($uploadDisk['disks'], 'sftp-upload'); - array_unshift($exportDisk['disks'], 'sftp-upload'); + array_unshift($exportDisk['disks'], 'sftp-export'); } return [ From d624f20107a4067cd5665065be4a61537b91c6da Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 16:40:12 +0200 Subject: [PATCH 54/94] Fixes for #1747 --- app/Console/Commands/ApplyRules.php | 106 ++++++++++++------ ...ExecuteRuleGroupOnExistingTransactions.php | 15 +-- 2 files changed, 82 insertions(+), 39 deletions(-) diff --git a/app/Console/Commands/ApplyRules.php b/app/Console/Commands/ApplyRules.php index 8569c149be..72fde55db6 100644 --- a/app/Console/Commands/ApplyRules.php +++ b/app/Console/Commands/ApplyRules.php @@ -6,6 +6,7 @@ use Carbon\Carbon; use FireflyIII\Helpers\Collector\TransactionCollectorInterface; use FireflyIII\Models\AccountType; use FireflyIII\Models\Rule; +use FireflyIII\Models\RuleGroup; use FireflyIII\Models\Transaction; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; @@ -49,6 +50,10 @@ class ApplyRules extends Command /** @var Carbon */ private $endDate; /** @var Collection */ + private $results; + /** @var Collection */ + private $ruleGroups; + /** @var Collection */ private $rules; /** @var Carbon */ private $startDate; @@ -61,8 +66,10 @@ class ApplyRules extends Command public function __construct() { parent::__construct(); - $this->accounts = new Collection; - $this->rules = new Collection; + $this->accounts = new Collection; + $this->rules = new Collection; + $this->ruleGroups = new Collection; + $this->results = new Collection; } /** @@ -84,6 +91,7 @@ class ApplyRules extends Command return 1; } + // get transactions from asset accounts. /** @var TransactionCollectorInterface $collector */ $collector = app(TransactionCollectorInterface::class); @@ -92,40 +100,40 @@ class ApplyRules extends Command $collector->setRange($this->startDate, $this->endDate); $transactions = $collector->getTransactions(); $count = $transactions->count(); - $bar = $this->output->createProgressBar($count * $this->rules->count()); - $results = new Collection; - $this->line(sprintf('Will apply %d rules to %d transactions', $this->rules->count(), $transactions->count())); + // first run all rule groups: + /** @var RuleGroupRepositoryInterface $ruleGroupRepos */ + $ruleGroupRepos = app(RuleGroupRepositoryInterface::class); + $ruleGroupRepos->setUser($this->getUser()); - foreach ($this->rules as $rule) { - /** @var Processor $processor */ - $processor = app(Processor::class); - $processor->make($rule, true); - - /** @var Transaction $transaction */ - foreach ($transactions as $transaction) { - /** @var Rule $rule */ - $bar->advance(); - $result = $processor->handleTransaction($transaction); - if (true === $result) { - $results->push($transaction); - } - } + /** @var RuleGroup $ruleGroup */ + foreach ($this->ruleGroups as $ruleGroup) { + $this->line(sprintf('Going to apply rule group "%s" to %d transaction(s).', $ruleGroup->title, $count)); + $rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup); + $this->applyRuleSelection($rules, $transactions, true); } - $results = $results->unique( + + // then run all rules (rule groups should be empty). + if ($this->rules->count() > 0) { + + $this->line(sprintf('Will apply %d rule(s) to %d transaction(s)', $this->rules->count(), $transactions->count())); + $this->applyRuleSelection($this->rules, $transactions, false); + } + + // filter results: + $this->results = $this->results->unique( function (Transaction $transaction) { return (int)$transaction->journal_id; } ); - $bar->finish(); $this->line(''); - if (0 === \count($results)) { + if (0 === $this->results->count()) { $this->line('The rules were fired but did not influence any transactions.'); } - if (\count($results) > 0) { - $this->line(sprintf('The rules were fired, and influences %d transaction(s).', \count($results))); - foreach ($results as $result) { + if ($this->results->count() > 0) { + $this->line(sprintf('The rule(s) was/were fired, and influenced %d transaction(s).', $this->results->count())); + foreach ($this->results as $result) { $this->line( vsprintf( 'Transaction #%d: "%s" (%s %s)', @@ -143,6 +151,40 @@ class ApplyRules extends Command return 0; } + /** + * @param Collection $rules + * @param Collection $transactions + * @param bool $breakProcessing + * + * @throws \FireflyIII\Exceptions\FireflyException + */ + private function applyRuleSelection(Collection $rules, Collection $transactions, bool $breakProcessing): void + { + $bar = $this->output->createProgressBar($rules->count() * $transactions->count()); + foreach ($rules as $rule) { + /** @var Processor $processor */ + $processor = app(Processor::class); + $processor->make($rule, true); + + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + /** @var Rule $rule */ + $bar->advance(); + $result = $processor->handleTransaction($transaction); + if (true === $result) { + $this->results->push($transaction); + } + } + if (true === $rule->stop_processing && true === $breakProcessing) { + $this->line(''); + $this->line(sprintf('Rule #%d ("%s") says to stop processing.', $rule->id, $rule->title)); + + return; + } + } + $this->line(''); + } + /** * */ @@ -153,6 +195,9 @@ class ApplyRules extends Command $ruleRepos = app(RuleRepositoryInterface::class); $ruleRepos->setUser($this->getUser()); $this->rules = $ruleRepos->getAll(); + + // reset rule groups. + $this->ruleGroups = new Collection; } } @@ -284,7 +329,6 @@ class ApplyRules extends Command // can be empty. return true; } - $finalList = new Collection; $ruleGroupList = explode(',', $ruleGroupString); if (0 === \count($ruleGroupList)) { @@ -299,12 +343,8 @@ class ApplyRules extends Command foreach ($ruleGroupList as $ruleGroupId) { $ruleGroupId = (int)$ruleGroupId; $ruleGroup = $ruleGroupRepos->find($ruleGroupId); - if (null !== $ruleGroup) { - $rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup); - $finalList = $finalList->merge($rules); - } + $this->ruleGroups->push($ruleGroup); } - $this->rules = $finalList; return true; } @@ -340,7 +380,9 @@ class ApplyRules extends Command } } if ($finalList->count() > 0) { - $this->rules = $finalList; + // reset rule groups. + $this->ruleGroups = new Collection; + $this->rules = $finalList; } return true; diff --git a/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php b/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php index f6901a6f3f..ec1931df95 100644 --- a/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php +++ b/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php @@ -154,15 +154,15 @@ class ExecuteRuleGroupOnExistingTransactions extends Job implements ShouldQueue $processors = $this->collectProcessors(); // Execute the rules for each transaction - foreach ($transactions as $transaction) { - /** @var Processor $processor */ - foreach ($processors as $processor) { + foreach ($processors as $processor) { + foreach ($transactions as $transaction) { + /** @var Processor $processor */ $processor->handleTransaction($transaction); - // Stop processing this group if the rule specifies 'stop_processing' - if ($processor->getRule()->stop_processing) { - break; - } + } + // Stop processing this group if the rule specifies 'stop_processing' + if ($processor->getRule()->stop_processing) { + break; } } } @@ -203,6 +203,7 @@ class ExecuteRuleGroupOnExistingTransactions extends Job implements ShouldQueue /** @var Processor $processor */ $processor = app(Processor::class); $processor->make($rule); + return $processor; }, $rules->all() From 329b34f7d137f259cc065cce1c6f1b12080ec994 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 16:54:11 +0200 Subject: [PATCH 55/94] Fix for #1760 --- .../Report/Tag/MonthReportGenerator.php | 3 +- .../Collector/TransactionCollector.php | 90 +++++++++---------- .../Filter/DoubleTransactionFilter.php | 60 +++++++++++++ 3 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 app/Helpers/Filter/DoubleTransactionFilter.php diff --git a/app/Generator/Report/Tag/MonthReportGenerator.php b/app/Generator/Report/Tag/MonthReportGenerator.php index 2b6e3d067d..5f6de0bbc9 100644 --- a/app/Generator/Report/Tag/MonthReportGenerator.php +++ b/app/Generator/Report/Tag/MonthReportGenerator.php @@ -29,6 +29,7 @@ use Carbon\Carbon; use FireflyIII\Generator\Report\ReportGeneratorInterface; use FireflyIII\Generator\Report\Support; use FireflyIII\Helpers\Collector\TransactionCollectorInterface; +use FireflyIII\Helpers\Filter\DoubleTransactionFilter; use FireflyIII\Helpers\Filter\NegativeAmountFilter; use FireflyIII\Helpers\Filter\OpposingAccountFilter; use FireflyIII\Helpers\Filter\PositiveAmountFilter; @@ -216,9 +217,9 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface ->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]) ->setTags($this->tags)->withOpposingAccount(); $collector->removeFilter(TransferFilter::class); - $collector->addFilter(OpposingAccountFilter::class); $collector->addFilter(PositiveAmountFilter::class); + $collector->addFilter(DoubleTransactionFilter::class); $transactions = $collector->getTransactions(); $this->expenses = $transactions; diff --git a/app/Helpers/Collector/TransactionCollector.php b/app/Helpers/Collector/TransactionCollector.php index 5e7456b938..46c4b200a2 100644 --- a/app/Helpers/Collector/TransactionCollector.php +++ b/app/Helpers/Collector/TransactionCollector.php @@ -28,6 +28,7 @@ use Carbon\Carbon; use DB; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Filter\CountAttachmentsFilter; +use FireflyIII\Helpers\Filter\DoubleTransactionFilter; use FireflyIII\Helpers\Filter\FilterInterface; use FireflyIII\Helpers\Filter\InternalTransferFilter; use FireflyIII\Helpers\Filter\NegativeAmountFilter; @@ -53,26 +54,14 @@ use Log; /** * Class TransactionCollector * - * @codeCoverageIgnore + * @codeCoverageIgnore */ class TransactionCollector implements TransactionCollectorInterface { - /** - * Constructor. - */ - public function __construct() - { - if ('testing' === env('APP_ENV')) { - Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this))); - } - } - - /** @var array */ private $accountIds = []; /** @var int */ private $count = 0; - /** @var array */ private $fields = [ @@ -139,6 +128,16 @@ class TransactionCollector implements TransactionCollectorInterface /** @var User */ private $user; + /** + * Constructor. + */ + public function __construct() + { + if ('testing' === env('APP_ENV')) { + Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this))); + } + } + /** * @param string $filter * @@ -253,6 +252,30 @@ class TransactionCollector implements TransactionCollectorInterface return $this->count; } + /** + * @return LengthAwarePaginator + * @throws FireflyException + */ + public function getPaginatedTransactions(): LengthAwarePaginator + { + if (true === $this->run) { + throw new FireflyException('Cannot getPaginatedTransactions after run in TransactionCollector.'); + } + $this->count(); + $set = $this->getTransactions(); + $journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page); + + return $journals; + } + + /** + * @return EloquentBuilder + */ + public function getQuery(): EloquentBuilder + { + return $this->query; + } + /** * @return Collection */ @@ -309,30 +332,6 @@ class TransactionCollector implements TransactionCollectorInterface return $set; } - /** - * @return LengthAwarePaginator - * @throws FireflyException - */ - public function getPaginatedTransactions(): LengthAwarePaginator - { - if (true === $this->run) { - throw new FireflyException('Cannot getPaginatedTransactions after run in TransactionCollector.'); - } - $this->count(); - $set = $this->getTransactions(); - $journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page); - - return $journals; - } - - /** - * @return EloquentBuilder - */ - public function getQuery(): EloquentBuilder - { - return $this->query; - } - /** * @return TransactionCollectorInterface */ @@ -784,14 +783,15 @@ class TransactionCollector implements TransactionCollectorInterface { // create all possible filters: $filters = [ - InternalTransferFilter::class => new InternalTransferFilter($this->accountIds), - OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds), - TransferFilter::class => new TransferFilter, - PositiveAmountFilter::class => new PositiveAmountFilter, - NegativeAmountFilter::class => new NegativeAmountFilter, - SplitIndicatorFilter::class => new SplitIndicatorFilter, - CountAttachmentsFilter::class => new CountAttachmentsFilter, - TransactionViewFilter::class => new TransactionViewFilter, + InternalTransferFilter::class => new InternalTransferFilter($this->accountIds), + OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds), + TransferFilter::class => new TransferFilter, + PositiveAmountFilter::class => new PositiveAmountFilter, + NegativeAmountFilter::class => new NegativeAmountFilter, + SplitIndicatorFilter::class => new SplitIndicatorFilter, + CountAttachmentsFilter::class => new CountAttachmentsFilter, + TransactionViewFilter::class => new TransactionViewFilter, + DoubleTransactionFilter::class => new DoubleTransactionFilter, ]; Log::debug(sprintf('Will run %d filters on the set.', \count($this->filters))); foreach ($this->filters as $enabled) { diff --git a/app/Helpers/Filter/DoubleTransactionFilter.php b/app/Helpers/Filter/DoubleTransactionFilter.php new file mode 100644 index 0000000000..ce35b22c60 --- /dev/null +++ b/app/Helpers/Filter/DoubleTransactionFilter.php @@ -0,0 +1,60 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Helpers\Filter; + + +use FireflyIII\Models\Transaction; +use Illuminate\Support\Collection; + +/** + * + * Used when the final collection contains double transactions, which can happen when viewing the tag report. + * Class DoubleTransactionFilter + */ +class DoubleTransactionFilter implements FilterInterface +{ + + /** + * Apply the filter. + * + * @param Collection $set + * + * @return Collection + */ + public function filter(Collection $set): Collection + { + $count = []; + $result = new Collection; + /** @var Transaction $transaction */ + foreach ($set as $transaction) { + $id = (int)$transaction->id; + $count[$id] = isset($count[$id]) ? $count[$id] + 1 : 1; + if (1 === $count[$id]) { + $result->push($transaction); + } + } + + return $result; + } +} \ No newline at end of file From db7e3d725e519c4f420eadcc42919989cb538df2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 14 Oct 2018 17:38:26 +0200 Subject: [PATCH 56/94] Fix for #1781 --- app/Http/Requests/RuleFormRequest.php | 29 ++++++++-------- app/Validation/FireflyValidator.php | 4 +-- config/firefly.php | 50 +++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/app/Http/Requests/RuleFormRequest.php b/app/Http/Requests/RuleFormRequest.php index 40df4da5d8..acca6dba81 100644 --- a/app/Http/Requests/RuleFormRequest.php +++ b/app/Http/Requests/RuleFormRequest.php @@ -75,32 +75,31 @@ class RuleFormRequest extends Request $validTriggers = array_keys(config('firefly.rule-triggers')); $validActions = array_keys(config('firefly.rule-actions')); - // some actions require text: - $contextActions = implode(',', config('firefly.rule-actions-text')); + // some actions require text (aka context): + $contextActions = implode(',', config('firefly.context-rule-actions')); - $titleRule = 'required|between:1,100|uniqueObjectForUser:rules,title'; - /** @var Rule $rule */ - $rule = $this->route()->parameter('rule'); + // some triggers require text (aka context): + $contextTriggers = implode(',', config('firefly.context-rule-triggers')); - if (null !== $rule) { - $titleRule = 'required|between:1,100|uniqueObjectForUser:rules,title,' . $rule->id; - } + // initial set of rules: $rules = [ - 'title' => $titleRule, + 'title' => 'required|between:1,100|uniqueObjectForUser:rules,title', 'description' => 'between:1,5000|nullable', 'stop_processing' => 'boolean', 'rule_group_id' => 'required|belongsToUser:rule_groups', 'trigger' => 'required|in:store-journal,update-journal', 'rule_triggers.*.name' => 'required|in:' . implode(',', $validTriggers), - 'rule_triggers.*.value' => 'required|min:1|ruleTriggerValue', + 'rule_triggers.*.value' => sprintf('required_if:rule_triggers.*.name,%s|min:1|ruleTriggerValue', $contextTriggers), 'rule-actions.*.name' => 'required|in:' . implode(',', $validActions), + 'rule_actions.*.value' => sprintf('required_if:rule_actions.*.name,%s|min:1|ruleActionValue', $contextActions), 'strict' => 'in:0,1', ]; - // since Laravel does not support this stuff yet, here's a trick. - for ($i = 0; $i < 10; ++$i) { - $key = sprintf('rule_actions.%d.value', $i); - $rule = sprintf('required-if:rule_actions.%d.name,%s|ruleActionValue', $i, $contextActions); - $rules[$key] = $rule; + + /** @var Rule $rule */ + $rule = $this->route()->parameter('rule'); + + if (null !== $rule) { + $rules['title'] = 'required|between:1,100|uniqueObjectForUser:rules,title,' . $rule->id; } return $rules; diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index 1c62516695..cc4766ed26 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -313,10 +313,8 @@ class FireflyValidator extends Validator * * @return bool */ - public function validateRuleTriggerValue(string $attribute, string $value): bool + public function validateRuleTriggerValue(string $attribute, string $value = null): bool { - // - // first, get the index from this string: $parts = explode('.', $attribute); $index = (int)($parts[1] ?? '0'); diff --git a/config/firefly.php b/config/firefly.php index d8811e0999..fa6f94ec9c 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -375,23 +375,59 @@ return [ 'convert_deposit' => ConvertToDeposit::class, 'convert_transfer' => ConvertToTransfer::class, ], - 'rule-actions-text' => [ + 'context-rule-actions' => [ 'set_category', 'set_budget', 'add_tag', 'remove_tag', - 'link_to_bill', 'set_description', 'append_description', 'prepend_description', + 'set_source_account', + 'set_destination_account', + 'set_notes', + 'append_notes', + 'prepend_notes', + 'link_to_bill', + 'convert_withdrawal', + 'convert_deposit', + 'convert_transfer', ], - 'test-triggers' => [ + 'context-rule-triggers' => [ + 'from_account_starts', + 'from_account_ends', + 'from_account_is', + 'from_account_contains', + 'to_account_starts', + 'to_account_ends', + 'to_account_is', + 'to_account_contains', + 'amount_less', + 'amount_exactly', + 'amount_more', + 'description_starts', + 'description_ends', + 'description_contains', + 'description_is', + 'transaction_type', + 'category_is', + 'budget_is', + 'tag_is', + 'currency_is', + 'notes_contain', + 'notes_start', + 'notes_end', + 'notes_are', + ], + + + 'test-triggers' => [ 'limit' => 10, 'range' => 200, ], - 'default_currency' => 'EUR', - 'default_language' => 'en_US', - 'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category', - 'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after'], + 'default_currency' => 'EUR', + 'default_language' => 'en_US', + 'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category', + 'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after'], // tag notes has_attachments ]; From 1653152dad12c313c1873b16c45269d2bf1784fd Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 15 Oct 2018 19:37:18 +0200 Subject: [PATCH 57/94] Fix for #1792 --- resources/lang/en_US/firefly.php | 1 + resources/views/reports/default/multi-year.twig | 5 +++++ resources/views/reports/default/year.twig | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 1c53b1c8b1..69bbef66d1 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1023,6 +1023,7 @@ return [ 'select_expense_revenue' => 'Select expense/revenue account', 'multi_currency_report_sum' => 'Because this list contains accounts with multiple currencies, the sum(s) you see may not make sense. The report will always fall back to your default currency.', 'sum_in_default_currency' => 'The sum will always be in your default currency.', + 'net_filtered_prefs' => 'This chart will never include accounts that have the "Include in net worth"-option unchecked.', // charts: 'chart' => 'Chart', diff --git a/resources/views/reports/default/multi-year.twig b/resources/views/reports/default/multi-year.twig index 5cf206ed6e..79da237b46 100644 --- a/resources/views/reports/default/multi-year.twig +++ b/resources/views/reports/default/multi-year.twig @@ -101,6 +101,11 @@
+
diff --git a/resources/views/reports/default/year.twig b/resources/views/reports/default/year.twig index fa702a12e4..fd75fea823 100644 --- a/resources/views/reports/default/year.twig +++ b/resources/views/reports/default/year.twig @@ -100,6 +100,11 @@
+ From 9b46e62eb6c33b8f95e9d833cbb48b5de521fd5f Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 16 Oct 2018 21:42:08 +0200 Subject: [PATCH 58/94] match api end point with config changes. --- app/Api/V1/Requests/RuleRequest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Api/V1/Requests/RuleRequest.php b/app/Api/V1/Requests/RuleRequest.php index f8e50e4da2..95f2316abf 100644 --- a/app/Api/V1/Requests/RuleRequest.php +++ b/app/Api/V1/Requests/RuleRequest.php @@ -75,8 +75,10 @@ class RuleRequest extends Request $validTriggers = array_keys(config('firefly.rule-triggers')); $validActions = array_keys(config('firefly.rule-actions')); - // some actions require text: - $contextActions = implode(',', config('firefly.rule-actions-text')); + // some triggers and actions require text: + $contextTriggers = implode(',', config('firefly.context-rule-triggers')); + $contextActions = implode(',', config('firefly.context-rule-actions')); + $rules = [ 'title' => 'required|between:1,100|uniqueObjectForUser:rules,title', @@ -86,7 +88,7 @@ class RuleRequest extends Request 'trigger' => 'required|in:store-journal,update-journal', 'rule_triggers.*.name' => 'required|in:' . implode(',', $validTriggers), 'rule_triggers.*.stop_processing' => 'boolean', - 'rule_triggers.*.value' => 'required|min:1|ruleTriggerValue', + 'rule_triggers.*.value' => 'required_if:rule_actions.*.type,' . $contextTriggers . '|min:1|ruleTriggerValue', 'rule_actions.*.name' => 'required|in:' . implode(',', $validActions), 'rule_actions.*.value' => 'required_if:rule_actions.*.type,' . $contextActions . '|ruleActionValue', 'rule_actions.*.stop_processing' => 'boolean', From 8cd0d5e1ef585368b102b14d1a8b0ba1ad5ebb02 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 17 Oct 2018 05:04:26 +0200 Subject: [PATCH 59/94] Fix for #1798 --- app/Services/Internal/Destroy/AccountDestroyService.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/Internal/Destroy/AccountDestroyService.php b/app/Services/Internal/Destroy/AccountDestroyService.php index cec7a802b3..a747cbd7fc 100644 --- a/app/Services/Internal/Destroy/AccountDestroyService.php +++ b/app/Services/Internal/Destroy/AccountDestroyService.php @@ -26,6 +26,7 @@ namespace FireflyIII\Services\Internal\Destroy; use DB; use Exception; use FireflyIII\Models\Account; +use FireflyIII\Models\PiggyBank; use FireflyIII\Models\RecurrenceTransaction; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; @@ -97,6 +98,9 @@ class AccountDestroyService } } + // delete piggy banks: + PiggyBank::where('account_id', $account->id)->delete(); + try { $account->delete(); } catch (Exception $e) { // @codeCoverageIgnore From ea48c23535c698209fae18aa9a4cf7f0189e3eda Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 17 Oct 2018 05:31:51 +0200 Subject: [PATCH 60/94] Fix for #1790 --- resources/views/bills/show.twig | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/resources/views/bills/show.twig b/resources/views/bills/show.twig index 3020e80b06..fd1a4e91c9 100644 --- a/resources/views/bills/show.twig +++ b/resources/views/bills/show.twig @@ -109,32 +109,30 @@
- {% for att in bill.data.attachments.data %} + {% for att in object.data.attachments.data %} - {% endfor %}
- - + + +
- - - {% if att.data.title %} - {{ att.data.title }} + + + {% if att.title %} + {{ att.title }} {% else %} - {{ att.data.filename }} + {{ att.filename }} {% endif %} - ({{ att.data.size|filesize }}) - {% if att.data.description %} + ({{ att.size|filesize }}) + {% if att.description %}
- {{ att.data.description }} + {{ att.description }} {% endif %}
- -
From da5a1fe26478459bf6031334be3fafd0244c69ba Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 17 Oct 2018 06:05:19 +0200 Subject: [PATCH 61/94] Fix for #1785 --- app/Support/Http/Controllers/UserNavigation.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Support/Http/Controllers/UserNavigation.php b/app/Support/Http/Controllers/UserNavigation.php index f6bcd2ddf3..3119328c52 100644 --- a/app/Support/Http/Controllers/UserNavigation.php +++ b/app/Support/Http/Controllers/UserNavigation.php @@ -28,6 +28,7 @@ use FireflyIII\Models\AccountType; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use Illuminate\Http\RedirectResponse; +use Illuminate\Support\ViewErrorBag; use Log; use URL; @@ -141,6 +142,10 @@ trait UserNavigation */ protected function rememberPreviousUri(string $identifier): void { - session()->put($identifier, URL::previous()); + /** @var ViewErrorBag $errors */ + $errors = session()->get('errors'); + if(null === $errors || (null !== $errors && 0=== $errors->count())) { + session()->put($identifier, URL::previous()); + } } } \ No newline at end of file From b12773bc99d9ac467aa6f399bf550e1f38dcd480 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 17 Oct 2018 06:06:36 +0200 Subject: [PATCH 62/94] Fix for #1784 --- app/Http/Requests/AccountFormRequest.php | 3 +- app/Rules/ZeroOrMore.php | 45 ++++++++++++++++++++++++ resources/lang/en_US/validation.php | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 app/Rules/ZeroOrMore.php diff --git a/app/Http/Requests/AccountFormRequest.php b/app/Http/Requests/AccountFormRequest.php index 3d01ff4a3c..33d3310334 100644 --- a/app/Http/Requests/AccountFormRequest.php +++ b/app/Http/Requests/AccountFormRequest.php @@ -24,6 +24,7 @@ namespace FireflyIII\Http\Requests; use FireflyIII\Models\Account; use FireflyIII\Rules\UniqueIban; +use FireflyIII\Rules\ZeroOrMore; /** * Class AccountFormRequest. @@ -116,7 +117,7 @@ class AccountFormRequest extends Request ]; if ('liabilities' === $this->get('what')) { - $rules['openingBalance'] = 'numeric|required|more:0'; + $rules['openingBalance'] = ['numeric', 'required', new ZeroOrMore]; $rules['openingBalanceDate'] = 'date|required'; } diff --git a/app/Rules/ZeroOrMore.php b/app/Rules/ZeroOrMore.php new file mode 100644 index 0000000000..07e1d8c46b --- /dev/null +++ b/app/Rules/ZeroOrMore.php @@ -0,0 +1,45 @@ + 0) { + return false; + } + + return true; + } +} diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index 39f4f3f50c..9f8f7b9d50 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -24,6 +24,7 @@ declare(strict_types=1); return [ 'iban' => 'This is not a valid IBAN.', + 'zero_or_more' => 'The value cannot be negative.', 'source_equals_destination' => 'The source account equals the destination account.', 'unique_account_number_for_user' => 'It looks like this account number is already in use.', 'unique_iban_for_user' => 'It looks like this IBAN is already in use.', From d0d2189d55f320e3c975a2e78444facd97a05e7d Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 17 Oct 2018 15:18:09 +0200 Subject: [PATCH 63/94] Users can now reorder budgets #1108 --- .../Controllers/Budget/IndexController.php | 26 ++++- app/Models/Budget.php | 3 +- app/Repositories/Budget/BudgetRepository.php | 32 ++++-- .../Budget/BudgetRepositoryInterface.php | 12 ++- public/js/ff/budgets/index.js | 93 +++++++++++++++++ resources/views/budgets/index.twig | 99 ++++++++++--------- routes/web.php | 4 + 7 files changed, 211 insertions(+), 58 deletions(-) diff --git a/app/Http/Controllers/Budget/IndexController.php b/app/Http/Controllers/Budget/IndexController.php index 78bd66d719..8db0e98e64 100644 --- a/app/Http/Controllers/Budget/IndexController.php +++ b/app/Http/Controllers/Budget/IndexController.php @@ -28,6 +28,7 @@ use Carbon\Carbon; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Support\Http\Controllers\DateCalculation; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; @@ -63,7 +64,6 @@ class IndexController extends Controller ); } - /** * Show all budgets. * @@ -134,5 +134,29 @@ class IndexController extends Controller ); } + /** + * @param Request $request + * + * @return JsonResponse + */ + public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse + { + $budgetIds = $request->get('budgetIds'); + $page = (int)$request->get('page'); + $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; + + $currentOrder = (($page - 1) * $pageSize) + 1; + foreach ($budgetIds as $budgetId) { + $budgetId = (int)$budgetId; + $budget = $repository->findNull($budgetId); + if (null !== $budget) { + $repository->setBudgetOrder($budget, $currentOrder); + } + $currentOrder++; + } + + return response()->json(['OK']); + } + } diff --git a/app/Models/Budget.php b/app/Models/Budget.php index 0ef5142e05..5efdbe2b58 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -42,6 +42,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property-read string $email * @property bool encrypted * @property Collection budgetlimits + * @property int $order */ class Budget extends Model { @@ -61,7 +62,7 @@ class Budget extends Model 'encrypted' => 'boolean', ]; /** @var array Fields that can be filled */ - protected $fillable = ['user_id', 'name', 'active']; + protected $fillable = ['user_id', 'name', 'active','order']; /** @var array Hidden from view */ protected $hidden = ['encrypted']; diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 3787219f0e..b1a18f6719 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -107,6 +107,7 @@ class BudgetRepository implements BudgetRepositoryInterface } catch (Exception $e) { Log::debug(sprintf('Could not delete budget limit: %s', $e->getMessage())); } + Budget::where('order',0)->update(['order' => 100]); // do the clean up by hand because Sqlite can be tricky with this. $budgetLimits = BudgetLimit::orderBy('created_at', 'DESC')->get(['id', 'budget_id', 'start_date', 'end_date']); @@ -289,11 +290,14 @@ class BudgetRepository implements BudgetRepositoryInterface public function getActiveBudgets(): Collection { /** @var Collection $set */ - $set = $this->user->budgets()->where('active', 1)->get(); + $set = $this->user->budgets()->where('active', 1) + ->get(); $set = $set->sortBy( function (Budget $budget) { - return strtolower($budget->name); + $str = str_pad((string)$budget->order, 4, '0', STR_PAD_LEFT) . strtolower($budget->name); + + return $str; } ); @@ -554,7 +558,9 @@ class BudgetRepository implements BudgetRepositoryInterface $set = $set->sortBy( function (Budget $budget) { - return strtolower($budget->name); + $str = str_pad((string)$budget->order, 4, '0', STR_PAD_LEFT) . strtolower($budget->name); + + return $str; } ); @@ -583,7 +589,9 @@ class BudgetRepository implements BudgetRepositoryInterface $set = $set->sortBy( function (Budget $budget) { - return strtolower($budget->name); + $str = str_pad((string)$budget->order, 4, '0', STR_PAD_LEFT) . strtolower($budget->name); + + return $str; } ); @@ -652,6 +660,18 @@ class BudgetRepository implements BudgetRepositoryInterface return $availableBudget; } + /** + * @param Budget $budget + * @param int $order + */ + public function setBudgetOrder(Budget $budget, int $order): void + { + $budget->order = $order; + $budget->save(); + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** * @param User $user */ @@ -660,7 +680,6 @@ class BudgetRepository implements BudgetRepositoryInterface $this->user = $user; } - /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param Collection $budgets * @param Collection $accounts @@ -825,6 +844,8 @@ class BudgetRepository implements BudgetRepositoryInterface } + /** @noinspection MoreThanThreeArgumentsInspection */ + /** * @param BudgetLimit $budgetLimit * @param array $data @@ -848,7 +869,6 @@ class BudgetRepository implements BudgetRepositoryInterface return $budgetLimit; } - /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param Budget $budget * @param Carbon $start diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index d6df2f54c6..54433c9ace 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -156,7 +156,6 @@ interface BudgetRepositoryInterface */ public function getBudgetLimits(Budget $budget, Carbon $start = null, Carbon $end = null): Collection; - /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param Collection $budgets * @param Collection $accounts @@ -167,6 +166,8 @@ interface BudgetRepositoryInterface */ public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array; + /** @noinspection MoreThanThreeArgumentsInspection */ + /** * @return Collection */ @@ -195,7 +196,6 @@ interface BudgetRepositoryInterface */ public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array; - /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param TransactionCurrency $currency * @param Carbon $start @@ -206,6 +206,14 @@ interface BudgetRepositoryInterface */ public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget; + /** @noinspection MoreThanThreeArgumentsInspection */ + + /** + * @param Budget $budget + * @param int $order + */ + public function setBudgetOrder(Budget $budget, int $order): void; + /** * @param User $user */ diff --git a/public/js/ff/budgets/index.js b/public/js/ff/budgets/index.js index ea31da14e3..fb962528d4 100644 --- a/public/js/ff/budgets/index.js +++ b/public/js/ff/budgets/index.js @@ -48,8 +48,101 @@ $(function () { } }); + // sortable! + if (typeof $(".sortable-table tbody").sortable !== "undefined") { + $(".sortable-table tbody").sortable( + { + helper: fixHelper, + items: 'tr:not(.ignore)', + stop: sortStop, + handle: '.handle', + start: function (event, ui) { + // Build a placeholder cell that spans all the cells in the row + var cellCount = 0; + $('td, th', ui.helper).each(function () { + // For each TD or TH try and get it's colspan attribute, and add that or 1 to the total + var colspan = 1; + var colspanAttr = $(this).attr('colspan'); + if (colspanAttr > 1) { + colspan = colspanAttr; + } + cellCount += colspan; + }); + + // Add the placeholder UI - note that this is the item's content, so TD rather than TR + ui.placeholder.html(' '); + } + } + ); + } }); +var fixHelper = function (e, tr) { + "use strict"; + var $originals = tr.children(); + var $helper = tr.clone(); + $helper.children().each(function (index) { + // Set helper cell sizes to match the original sizes + $(this).width($originals.eq(index).width()); + }); + return $helper; +}; + + +function sortStop(event, ui) { + "use strict"; + + + //var current = $(ui.item); + var list = $('.sortable-table tbody tr'); + var submit = []; + $.each(list, function (i, v) { + var row = $(v); + var id = parseInt(row.data('id')); + if (id > 0) { + submit.push(id); + } + }); + var arr = { + budgetIds: submit, + page: page, + _token: token + }; + // var thisDate = current.data('date'); + // var originalBG = current.css('backgroundColor'); + // + // + // if (current.prev().data('date') !== thisDate && current.next().data('date') !== thisDate) { + // // animate something with color: + // current.animate({backgroundColor: "#d9534f"}, 200, function () { + // $(this).animate({backgroundColor: originalBG}, 200); + // return undefined; + // }); + // + // return false; + // } + // + // // do update + // var list = $('tr[data-date="' + thisDate + '"]'); + // var submit = []; + // $.each(list, function (i, v) { + // var row = $(v); + // var id = row.data('id'); + // submit.push(id); + // }); + // + // // do extra animation when done? + $.get('budgets/reorder', arr); + // + // current.animate({backgroundColor: "#5cb85c"}, 200, function () { + // $(this).animate({backgroundColor: originalBG}, 200); + // return undefined; + // }); + // return undefined; + //alert('drop!'); +} + + function drawSpentBar() { "use strict"; if ($('.spentBar').length > 0) { diff --git a/resources/views/budgets/index.twig b/resources/views/budgets/index.twig index 73e175b45a..d5d62fde16 100644 --- a/resources/views/budgets/index.twig +++ b/resources/views/budgets/index.twig @@ -17,7 +17,8 @@ {{ 'budgeted'|_ }}: {{ budgeted|formatAmountPlain }}
- {{ trans('firefly.available_between',{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat) }) }}: + {{ trans('firefly.available_between',{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat) }) }} + : {{ available|formatAmountPlain }} @@ -39,7 +40,8 @@
- {{ trans('firefly.spent_between', {start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }}: {{ spent|formatAmount }} + {{ trans('firefly.spent_between', {start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }} + : {{ spent|formatAmount }}
@@ -135,12 +137,12 @@
{{ paginator.render|raw }}
- +
@@ -151,53 +153,53 @@ - - {% for budget in paginator %} - - - + + {% if budgetInformation[budget.id]['currentLimit'] %} - {{ budget.name }} + {% set repAmount = budgetInformation[budget.id]['budgeted'] %} {% else %} - {{ budget.name }} + {% set repAmount = '0' %} {% endif %} - - {% if budgetInformation[budget.id]['currentLimit'] %} - {% set repAmount = budgetInformation[budget.id]['budgeted'] %} - {% else %} - {% set repAmount = '0' %} - {% endif %} - - - - + + + + {% endfor %}
+ {% for budget in paginator %} +
+ {% if budgetInformation[budget.id]['currentLimit'] %} + {{ budget.name }} + {% else %} + {{ budget.name }} + {% endif %} + -
-
{{ defaultCurrency.symbol|raw }}
- - -
- -
- {{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }} - {% if repAmount + budgetInformation[budget.id]['spent'] > 0 %} - ({{ ((repAmount + budgetInformation[budget.id]['spent']) / activeDaysLeft)|formatAmount }}) - {% endif %} -
+
+
{{ defaultCurrency.symbol|raw }}
+ + +
+ +
+ {{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }} + {% if repAmount + budgetInformation[budget.id]['spent'] > 0 %} + ({{ ((repAmount + budgetInformation[budget.id]['spent']) / activeDaysLeft)|formatAmount }}) + {% endif %} +
@@ -206,7 +208,7 @@
@@ -239,6 +241,7 @@ {% endblock %} {% block scripts %} +