Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d23456ce43 | |||
| e2bd475236 | |||
| b94a3bdab7 | |||
| f97bc6a7de | |||
| 206eb7f9cd | |||
| 074129d33b | |||
| a7888e1a58 | |||
| c7ec962e4e | |||
| 2c7b1946cd |
@@ -751,12 +751,38 @@ class API
|
||||
$values[] = $from;
|
||||
$values[] = $to;
|
||||
}
|
||||
|
||||
// ORDER BY
|
||||
if (isset($builder['orderBy']) && is_array($builder['orderBy'])) {
|
||||
|
||||
if (count($builder['orderBy']) !== 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$column = $builder['orderBy'][0];
|
||||
$direction = strtoupper($builder['orderBy'][1]);
|
||||
|
||||
if (!in_array($column, $this->allowedGetColumns, true)) {
|
||||
$this->apiOutput(400, ['error' => "The column $column is not allowed."]);
|
||||
}
|
||||
|
||||
if (!in_array($direction, ['ASC', 'DESC'], true)) {
|
||||
$this->apiOutput(400, ['error' => "Invalid order direction."]);
|
||||
}
|
||||
|
||||
$orderByClauses[] = "$column $direction";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($whereClauses)) {
|
||||
$this->baseQuery .= " WHERE " . implode(" AND ", $whereClauses);
|
||||
}
|
||||
|
||||
if (!empty($orderByClauses)) {
|
||||
$this->baseQuery .= " ORDER BY " . implode(", ", $orderByClauses);
|
||||
}
|
||||
|
||||
return [$this->baseQuery, $types, $values];
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ class API_inserve extends API
|
||||
$sizes = array_column($disks, 'disk_space');
|
||||
$server_disks_count = array_sum($sizes);
|
||||
}
|
||||
return $server_disks_count;
|
||||
return (int)ceil($server_disks_count);
|
||||
}
|
||||
|
||||
private function buildCountObject(string $serverUuid, string $key): array
|
||||
@@ -294,11 +294,11 @@ class API_inserve extends API
|
||||
return [
|
||||
'countSentri' => 0,
|
||||
'countInserve' => 0,
|
||||
'sentriCompanyId' => 0,
|
||||
'SentriStatus' => 0,
|
||||
'subscriptionInserveExists' => false,
|
||||
'subscriptionInserveId' => false,
|
||||
'subscriptionInserveCompanyId' => false,
|
||||
'subscriptionSentriCompanyName' => false,
|
||||
'subscriptionInserveCompanyName' => false,
|
||||
'subscriptionInserveName' => false,
|
||||
'subscriptionInserveStatus' => 0,
|
||||
'md5' => md5($serverUuid . ':' . $key),
|
||||
@@ -338,11 +338,6 @@ class API_inserve extends API
|
||||
|
||||
public function syncServerLicencesToInserve()
|
||||
{
|
||||
# Get all the linked companies
|
||||
$this->getLinkedCompanies();
|
||||
$allCompanies = json_decode($this->response, true);
|
||||
$allCompaniesIds = array_column($allCompanies['matched'], 'id', 'company_id');
|
||||
|
||||
# first get the current subscriptions
|
||||
$this->getCloudSubscriptions();
|
||||
$allInserveCloudSubscriptions = json_decode($this->response, true);
|
||||
@@ -361,7 +356,7 @@ class API_inserve extends API
|
||||
'id' => (int)$subscription['id'],
|
||||
'quantity' => (int)$subscription['quantity'],
|
||||
'status' => (int)$subscription['status'],
|
||||
'cloud_distribution_company_id' => (int)$subscription['cloud_distribution_company_id'],
|
||||
'company_name' => $subscription['company_name'],
|
||||
'name' => $subscription['name'],
|
||||
];
|
||||
}
|
||||
@@ -421,19 +416,18 @@ class API_inserve extends API
|
||||
|
||||
if (isset($inserveLookup[$md5])) { # Subscription already exists in Inserve
|
||||
$item['SentriStatus'] = $sentriStatus;
|
||||
$item['sentriCompanyId'] = (int)$allCompaniesIds[$row['company_source_id']] ?? 0;
|
||||
$item['subscriptionInserveExists'] = true;
|
||||
$item['subscriptionInserveId'] = $inserveLookup[$item['md5']]['id'];
|
||||
$item['countInserve'] = $inserveLookup[$item['md5']]['quantity'];
|
||||
$item['subscriptionInserveCompanyId'] = $inserveLookup[$item['md5']]['cloud_distribution_company_id'];
|
||||
$item['subscriptionSentriCompanyName'] = $row['company_name'];
|
||||
$item['subscriptionInserveCompanyName'] = $inserveLookup[$item['md5']]['company_name'];
|
||||
$item['subscriptionInserveName'] = $inserveLookup[$item['md5']]['name'];
|
||||
//$item['subscriptionInserveStatus'] = $inserveLookup[$item['md5']]['status'];
|
||||
$item['subscriptionInserveStatus'] = $inserveLookup[$item['md5']]['status'];
|
||||
} else { # Subscription does not exist in Inserve
|
||||
$item['sentriCompanyId'] = (int)$allCompaniesIds[$row['company_source_id']] ?? 0;
|
||||
$item['subscriptionSentriCompanyName'] = $row['company_name'];
|
||||
$item['subscriptionInserveExists'] = false;
|
||||
$item['subscriptionInserveId'] = false;
|
||||
$item['countInserve'] = 0;
|
||||
$item['subscriptionInserveCompanyId'] = false;
|
||||
}
|
||||
}
|
||||
unset($item);
|
||||
@@ -487,9 +481,9 @@ class API_inserve extends API
|
||||
"cloud_distribution_id" => $item['md5'], #md5 hash based on the server_uuid from sentri and the subscription name (e.g. server_cpu_count)
|
||||
"cloud_subscription_id" => "sentri-servers", # Mark all the sentri-servers subscriptions so we can filter the subscriptions better
|
||||
"name" => $item['subscriptionSentriName'],
|
||||
"company_name" => $item['subscriptionSentriCompanyName'],
|
||||
"quantity" => ($row['server_state'] === 'deleted') ? 0 : $item['countSentri'],
|
||||
"cloud_distributor" => $this->cloudDistributor,
|
||||
"cloud_distribution_company_id" => $item['sentriCompanyId'], # this is generated by inserve
|
||||
"status" => $item['SentriStatus'],
|
||||
"period_type" => 0, # 0 = monthly, 1 = annual, 2 = one time cost
|
||||
"start_date" => date('Y-m-d')
|
||||
@@ -500,26 +494,55 @@ class API_inserve extends API
|
||||
continue;
|
||||
}
|
||||
|
||||
// update the subscription if the countInserve and countSentri don't match
|
||||
// Or when sentriCompanyId and subscriptionInserveCompanyId don't match
|
||||
if ((
|
||||
(int)$item['countInserve'] !== (int)$item['countSentri'] ||
|
||||
(int)$item['sentriCompanyId'] !== (int)$item['subscriptionInserveCompanyId'] ||
|
||||
(int)$item['SentriStatus'] !== (int)$item['subscriptionInserveStatus'] ||
|
||||
$item['subscriptionSentriName'] !== $item['subscriptionInserveName']
|
||||
)
|
||||
&& $item['subscriptionInserveExists'] !== false
|
||||
$countMismatch =
|
||||
(int)$item['subscriptionInserveStatus'] !== 5 && // Do not update the cound when license status is 5 (removed) in Inserve
|
||||
(int)$item['countInserve'] !== (int)$item['countSentri'];
|
||||
$statusMismatch = (int)$item['SentriStatus'] !== (int)$item['subscriptionInserveStatus'];
|
||||
$nameMismatch = $item['subscriptionSentriName'] !== $item['subscriptionInserveName'];
|
||||
$companyMismatch = $item['subscriptionSentriCompanyName'] !== $item['subscriptionInserveCompanyName'];
|
||||
$subscriptionExists = $item['subscriptionInserveExists'] !== false;
|
||||
|
||||
if (
|
||||
($countMismatch ||
|
||||
$statusMismatch ||
|
||||
$nameMismatch ||
|
||||
$companyMismatch)
|
||||
&& $subscriptionExists
|
||||
) {
|
||||
$output = false;
|
||||
if ($output) {
|
||||
echo "<h3>Update triggered because:</h3>";
|
||||
|
||||
if ($countMismatch) {
|
||||
echo "Count differs: Inserve={$item['countInserve']} Sentri={$item['countSentri']}<br>";
|
||||
}
|
||||
|
||||
if ($statusMismatch) {
|
||||
echo "Status differs: Inserve={$item['subscriptionInserveStatus']} Sentri={$item['SentriStatus']}<br>";
|
||||
}
|
||||
|
||||
if ($nameMismatch) {
|
||||
echo "Name differs: Inserve='{$item['subscriptionInserveName']}' Sentri='{$item['subscriptionSentriName']}'<br>";
|
||||
}
|
||||
|
||||
if ($companyMismatch) {
|
||||
echo "Company differs: Inserve='{$item['subscriptionInserveCompanyName']}' Sentri='{$item['subscriptionSentriCompanyName']}'<br>";
|
||||
}
|
||||
|
||||
if (!$subscriptionExists) {
|
||||
echo "Subscription does not exist.<br>";
|
||||
}
|
||||
}
|
||||
|
||||
$payload = [
|
||||
"quantity" => ($row['server_state'] === 'deleted') ? 0 : $item['countSentri'],
|
||||
"cloud_distributor" => $this->cloudDistributor,
|
||||
"cloud_distribution_company_id" => (int)$item['sentriCompanyId'],
|
||||
"company_name" => $item['subscriptionSentriCompanyName'],
|
||||
"name" => $item['subscriptionSentriName'],
|
||||
"status" => $item['SentriStatus']
|
||||
];
|
||||
|
||||
$this->updateCloudSubscription($item['subscriptionInserveId'], $payload);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,20 +59,21 @@ class API_servers extends API
|
||||
{
|
||||
|
||||
# if the server_state that is posted is 'deleted' check if the current server state is 'new' if so, delete it perm.
|
||||
if ($this->data['server_state'] == 'deleted') {
|
||||
$stmt = $GLOBALS['pdo']->prepare("SELECT server_state FROM servers WHERE server_vm_id = ? AND server_state = 'new'");
|
||||
$stmt->execute([$this->data['server_vm_id']]);
|
||||
if (isset($this->data['server_state'])) {
|
||||
if ($this->data['server_state'] == 'deleted') {
|
||||
$stmt = $GLOBALS['pdo']->prepare("SELECT server_state FROM servers WHERE server_vm_id = ? AND server_state = 'new'");
|
||||
$stmt->execute([$this->data['server_vm_id']]);
|
||||
|
||||
if ($stmt->fetch()) {
|
||||
$deleteStmt = $GLOBALS['pdo']->prepare("DELETE FROM servers WHERE server_vm_id = ? AND server_state = 'new'");
|
||||
$deleteStmt->execute([$this->data['server_vm_id']]);
|
||||
return;
|
||||
if ($stmt->fetch()) {
|
||||
$deleteStmt = $GLOBALS['pdo']->prepare("DELETE FROM servers WHERE server_vm_id = ? AND server_state = 'new'");
|
||||
$deleteStmt->execute([$this->data['server_vm_id']]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->data['company_uuid'])) {
|
||||
if (strlen($this->data['company_uuid']) == 0) {
|
||||
$this->data['company_uuid'] = NULL;
|
||||
if (isset($this->data['company_uuid'])) {
|
||||
if (strlen($this->data['company_uuid']) == 0) {
|
||||
$this->data['company_uuid'] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,17 @@ if (!$GLOBALS['modules_enabled']['office']) {
|
||||
if ($API_office_travel_reimburse->request_method === 'GET') {
|
||||
$API_office_travel_reimburse->checkPermissions('office-travel-reimburse', 'RO');
|
||||
|
||||
$_GET['builder'] = [1 => ['where' => [0 => 'user_uuid', 1 => $_SESSION['user']['user_uuid']]]];
|
||||
if (!isset($_GET['builder']) || !is_array($_GET['builder'])) {
|
||||
$_GET['builder'] = [];
|
||||
}
|
||||
|
||||
# Append user_uuid where builder to always search for the user_uuid that is requesting the travel entries
|
||||
$_GET['builder'][] = [
|
||||
'where' => [
|
||||
0 => 'user_uuid',
|
||||
1 => $_SESSION['user']['user_uuid']
|
||||
]
|
||||
];
|
||||
|
||||
$travel_reimbursements = $API_office_travel_reimburse->getTravelReimburse();
|
||||
$API_office_travel_reimburse->apiOutput($code = 200, $travel_reimbursements);
|
||||
|
||||
@@ -20,8 +20,6 @@ if (!$GLOBALS['modules_enabled']['office']) {
|
||||
}
|
||||
|
||||
if ($API_office_travel_reimburse->request_method === 'POST') {
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
$API_office_travel_reimburse->checkPermissions('office-travel-reimburse', 'RO');
|
||||
$portal_settings = $GLOBALS['conn']->query("SELECT * FROM system_settings")->fetch_assoc();
|
||||
$month = $_POST['calender_month'];
|
||||
@@ -38,6 +36,10 @@ if ($API_office_travel_reimburse->request_method === 'POST') {
|
||||
0 => 'travel_date',
|
||||
1 => $firstDay,
|
||||
2 => $lastDay
|
||||
],
|
||||
'orderBy' => [
|
||||
0 => 'travel_date',
|
||||
1 => 'ASC'
|
||||
]
|
||||
]
|
||||
];
|
||||
@@ -199,7 +201,7 @@ if ($API_office_travel_reimburse->request_method === 'POST') {
|
||||
$mail->mailText = 'Your travel reimbursement is attached.';
|
||||
|
||||
try {
|
||||
$mail->addAttachment($pdfFile, 'travel_reimbursement.pdf');
|
||||
$mail->addAttachment($pdfFile, 'Travel reimbursement ' . $_SESSION['user']['user_full_name'] . ' - ' . $invoiceNumber . '.pdf');
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
use api\classes\API_inserve;
|
||||
|
||||
session_start();
|
||||
|
||||
require_once "{$_SERVER['DOCUMENT_ROOT']}/api/classes/API_inserve.php";
|
||||
|
||||
|
||||
$API_inserve = new API_inserve();
|
||||
|
||||
if ($API_inserve->request_method === 'GET' || $API_inserve->request_method === 'POST') {
|
||||
# This syncs the company id's from Sentri to the Inserve cloudDistributor
|
||||
# These are the same id's but it Inserve requires it to be synced to the cloudDistributor
|
||||
$API_inserve->checkPermissions('servers', 'RW');
|
||||
$API_inserve->setupConnection();
|
||||
|
||||
$API_inserve->syncCompaniesFromSentri();
|
||||
|
||||
|
||||
$API_inserve->apiOutput(200, ['success' => 'Sync is done successfully']);
|
||||
}
|
||||
@@ -13,7 +13,6 @@ if ($API_inserve->request_method === 'GET' || $API_inserve->request_method === '
|
||||
$API_inserve->checkPermissions('servers', 'RW');
|
||||
$API_inserve->setupConnection();
|
||||
|
||||
$API_inserve->syncCompaniesFromSentri();
|
||||
$API_inserve->syncServerLicencesToInserve();
|
||||
|
||||
$API_inserve->apiOutput(200, ['success' => 'Sync is done successfully']);
|
||||
|
||||
@@ -13,7 +13,6 @@ if ($API_inserve->request_method === 'GET' || $API_inserve->request_method === '
|
||||
$API_inserve->checkPermissions('servers', 'RW');
|
||||
$API_inserve->setupConnection();
|
||||
|
||||
$API_inserve->syncCompaniesFromSentri();
|
||||
$API_inserve->syncServerSubscriptionsToInserve();
|
||||
|
||||
$API_inserve->apiOutput(200, ['success' => 'Sync is done successfully']);
|
||||
|
||||
@@ -300,8 +300,6 @@ return [
|
||||
'source_custom_data' => "Custom source data",
|
||||
'settings' => 'settings',
|
||||
'source_description' => 'Enter the necessary API details to set up and configure your connection to the Inserve API. This allows Sentri to communicate with Inserve and retrieve the data it needs. ',
|
||||
'source_inserve_sync_cloud' => 'Sync cloud distributor companies',
|
||||
'source_inserve_sync_cloud_desc' => 'This API call synchronizes active companies in Sentri with the corresponding cloud distributor companies in Inserve. These cloud distributor companies are required to associate Sentri server licenses with companies in Inserve.',
|
||||
'source_inserve_sync_companies' => 'Sync companies from Inserve to Sentri',
|
||||
'source_inserve_sync_companies_desc' => 'This API call retrieves all companies from Inserve and creates or updates them in Sentri.',
|
||||
'source_inserve_sync_licenses' => 'Sync servers licenses',
|
||||
|
||||
@@ -300,8 +300,6 @@ return [
|
||||
'source_custom_data' => "Custom bron data",
|
||||
'settings' => 'insetellingen',
|
||||
'source_description' => 'Voer de benodigde API-gegevens in om uw verbinding met de Inserve API in te stellen en te configureren. Dit stelt Sentri in staat om te communiceren met Inserve en de benodigde gegevens op te halen.',
|
||||
'source_inserve_sync_cloud' => 'Synchroniseer cloud-distributeurbedrijven',
|
||||
'source_inserve_sync_cloud_desc' => 'Deze API-call synchroniseert actieve bedrijven in Sentri met de bijbehorende cloud-distributeurbedrijven in Inserve. Deze cloud-distributeurbedrijven zijn nodig om Sentri-serverlicenties te koppelen aan bedrijven in Inserve.',
|
||||
'source_inserve_sync_companies' => 'Synchroniseer bedrijven van Inserve naar Sentri.',
|
||||
'source_inserve_sync_companies_desc' => 'Deze API-call haalt alle bedrijven op uit Inserve en maakt ze aan of werkt ze bij in Sentri.',
|
||||
'source_inserve_sync_licenses' => 'Synchroniseer serverlicenties.',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="card-body py-0 border">
|
||||
<h5>
|
||||
Sentri<br> Made by:
|
||||
<a class="text-decoration-none" href="https://marcomooij.net" target="_blank">Marco Mooij</a><br> Version 1.3.0
|
||||
<a class="text-decoration-none" href="https://marcomooij.net" target="_blank">Marco Mooij</a><br> Version 1.3.1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,7 +87,7 @@ while ($module = $system_modules_data->fetch_assoc()) {
|
||||
<div class="card">
|
||||
<form id="FormValidation" method="post" action="/api/v1/portal-management/configure/">
|
||||
<input type="hidden" name="X-HTTP-Method-Override" value="PUT">
|
||||
<input type="hidden" name="_return" value="/systemconfig/#global-settings">
|
||||
<input type="hidden" name="_return" value="/portal-management/#global-settings">
|
||||
<input type="hidden" name="portal_uuid" value="<?php echo $portal_settings['portal_uuid']; ?>">
|
||||
<div class="card-body">
|
||||
<div class="form-group form-show-validation row">
|
||||
@@ -176,7 +176,7 @@ while ($module = $system_modules_data->fetch_assoc()) {
|
||||
<form id="FormValidation" method="post" action="/api/v1/portal-management/mail/configure/">
|
||||
<input type="hidden" name="portal_uuid" value="<?php echo $portal_settings['portal_uuid']; ?>">
|
||||
<input type="hidden" name="X-HTTP-Method-Override" value="PUT">
|
||||
<input type="hidden" name="_return" value="/systemconfig/#mail-settings">
|
||||
<input type="hidden" name="_return" value="/portal-management/#mail-settings">
|
||||
<div class="card-body">
|
||||
<div class="form-group form-show-validation row">
|
||||
<label for="mail_from_name" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2"><?php echo __('mail_from_name') ?></label>
|
||||
@@ -276,7 +276,7 @@ while ($module = $system_modules_data->fetch_assoc()) {
|
||||
<form id="FormValidation" method="post" action="/api/v1/portal-management/mail/test/">
|
||||
<input type="hidden" name="portal_uuid" value="<?php echo $portal_settings['portal_uuid']; ?>">
|
||||
<input type="hidden" name="X-HTTP-Method-Override" value="POST">
|
||||
<input type="hidden" name="_return" value="/systemconfig/#mail-settings">
|
||||
<input type="hidden" name="_return" value="/portal-management/#mail-settings">
|
||||
<div class="form-group form-show-validation row">
|
||||
<label for="mail_to" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2"><?php echo __('mail_to') ?>:</label>
|
||||
<div class="col-lg-9 col-md-12 col-sm-10">
|
||||
@@ -313,7 +313,7 @@ while ($module = $system_modules_data->fetch_assoc()) {
|
||||
<form id="FormValidation" method="post" action="/api/v1/modules/">
|
||||
<input type="hidden" name="portal_uuid" value="<?php echo $portal_settings['portal_uuid']; ?>">
|
||||
<input type="hidden" name="X-HTTP-Method-Override" value="PUT">
|
||||
<input type="hidden" name="_return" value="/systemconfig/#modules">
|
||||
<input type="hidden" name="_return" value="/portal-management/#modules">
|
||||
<table class="multi-filter-select display table table-striped table-hover" data-skip-columns="0,5">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -129,25 +129,6 @@ $pageNavbar->outPutNavbar();
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($GLOBALS['modules_enabled']['servers'] && $API->checkPermissions('servers', 'RW', true)) { ?>
|
||||
<div class="col d-flex">
|
||||
<form method="post" action="/api/v1/sources/inserve/sync-cloud-distributor/" class="w-100">
|
||||
<div class="card h-100 w-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php echo __('source_inserve_sync_cloud') ?></h5>
|
||||
<input type="hidden" name="_return" value="/portal-management/sources/inserve">
|
||||
<p class="card-text"><?php echo __('source_inserve_sync_cloud_desc') ?></p>
|
||||
</div>
|
||||
<div class="card-footer mt-auto">
|
||||
<button class="btn btn-primary">
|
||||
<i class="fa-solid fa-arrow-rotate-right"></i> <?php echo __('sync') ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($GLOBALS['modules_enabled']['servers'] && $API->checkPermissions('servers', 'RW', true)) { ?>
|
||||
<div class="col d-flex">
|
||||
<form method="post" action="/api/v1/sources/inserve/sync-server-licenses/" class="w-100">
|
||||
|
||||
@@ -309,7 +309,7 @@ class pageBuilder
|
||||
</nav>
|
||||
<div class="copyright">
|
||||
<?php echo __('version') ?>
|
||||
<a class="text-primary" href="/changelog/">1.3.0</a>
|
||||
<a class="text-primary" href="/changelog/">1.3.1</a>
|
||||
</div>
|
||||
<div>
|
||||
<span class="navbar-text">Sentri</span>
|
||||
|
||||
@@ -1083,3 +1083,11 @@
|
||||
rotate: 180deg
|
||||
}
|
||||
|
||||
.fc .fc-daygrid-day-frame {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.fc .fc-daygrid-day-number {
|
||||
padding: 2px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,9 @@ document.addEventListener('DOMContentLoaded', async function () {
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (!Array.isArray(data)) {
|
||||
data = [];
|
||||
}
|
||||
let totalDistanceHomework = 0;
|
||||
let totalDistanceBusiness = 0;
|
||||
|
||||
|
||||
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
@@ -19,4 +19,4 @@ if (PHP_VERSION_ID < 50600) {
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit017c5201b421d99f90b020e446d1b958::getLoader();
|
||||
return ComposerAutoloaderInit5efdf6ab6e0ff6546006cfc14f689fc3::getLoader();
|
||||
|
||||
10
vendor/composer/autoload_real.php
vendored
10
vendor/composer/autoload_real.php
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit017c5201b421d99f90b020e446d1b958
|
||||
class ComposerAutoloaderInit5efdf6ab6e0ff6546006cfc14f689fc3
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
@@ -24,16 +24,16 @@ class ComposerAutoloaderInit017c5201b421d99f90b020e446d1b958
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit017c5201b421d99f90b020e446d1b958', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit5efdf6ab6e0ff6546006cfc14f689fc3', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit017c5201b421d99f90b020e446d1b958', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit5efdf6ab6e0ff6546006cfc14f689fc3', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit017c5201b421d99f90b020e446d1b958::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit017c5201b421d99f90b020e446d1b958::$files;
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
8
vendor/composer/autoload_static.php
vendored
8
vendor/composer/autoload_static.php
vendored
@@ -4,7 +4,7 @@
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit017c5201b421d99f90b020e446d1b958
|
||||
class ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3
|
||||
{
|
||||
public static $files = array (
|
||||
'72243e5536b63e298acb6476f01f1aff' => __DIR__ . '/..' . '/thecodingmachine/safe/lib/special_cases.php',
|
||||
@@ -262,9 +262,9 @@ class ComposerStaticInit017c5201b421d99f90b020e446d1b958
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit017c5201b421d99f90b020e446d1b958::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit017c5201b421d99f90b020e446d1b958::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit017c5201b421d99f90b020e446d1b958::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit5efdf6ab6e0ff6546006cfc14f689fc3::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
||||
2
vendor/composer/installed.json
vendored
2
vendor/composer/installed.json
vendored
@@ -533,7 +533,7 @@
|
||||
},
|
||||
"time": "2026-01-05T13:17:41+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "source",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"RobThree\\Auth\\": "lib"
|
||||
|
||||
569
vendor/dompdf/dompdf/lib/fonts/Times-Bold.afm.json
vendored
569
vendor/dompdf/dompdf/lib/fonts/Times-Bold.afm.json
vendored
@@ -1,569 +0,0 @@
|
||||
{
|
||||
"codeToName": {
|
||||
"32": "space",
|
||||
"160": "space",
|
||||
"33": "exclam",
|
||||
"34": "quotedbl",
|
||||
"35": "numbersign",
|
||||
"36": "dollar",
|
||||
"37": "percent",
|
||||
"38": "ampersand",
|
||||
"146": "quoteright",
|
||||
"40": "parenleft",
|
||||
"41": "parenright",
|
||||
"42": "asterisk",
|
||||
"43": "plus",
|
||||
"44": "comma",
|
||||
"45": "hyphen",
|
||||
"173": "hyphen",
|
||||
"46": "period",
|
||||
"47": "slash",
|
||||
"48": "zero",
|
||||
"49": "one",
|
||||
"50": "two",
|
||||
"51": "three",
|
||||
"52": "four",
|
||||
"53": "five",
|
||||
"54": "six",
|
||||
"55": "seven",
|
||||
"56": "eight",
|
||||
"57": "nine",
|
||||
"58": "colon",
|
||||
"59": "semicolon",
|
||||
"60": "less",
|
||||
"61": "equal",
|
||||
"62": "greater",
|
||||
"63": "question",
|
||||
"64": "at",
|
||||
"65": "A",
|
||||
"66": "B",
|
||||
"67": "C",
|
||||
"68": "D",
|
||||
"69": "E",
|
||||
"70": "F",
|
||||
"71": "G",
|
||||
"72": "H",
|
||||
"73": "I",
|
||||
"74": "J",
|
||||
"75": "K",
|
||||
"76": "L",
|
||||
"77": "M",
|
||||
"78": "N",
|
||||
"79": "O",
|
||||
"80": "P",
|
||||
"81": "Q",
|
||||
"82": "R",
|
||||
"83": "S",
|
||||
"84": "T",
|
||||
"85": "U",
|
||||
"86": "V",
|
||||
"87": "W",
|
||||
"88": "X",
|
||||
"89": "Y",
|
||||
"90": "Z",
|
||||
"91": "bracketleft",
|
||||
"92": "backslash",
|
||||
"93": "bracketright",
|
||||
"94": "asciicircum",
|
||||
"95": "underscore",
|
||||
"145": "quoteleft",
|
||||
"97": "a",
|
||||
"98": "b",
|
||||
"99": "c",
|
||||
"100": "d",
|
||||
"101": "e",
|
||||
"102": "f",
|
||||
"103": "g",
|
||||
"104": "h",
|
||||
"105": "i",
|
||||
"106": "j",
|
||||
"107": "k",
|
||||
"108": "l",
|
||||
"109": "m",
|
||||
"110": "n",
|
||||
"111": "o",
|
||||
"112": "p",
|
||||
"113": "q",
|
||||
"114": "r",
|
||||
"115": "s",
|
||||
"116": "t",
|
||||
"117": "u",
|
||||
"118": "v",
|
||||
"119": "w",
|
||||
"120": "x",
|
||||
"121": "y",
|
||||
"122": "z",
|
||||
"123": "braceleft",
|
||||
"124": "bar",
|
||||
"125": "braceright",
|
||||
"126": "asciitilde",
|
||||
"161": "exclamdown",
|
||||
"162": "cent",
|
||||
"163": "sterling",
|
||||
"165": "yen",
|
||||
"131": "florin",
|
||||
"167": "section",
|
||||
"164": "currency",
|
||||
"39": "quotesingle",
|
||||
"147": "quotedblleft",
|
||||
"171": "guillemotleft",
|
||||
"139": "guilsinglleft",
|
||||
"155": "guilsinglright",
|
||||
"150": "endash",
|
||||
"134": "dagger",
|
||||
"135": "daggerdbl",
|
||||
"183": "periodcentered",
|
||||
"182": "paragraph",
|
||||
"149": "bullet",
|
||||
"130": "quotesinglbase",
|
||||
"132": "quotedblbase",
|
||||
"148": "quotedblright",
|
||||
"187": "guillemotright",
|
||||
"133": "ellipsis",
|
||||
"137": "perthousand",
|
||||
"191": "questiondown",
|
||||
"96": "grave",
|
||||
"180": "acute",
|
||||
"136": "circumflex",
|
||||
"152": "tilde",
|
||||
"175": "macron",
|
||||
"168": "dieresis",
|
||||
"184": "cedilla",
|
||||
"151": "emdash",
|
||||
"198": "AE",
|
||||
"170": "ordfeminine",
|
||||
"216": "Oslash",
|
||||
"140": "OE",
|
||||
"186": "ordmasculine",
|
||||
"230": "ae",
|
||||
"248": "oslash",
|
||||
"156": "oe",
|
||||
"223": "germandbls",
|
||||
"207": "Idieresis",
|
||||
"233": "eacute",
|
||||
"159": "Ydieresis",
|
||||
"247": "divide",
|
||||
"221": "Yacute",
|
||||
"194": "Acircumflex",
|
||||
"225": "aacute",
|
||||
"219": "Ucircumflex",
|
||||
"253": "yacute",
|
||||
"234": "ecircumflex",
|
||||
"220": "Udieresis",
|
||||
"218": "Uacute",
|
||||
"203": "Edieresis",
|
||||
"169": "copyright",
|
||||
"229": "aring",
|
||||
"224": "agrave",
|
||||
"227": "atilde",
|
||||
"154": "scaron",
|
||||
"237": "iacute",
|
||||
"251": "ucircumflex",
|
||||
"226": "acircumflex",
|
||||
"231": "ccedilla",
|
||||
"222": "Thorn",
|
||||
"179": "threesuperior",
|
||||
"210": "Ograve",
|
||||
"192": "Agrave",
|
||||
"215": "multiply",
|
||||
"250": "uacute",
|
||||
"255": "ydieresis",
|
||||
"238": "icircumflex",
|
||||
"202": "Ecircumflex",
|
||||
"228": "adieresis",
|
||||
"235": "edieresis",
|
||||
"205": "Iacute",
|
||||
"177": "plusminus",
|
||||
"166": "brokenbar",
|
||||
"174": "registered",
|
||||
"200": "Egrave",
|
||||
"142": "Zcaron",
|
||||
"208": "Eth",
|
||||
"199": "Ccedilla",
|
||||
"193": "Aacute",
|
||||
"196": "Adieresis",
|
||||
"232": "egrave",
|
||||
"211": "Oacute",
|
||||
"243": "oacute",
|
||||
"239": "idieresis",
|
||||
"212": "Ocircumflex",
|
||||
"217": "Ugrave",
|
||||
"254": "thorn",
|
||||
"178": "twosuperior",
|
||||
"214": "Odieresis",
|
||||
"181": "mu",
|
||||
"236": "igrave",
|
||||
"190": "threequarters",
|
||||
"153": "trademark",
|
||||
"204": "Igrave",
|
||||
"189": "onehalf",
|
||||
"244": "ocircumflex",
|
||||
"241": "ntilde",
|
||||
"201": "Eacute",
|
||||
"188": "onequarter",
|
||||
"138": "Scaron",
|
||||
"176": "degree",
|
||||
"242": "ograve",
|
||||
"249": "ugrave",
|
||||
"209": "Ntilde",
|
||||
"245": "otilde",
|
||||
"195": "Atilde",
|
||||
"197": "Aring",
|
||||
"213": "Otilde",
|
||||
"206": "Icircumflex",
|
||||
"172": "logicalnot",
|
||||
"246": "odieresis",
|
||||
"252": "udieresis",
|
||||
"240": "eth",
|
||||
"158": "zcaron",
|
||||
"185": "onesuperior",
|
||||
"128": "Euro"
|
||||
},
|
||||
"isUnicode": false,
|
||||
"FontName": "Times-Bold",
|
||||
"FullName": "Times Bold",
|
||||
"FamilyName": "Times",
|
||||
"Weight": "Bold",
|
||||
"ItalicAngle": "0",
|
||||
"IsFixedPitch": "false",
|
||||
"CharacterSet": "ExtendedRoman",
|
||||
"FontBBox": [
|
||||
"-168",
|
||||
"-218",
|
||||
"1000",
|
||||
"935"
|
||||
],
|
||||
"UnderlinePosition": "-100",
|
||||
"UnderlineThickness": "50",
|
||||
"Version": "002.000",
|
||||
"EncodingScheme": "WinAnsiEncoding",
|
||||
"CapHeight": "676",
|
||||
"XHeight": "461",
|
||||
"Ascender": "683",
|
||||
"Descender": "-217",
|
||||
"StdHW": "44",
|
||||
"StdVW": "139",
|
||||
"StartCharMetrics": "317",
|
||||
"C": {
|
||||
"32": 250,
|
||||
"160": 250,
|
||||
"33": 333,
|
||||
"34": 555,
|
||||
"35": 500,
|
||||
"36": 500,
|
||||
"37": 1000,
|
||||
"38": 833,
|
||||
"146": 333,
|
||||
"40": 333,
|
||||
"41": 333,
|
||||
"42": 500,
|
||||
"43": 570,
|
||||
"44": 250,
|
||||
"45": 333,
|
||||
"173": 333,
|
||||
"46": 250,
|
||||
"47": 278,
|
||||
"48": 500,
|
||||
"49": 500,
|
||||
"50": 500,
|
||||
"51": 500,
|
||||
"52": 500,
|
||||
"53": 500,
|
||||
"54": 500,
|
||||
"55": 500,
|
||||
"56": 500,
|
||||
"57": 500,
|
||||
"58": 333,
|
||||
"59": 333,
|
||||
"60": 570,
|
||||
"61": 570,
|
||||
"62": 570,
|
||||
"63": 500,
|
||||
"64": 930,
|
||||
"65": 722,
|
||||
"66": 667,
|
||||
"67": 722,
|
||||
"68": 722,
|
||||
"69": 667,
|
||||
"70": 611,
|
||||
"71": 778,
|
||||
"72": 778,
|
||||
"73": 389,
|
||||
"74": 500,
|
||||
"75": 778,
|
||||
"76": 667,
|
||||
"77": 944,
|
||||
"78": 722,
|
||||
"79": 778,
|
||||
"80": 611,
|
||||
"81": 778,
|
||||
"82": 722,
|
||||
"83": 556,
|
||||
"84": 667,
|
||||
"85": 722,
|
||||
"86": 722,
|
||||
"87": 1000,
|
||||
"88": 722,
|
||||
"89": 722,
|
||||
"90": 667,
|
||||
"91": 333,
|
||||
"92": 278,
|
||||
"93": 333,
|
||||
"94": 581,
|
||||
"95": 500,
|
||||
"145": 333,
|
||||
"97": 500,
|
||||
"98": 556,
|
||||
"99": 444,
|
||||
"100": 556,
|
||||
"101": 444,
|
||||
"102": 333,
|
||||
"103": 500,
|
||||
"104": 556,
|
||||
"105": 278,
|
||||
"106": 333,
|
||||
"107": 556,
|
||||
"108": 278,
|
||||
"109": 833,
|
||||
"110": 556,
|
||||
"111": 500,
|
||||
"112": 556,
|
||||
"113": 556,
|
||||
"114": 444,
|
||||
"115": 389,
|
||||
"116": 333,
|
||||
"117": 556,
|
||||
"118": 500,
|
||||
"119": 722,
|
||||
"120": 500,
|
||||
"121": 500,
|
||||
"122": 444,
|
||||
"123": 394,
|
||||
"124": 220,
|
||||
"125": 394,
|
||||
"126": 520,
|
||||
"161": 333,
|
||||
"162": 500,
|
||||
"163": 500,
|
||||
"fraction": 167,
|
||||
"165": 500,
|
||||
"131": 500,
|
||||
"167": 500,
|
||||
"164": 500,
|
||||
"39": 278,
|
||||
"147": 500,
|
||||
"171": 500,
|
||||
"139": 333,
|
||||
"155": 333,
|
||||
"fi": 556,
|
||||
"fl": 556,
|
||||
"150": 500,
|
||||
"134": 500,
|
||||
"135": 500,
|
||||
"183": 250,
|
||||
"182": 540,
|
||||
"149": 350,
|
||||
"130": 333,
|
||||
"132": 500,
|
||||
"148": 500,
|
||||
"187": 500,
|
||||
"133": 1000,
|
||||
"137": 1000,
|
||||
"191": 500,
|
||||
"96": 333,
|
||||
"180": 333,
|
||||
"136": 333,
|
||||
"152": 333,
|
||||
"175": 333,
|
||||
"breve": 333,
|
||||
"dotaccent": 333,
|
||||
"168": 333,
|
||||
"ring": 333,
|
||||
"184": 333,
|
||||
"hungarumlaut": 333,
|
||||
"ogonek": 333,
|
||||
"caron": 333,
|
||||
"151": 1000,
|
||||
"198": 1000,
|
||||
"170": 300,
|
||||
"Lslash": 667,
|
||||
"216": 778,
|
||||
"140": 1000,
|
||||
"186": 330,
|
||||
"230": 722,
|
||||
"dotlessi": 278,
|
||||
"lslash": 278,
|
||||
"248": 500,
|
||||
"156": 722,
|
||||
"223": 556,
|
||||
"207": 389,
|
||||
"233": 444,
|
||||
"abreve": 500,
|
||||
"uhungarumlaut": 556,
|
||||
"ecaron": 444,
|
||||
"159": 722,
|
||||
"247": 570,
|
||||
"221": 722,
|
||||
"194": 722,
|
||||
"225": 500,
|
||||
"219": 722,
|
||||
"253": 500,
|
||||
"scommaaccent": 389,
|
||||
"234": 444,
|
||||
"Uring": 722,
|
||||
"220": 722,
|
||||
"aogonek": 500,
|
||||
"218": 722,
|
||||
"uogonek": 556,
|
||||
"203": 667,
|
||||
"Dcroat": 722,
|
||||
"commaaccent": 250,
|
||||
"169": 747,
|
||||
"Emacron": 667,
|
||||
"ccaron": 444,
|
||||
"229": 500,
|
||||
"Ncommaaccent": 722,
|
||||
"lacute": 278,
|
||||
"224": 500,
|
||||
"Tcommaaccent": 667,
|
||||
"Cacute": 722,
|
||||
"227": 500,
|
||||
"Edotaccent": 667,
|
||||
"154": 389,
|
||||
"scedilla": 389,
|
||||
"237": 278,
|
||||
"lozenge": 494,
|
||||
"Rcaron": 722,
|
||||
"Gcommaaccent": 778,
|
||||
"251": 556,
|
||||
"226": 500,
|
||||
"Amacron": 722,
|
||||
"rcaron": 444,
|
||||
"231": 444,
|
||||
"Zdotaccent": 667,
|
||||
"222": 611,
|
||||
"Omacron": 778,
|
||||
"Racute": 722,
|
||||
"Sacute": 556,
|
||||
"dcaron": 672,
|
||||
"Umacron": 722,
|
||||
"uring": 556,
|
||||
"179": 300,
|
||||
"210": 778,
|
||||
"192": 722,
|
||||
"Abreve": 722,
|
||||
"215": 570,
|
||||
"250": 556,
|
||||
"Tcaron": 667,
|
||||
"partialdiff": 494,
|
||||
"255": 500,
|
||||
"Nacute": 722,
|
||||
"238": 278,
|
||||
"202": 667,
|
||||
"228": 500,
|
||||
"235": 444,
|
||||
"cacute": 444,
|
||||
"nacute": 556,
|
||||
"umacron": 556,
|
||||
"Ncaron": 722,
|
||||
"205": 389,
|
||||
"177": 570,
|
||||
"166": 220,
|
||||
"174": 747,
|
||||
"Gbreve": 778,
|
||||
"Idotaccent": 389,
|
||||
"summation": 600,
|
||||
"200": 667,
|
||||
"racute": 444,
|
||||
"omacron": 500,
|
||||
"Zacute": 667,
|
||||
"142": 667,
|
||||
"greaterequal": 549,
|
||||
"208": 722,
|
||||
"199": 722,
|
||||
"lcommaaccent": 278,
|
||||
"tcaron": 416,
|
||||
"eogonek": 444,
|
||||
"Uogonek": 722,
|
||||
"193": 722,
|
||||
"196": 722,
|
||||
"232": 444,
|
||||
"zacute": 444,
|
||||
"iogonek": 278,
|
||||
"211": 778,
|
||||
"243": 500,
|
||||
"amacron": 500,
|
||||
"sacute": 389,
|
||||
"239": 278,
|
||||
"212": 778,
|
||||
"217": 722,
|
||||
"Delta": 612,
|
||||
"254": 556,
|
||||
"178": 300,
|
||||
"214": 778,
|
||||
"181": 556,
|
||||
"236": 278,
|
||||
"ohungarumlaut": 500,
|
||||
"Eogonek": 667,
|
||||
"dcroat": 556,
|
||||
"190": 750,
|
||||
"Scedilla": 556,
|
||||
"lcaron": 394,
|
||||
"Kcommaaccent": 778,
|
||||
"Lacute": 667,
|
||||
"153": 1000,
|
||||
"edotaccent": 444,
|
||||
"204": 389,
|
||||
"Imacron": 389,
|
||||
"Lcaron": 667,
|
||||
"189": 750,
|
||||
"lessequal": 549,
|
||||
"244": 500,
|
||||
"241": 556,
|
||||
"Uhungarumlaut": 722,
|
||||
"201": 667,
|
||||
"emacron": 444,
|
||||
"gbreve": 500,
|
||||
"188": 750,
|
||||
"138": 556,
|
||||
"Scommaaccent": 556,
|
||||
"Ohungarumlaut": 778,
|
||||
"176": 400,
|
||||
"242": 500,
|
||||
"Ccaron": 722,
|
||||
"249": 556,
|
||||
"radical": 549,
|
||||
"Dcaron": 722,
|
||||
"rcommaaccent": 444,
|
||||
"209": 722,
|
||||
"245": 500,
|
||||
"Rcommaaccent": 722,
|
||||
"Lcommaaccent": 667,
|
||||
"195": 722,
|
||||
"Aogonek": 722,
|
||||
"197": 722,
|
||||
"213": 778,
|
||||
"zdotaccent": 444,
|
||||
"Ecaron": 667,
|
||||
"Iogonek": 389,
|
||||
"kcommaaccent": 556,
|
||||
"minus": 570,
|
||||
"206": 389,
|
||||
"ncaron": 556,
|
||||
"tcommaaccent": 333,
|
||||
"172": 570,
|
||||
"246": 500,
|
||||
"252": 556,
|
||||
"notequal": 549,
|
||||
"gcommaaccent": 500,
|
||||
"240": 500,
|
||||
"158": 444,
|
||||
"ncommaaccent": 556,
|
||||
"185": 300,
|
||||
"imacron": 278,
|
||||
"128": 500
|
||||
},
|
||||
"CIDtoGID_Compressed": true,
|
||||
"CIDtoGID": "eJwDAAAAAAE=",
|
||||
"_version_": 6
|
||||
}
|
||||
569
vendor/dompdf/dompdf/lib/fonts/Times-Roman.afm.json
vendored
569
vendor/dompdf/dompdf/lib/fonts/Times-Roman.afm.json
vendored
@@ -1,569 +0,0 @@
|
||||
{
|
||||
"codeToName": {
|
||||
"32": "space",
|
||||
"160": "space",
|
||||
"33": "exclam",
|
||||
"34": "quotedbl",
|
||||
"35": "numbersign",
|
||||
"36": "dollar",
|
||||
"37": "percent",
|
||||
"38": "ampersand",
|
||||
"146": "quoteright",
|
||||
"40": "parenleft",
|
||||
"41": "parenright",
|
||||
"42": "asterisk",
|
||||
"43": "plus",
|
||||
"44": "comma",
|
||||
"45": "hyphen",
|
||||
"173": "hyphen",
|
||||
"46": "period",
|
||||
"47": "slash",
|
||||
"48": "zero",
|
||||
"49": "one",
|
||||
"50": "two",
|
||||
"51": "three",
|
||||
"52": "four",
|
||||
"53": "five",
|
||||
"54": "six",
|
||||
"55": "seven",
|
||||
"56": "eight",
|
||||
"57": "nine",
|
||||
"58": "colon",
|
||||
"59": "semicolon",
|
||||
"60": "less",
|
||||
"61": "equal",
|
||||
"62": "greater",
|
||||
"63": "question",
|
||||
"64": "at",
|
||||
"65": "A",
|
||||
"66": "B",
|
||||
"67": "C",
|
||||
"68": "D",
|
||||
"69": "E",
|
||||
"70": "F",
|
||||
"71": "G",
|
||||
"72": "H",
|
||||
"73": "I",
|
||||
"74": "J",
|
||||
"75": "K",
|
||||
"76": "L",
|
||||
"77": "M",
|
||||
"78": "N",
|
||||
"79": "O",
|
||||
"80": "P",
|
||||
"81": "Q",
|
||||
"82": "R",
|
||||
"83": "S",
|
||||
"84": "T",
|
||||
"85": "U",
|
||||
"86": "V",
|
||||
"87": "W",
|
||||
"88": "X",
|
||||
"89": "Y",
|
||||
"90": "Z",
|
||||
"91": "bracketleft",
|
||||
"92": "backslash",
|
||||
"93": "bracketright",
|
||||
"94": "asciicircum",
|
||||
"95": "underscore",
|
||||
"145": "quoteleft",
|
||||
"97": "a",
|
||||
"98": "b",
|
||||
"99": "c",
|
||||
"100": "d",
|
||||
"101": "e",
|
||||
"102": "f",
|
||||
"103": "g",
|
||||
"104": "h",
|
||||
"105": "i",
|
||||
"106": "j",
|
||||
"107": "k",
|
||||
"108": "l",
|
||||
"109": "m",
|
||||
"110": "n",
|
||||
"111": "o",
|
||||
"112": "p",
|
||||
"113": "q",
|
||||
"114": "r",
|
||||
"115": "s",
|
||||
"116": "t",
|
||||
"117": "u",
|
||||
"118": "v",
|
||||
"119": "w",
|
||||
"120": "x",
|
||||
"121": "y",
|
||||
"122": "z",
|
||||
"123": "braceleft",
|
||||
"124": "bar",
|
||||
"125": "braceright",
|
||||
"126": "asciitilde",
|
||||
"161": "exclamdown",
|
||||
"162": "cent",
|
||||
"163": "sterling",
|
||||
"165": "yen",
|
||||
"131": "florin",
|
||||
"167": "section",
|
||||
"164": "currency",
|
||||
"39": "quotesingle",
|
||||
"147": "quotedblleft",
|
||||
"171": "guillemotleft",
|
||||
"139": "guilsinglleft",
|
||||
"155": "guilsinglright",
|
||||
"150": "endash",
|
||||
"134": "dagger",
|
||||
"135": "daggerdbl",
|
||||
"183": "periodcentered",
|
||||
"182": "paragraph",
|
||||
"149": "bullet",
|
||||
"130": "quotesinglbase",
|
||||
"132": "quotedblbase",
|
||||
"148": "quotedblright",
|
||||
"187": "guillemotright",
|
||||
"133": "ellipsis",
|
||||
"137": "perthousand",
|
||||
"191": "questiondown",
|
||||
"96": "grave",
|
||||
"180": "acute",
|
||||
"136": "circumflex",
|
||||
"152": "tilde",
|
||||
"175": "macron",
|
||||
"168": "dieresis",
|
||||
"184": "cedilla",
|
||||
"151": "emdash",
|
||||
"198": "AE",
|
||||
"170": "ordfeminine",
|
||||
"216": "Oslash",
|
||||
"140": "OE",
|
||||
"186": "ordmasculine",
|
||||
"230": "ae",
|
||||
"248": "oslash",
|
||||
"156": "oe",
|
||||
"223": "germandbls",
|
||||
"207": "Idieresis",
|
||||
"233": "eacute",
|
||||
"159": "Ydieresis",
|
||||
"247": "divide",
|
||||
"221": "Yacute",
|
||||
"194": "Acircumflex",
|
||||
"225": "aacute",
|
||||
"219": "Ucircumflex",
|
||||
"253": "yacute",
|
||||
"234": "ecircumflex",
|
||||
"220": "Udieresis",
|
||||
"218": "Uacute",
|
||||
"203": "Edieresis",
|
||||
"169": "copyright",
|
||||
"229": "aring",
|
||||
"224": "agrave",
|
||||
"227": "atilde",
|
||||
"154": "scaron",
|
||||
"237": "iacute",
|
||||
"251": "ucircumflex",
|
||||
"226": "acircumflex",
|
||||
"231": "ccedilla",
|
||||
"222": "Thorn",
|
||||
"179": "threesuperior",
|
||||
"210": "Ograve",
|
||||
"192": "Agrave",
|
||||
"215": "multiply",
|
||||
"250": "uacute",
|
||||
"255": "ydieresis",
|
||||
"238": "icircumflex",
|
||||
"202": "Ecircumflex",
|
||||
"228": "adieresis",
|
||||
"235": "edieresis",
|
||||
"205": "Iacute",
|
||||
"177": "plusminus",
|
||||
"166": "brokenbar",
|
||||
"174": "registered",
|
||||
"200": "Egrave",
|
||||
"142": "Zcaron",
|
||||
"208": "Eth",
|
||||
"199": "Ccedilla",
|
||||
"193": "Aacute",
|
||||
"196": "Adieresis",
|
||||
"232": "egrave",
|
||||
"211": "Oacute",
|
||||
"243": "oacute",
|
||||
"239": "idieresis",
|
||||
"212": "Ocircumflex",
|
||||
"217": "Ugrave",
|
||||
"254": "thorn",
|
||||
"178": "twosuperior",
|
||||
"214": "Odieresis",
|
||||
"181": "mu",
|
||||
"236": "igrave",
|
||||
"190": "threequarters",
|
||||
"153": "trademark",
|
||||
"204": "Igrave",
|
||||
"189": "onehalf",
|
||||
"244": "ocircumflex",
|
||||
"241": "ntilde",
|
||||
"201": "Eacute",
|
||||
"188": "onequarter",
|
||||
"138": "Scaron",
|
||||
"176": "degree",
|
||||
"242": "ograve",
|
||||
"249": "ugrave",
|
||||
"209": "Ntilde",
|
||||
"245": "otilde",
|
||||
"195": "Atilde",
|
||||
"197": "Aring",
|
||||
"213": "Otilde",
|
||||
"206": "Icircumflex",
|
||||
"172": "logicalnot",
|
||||
"246": "odieresis",
|
||||
"252": "udieresis",
|
||||
"240": "eth",
|
||||
"158": "zcaron",
|
||||
"185": "onesuperior",
|
||||
"128": "Euro"
|
||||
},
|
||||
"isUnicode": false,
|
||||
"FontName": "Times-Roman",
|
||||
"FullName": "Times Roman",
|
||||
"FamilyName": "Times",
|
||||
"Weight": "Roman",
|
||||
"ItalicAngle": "0",
|
||||
"IsFixedPitch": "false",
|
||||
"CharacterSet": "ExtendedRoman",
|
||||
"FontBBox": [
|
||||
"-168",
|
||||
"-218",
|
||||
"1000",
|
||||
"898"
|
||||
],
|
||||
"UnderlinePosition": "-100",
|
||||
"UnderlineThickness": "50",
|
||||
"Version": "002.00",
|
||||
"EncodingScheme": "WinAnsiEncoding",
|
||||
"CapHeight": "662",
|
||||
"XHeight": "450",
|
||||
"Ascender": "683",
|
||||
"Descender": "-217",
|
||||
"StdHW": "28",
|
||||
"StdVW": "84",
|
||||
"StartCharMetrics": "317",
|
||||
"C": {
|
||||
"32": 250,
|
||||
"160": 250,
|
||||
"33": 333,
|
||||
"34": 408,
|
||||
"35": 500,
|
||||
"36": 500,
|
||||
"37": 833,
|
||||
"38": 778,
|
||||
"146": 333,
|
||||
"40": 333,
|
||||
"41": 333,
|
||||
"42": 500,
|
||||
"43": 564,
|
||||
"44": 250,
|
||||
"45": 333,
|
||||
"173": 333,
|
||||
"46": 250,
|
||||
"47": 278,
|
||||
"48": 500,
|
||||
"49": 500,
|
||||
"50": 500,
|
||||
"51": 500,
|
||||
"52": 500,
|
||||
"53": 500,
|
||||
"54": 500,
|
||||
"55": 500,
|
||||
"56": 500,
|
||||
"57": 500,
|
||||
"58": 278,
|
||||
"59": 278,
|
||||
"60": 564,
|
||||
"61": 564,
|
||||
"62": 564,
|
||||
"63": 444,
|
||||
"64": 921,
|
||||
"65": 722,
|
||||
"66": 667,
|
||||
"67": 667,
|
||||
"68": 722,
|
||||
"69": 611,
|
||||
"70": 556,
|
||||
"71": 722,
|
||||
"72": 722,
|
||||
"73": 333,
|
||||
"74": 389,
|
||||
"75": 722,
|
||||
"76": 611,
|
||||
"77": 889,
|
||||
"78": 722,
|
||||
"79": 722,
|
||||
"80": 556,
|
||||
"81": 722,
|
||||
"82": 667,
|
||||
"83": 556,
|
||||
"84": 611,
|
||||
"85": 722,
|
||||
"86": 722,
|
||||
"87": 944,
|
||||
"88": 722,
|
||||
"89": 722,
|
||||
"90": 611,
|
||||
"91": 333,
|
||||
"92": 278,
|
||||
"93": 333,
|
||||
"94": 469,
|
||||
"95": 500,
|
||||
"145": 333,
|
||||
"97": 444,
|
||||
"98": 500,
|
||||
"99": 444,
|
||||
"100": 500,
|
||||
"101": 444,
|
||||
"102": 333,
|
||||
"103": 500,
|
||||
"104": 500,
|
||||
"105": 278,
|
||||
"106": 278,
|
||||
"107": 500,
|
||||
"108": 278,
|
||||
"109": 778,
|
||||
"110": 500,
|
||||
"111": 500,
|
||||
"112": 500,
|
||||
"113": 500,
|
||||
"114": 333,
|
||||
"115": 389,
|
||||
"116": 278,
|
||||
"117": 500,
|
||||
"118": 500,
|
||||
"119": 722,
|
||||
"120": 500,
|
||||
"121": 500,
|
||||
"122": 444,
|
||||
"123": 480,
|
||||
"124": 200,
|
||||
"125": 480,
|
||||
"126": 541,
|
||||
"161": 333,
|
||||
"162": 500,
|
||||
"163": 500,
|
||||
"fraction": 167,
|
||||
"165": 500,
|
||||
"131": 500,
|
||||
"167": 500,
|
||||
"164": 500,
|
||||
"39": 180,
|
||||
"147": 444,
|
||||
"171": 500,
|
||||
"139": 333,
|
||||
"155": 333,
|
||||
"fi": 556,
|
||||
"fl": 556,
|
||||
"150": 500,
|
||||
"134": 500,
|
||||
"135": 500,
|
||||
"183": 250,
|
||||
"182": 453,
|
||||
"149": 350,
|
||||
"130": 333,
|
||||
"132": 444,
|
||||
"148": 444,
|
||||
"187": 500,
|
||||
"133": 1000,
|
||||
"137": 1000,
|
||||
"191": 444,
|
||||
"96": 333,
|
||||
"180": 333,
|
||||
"136": 333,
|
||||
"152": 333,
|
||||
"175": 333,
|
||||
"breve": 333,
|
||||
"dotaccent": 333,
|
||||
"168": 333,
|
||||
"ring": 333,
|
||||
"184": 333,
|
||||
"hungarumlaut": 333,
|
||||
"ogonek": 333,
|
||||
"caron": 333,
|
||||
"151": 1000,
|
||||
"198": 889,
|
||||
"170": 276,
|
||||
"Lslash": 611,
|
||||
"216": 722,
|
||||
"140": 889,
|
||||
"186": 310,
|
||||
"230": 667,
|
||||
"dotlessi": 278,
|
||||
"lslash": 278,
|
||||
"248": 500,
|
||||
"156": 722,
|
||||
"223": 500,
|
||||
"207": 333,
|
||||
"233": 444,
|
||||
"abreve": 444,
|
||||
"uhungarumlaut": 500,
|
||||
"ecaron": 444,
|
||||
"159": 722,
|
||||
"247": 564,
|
||||
"221": 722,
|
||||
"194": 722,
|
||||
"225": 444,
|
||||
"219": 722,
|
||||
"253": 500,
|
||||
"scommaaccent": 389,
|
||||
"234": 444,
|
||||
"Uring": 722,
|
||||
"220": 722,
|
||||
"aogonek": 444,
|
||||
"218": 722,
|
||||
"uogonek": 500,
|
||||
"203": 611,
|
||||
"Dcroat": 722,
|
||||
"commaaccent": 250,
|
||||
"169": 760,
|
||||
"Emacron": 611,
|
||||
"ccaron": 444,
|
||||
"229": 444,
|
||||
"Ncommaaccent": 722,
|
||||
"lacute": 278,
|
||||
"224": 444,
|
||||
"Tcommaaccent": 611,
|
||||
"Cacute": 667,
|
||||
"227": 444,
|
||||
"Edotaccent": 611,
|
||||
"154": 389,
|
||||
"scedilla": 389,
|
||||
"237": 278,
|
||||
"lozenge": 471,
|
||||
"Rcaron": 667,
|
||||
"Gcommaaccent": 722,
|
||||
"251": 500,
|
||||
"226": 444,
|
||||
"Amacron": 722,
|
||||
"rcaron": 333,
|
||||
"231": 444,
|
||||
"Zdotaccent": 611,
|
||||
"222": 556,
|
||||
"Omacron": 722,
|
||||
"Racute": 667,
|
||||
"Sacute": 556,
|
||||
"dcaron": 588,
|
||||
"Umacron": 722,
|
||||
"uring": 500,
|
||||
"179": 300,
|
||||
"210": 722,
|
||||
"192": 722,
|
||||
"Abreve": 722,
|
||||
"215": 564,
|
||||
"250": 500,
|
||||
"Tcaron": 611,
|
||||
"partialdiff": 476,
|
||||
"255": 500,
|
||||
"Nacute": 722,
|
||||
"238": 278,
|
||||
"202": 611,
|
||||
"228": 444,
|
||||
"235": 444,
|
||||
"cacute": 444,
|
||||
"nacute": 500,
|
||||
"umacron": 500,
|
||||
"Ncaron": 722,
|
||||
"205": 333,
|
||||
"177": 564,
|
||||
"166": 200,
|
||||
"174": 760,
|
||||
"Gbreve": 722,
|
||||
"Idotaccent": 333,
|
||||
"summation": 600,
|
||||
"200": 611,
|
||||
"racute": 333,
|
||||
"omacron": 500,
|
||||
"Zacute": 611,
|
||||
"142": 611,
|
||||
"greaterequal": 549,
|
||||
"208": 722,
|
||||
"199": 667,
|
||||
"lcommaaccent": 278,
|
||||
"tcaron": 326,
|
||||
"eogonek": 444,
|
||||
"Uogonek": 722,
|
||||
"193": 722,
|
||||
"196": 722,
|
||||
"232": 444,
|
||||
"zacute": 444,
|
||||
"iogonek": 278,
|
||||
"211": 722,
|
||||
"243": 500,
|
||||
"amacron": 444,
|
||||
"sacute": 389,
|
||||
"239": 278,
|
||||
"212": 722,
|
||||
"217": 722,
|
||||
"Delta": 612,
|
||||
"254": 500,
|
||||
"178": 300,
|
||||
"214": 722,
|
||||
"181": 500,
|
||||
"236": 278,
|
||||
"ohungarumlaut": 500,
|
||||
"Eogonek": 611,
|
||||
"dcroat": 500,
|
||||
"190": 750,
|
||||
"Scedilla": 556,
|
||||
"lcaron": 344,
|
||||
"Kcommaaccent": 722,
|
||||
"Lacute": 611,
|
||||
"153": 980,
|
||||
"edotaccent": 444,
|
||||
"204": 333,
|
||||
"Imacron": 333,
|
||||
"Lcaron": 611,
|
||||
"189": 750,
|
||||
"lessequal": 549,
|
||||
"244": 500,
|
||||
"241": 500,
|
||||
"Uhungarumlaut": 722,
|
||||
"201": 611,
|
||||
"emacron": 444,
|
||||
"gbreve": 500,
|
||||
"188": 750,
|
||||
"138": 556,
|
||||
"Scommaaccent": 556,
|
||||
"Ohungarumlaut": 722,
|
||||
"176": 400,
|
||||
"242": 500,
|
||||
"Ccaron": 667,
|
||||
"249": 500,
|
||||
"radical": 453,
|
||||
"Dcaron": 722,
|
||||
"rcommaaccent": 333,
|
||||
"209": 722,
|
||||
"245": 500,
|
||||
"Rcommaaccent": 667,
|
||||
"Lcommaaccent": 611,
|
||||
"195": 722,
|
||||
"Aogonek": 722,
|
||||
"197": 722,
|
||||
"213": 722,
|
||||
"zdotaccent": 444,
|
||||
"Ecaron": 611,
|
||||
"Iogonek": 333,
|
||||
"kcommaaccent": 500,
|
||||
"minus": 564,
|
||||
"206": 333,
|
||||
"ncaron": 500,
|
||||
"tcommaaccent": 278,
|
||||
"172": 564,
|
||||
"246": 500,
|
||||
"252": 500,
|
||||
"notequal": 549,
|
||||
"gcommaaccent": 500,
|
||||
"240": 500,
|
||||
"158": 444,
|
||||
"ncommaaccent": 500,
|
||||
"185": 300,
|
||||
"imacron": 278,
|
||||
"128": 500
|
||||
},
|
||||
"CIDtoGID_Compressed": true,
|
||||
"CIDtoGID": "eJwDAAAAAAE=",
|
||||
"_version_": 6
|
||||
}
|
||||
12
vendor/robthree/twofactorauth/.gitattributes
vendored
12
vendor/robthree/twofactorauth/.gitattributes
vendored
@@ -1,12 +0,0 @@
|
||||
/.github/ export-ignore
|
||||
/demo/ export-ignore
|
||||
/docs/ export-ignore
|
||||
/tests/ export-ignore
|
||||
/testsDependency/ export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.php-cs-fixer.dist.php export-ignore
|
||||
/logo.png export-ignore
|
||||
/multifactorauthforeveryone.png export-ignore
|
||||
/phpstan.neon export-ignore
|
||||
/phpunit.xml export-ignore
|
||||
@@ -1 +0,0 @@
|
||||
Don't be a jerk!
|
||||
@@ -1,4 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [RobThree]
|
||||
custom: ["https://paypal.me/robiii"]
|
||||
@@ -1,36 +0,0 @@
|
||||
name: Test Bacon QR Code Provider
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: [8.2, 8.3, 8.4, 8.5]
|
||||
bacon-version: ["^2", "^3"]
|
||||
exclude:
|
||||
- php-version: 8.4
|
||||
bacon-version: "^2"
|
||||
- php-version: 8.5
|
||||
bacon-version: "^2"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v3
|
||||
|
||||
- run: composer require bacon/bacon-qr-code:${{ matrix.bacon-version }}
|
||||
|
||||
- run: composer lint-ci
|
||||
- run: composer test testsDependency/BaconQRCodeTest.php
|
||||
@@ -1,44 +0,0 @@
|
||||
name: Test Endroid QR Code Provider
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: [8.2, 8.3, 8.4, 8.5]
|
||||
endroid-version: ["^3", "^4", "^5", "^6"]
|
||||
exclude:
|
||||
- php-version: 8.4
|
||||
endroid-version: "^3"
|
||||
- php-version: 8.4
|
||||
endroid-version: "^4"
|
||||
- php-version: 8.4
|
||||
endroid-version: "^5"
|
||||
- php-version: 8.5
|
||||
endroid-version: "^3"
|
||||
- php-version: 8.5
|
||||
endroid-version: "^4"
|
||||
- php-version: 8.5
|
||||
endroid-version: "^5"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v3
|
||||
|
||||
- run: composer require endroid/qrcode:${{ matrix.endroid-version }} -W
|
||||
|
||||
- run: composer lint-ci
|
||||
- run: composer test testsDependency/EndroidQRCodeTest.php
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: [8.2, 8.3, 8.4, 8.5]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v3
|
||||
|
||||
- run: composer lint-ci
|
||||
- run: composer phpstan
|
||||
- run: composer test
|
||||
193
vendor/robthree/twofactorauth/.gitignore
vendored
193
vendor/robthree/twofactorauth/.gitignore
vendored
@@ -1,193 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Roslyn cache directories
|
||||
*.ide/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
#NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding addin-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# If using the old MSBuild-Integrated Package Restore, uncomment this:
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# Composer
|
||||
/vendor
|
||||
composer.lock
|
||||
|
||||
# .vs
|
||||
.vs/
|
||||
|
||||
.phpunit.result.cache
|
||||
.php-cs-fixer.cache
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* PHP-CS-Fixer config for RobThree/TwoFactorAuth
|
||||
*/
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->name('/\.php|\.php.dist$/')
|
||||
->exclude('build')
|
||||
->exclude('demo')
|
||||
->exclude('docs')
|
||||
->in(['lib', 'tests', 'testsDependency'])
|
||||
;
|
||||
|
||||
$config = new PhpCsFixer\Config();
|
||||
|
||||
return $config->setRules(array(
|
||||
'@PSR2' => true,
|
||||
'@PSR12' => true,
|
||||
'@PHP82Migration' => true,
|
||||
'array_syntax' => ['syntax' => 'long'],
|
||||
'class_attributes_separation' => true,
|
||||
'declare_strict_types' => true,
|
||||
'dir_constant' => true,
|
||||
'is_null' => true,
|
||||
'no_homoglyph_names' => true,
|
||||
'no_null_property_initialization' => true,
|
||||
'no_php4_constructor' => true,
|
||||
'no_unused_imports' => true,
|
||||
'no_useless_else' => true,
|
||||
'non_printable_character' => true,
|
||||
'ordered_imports' => true,
|
||||
'ordered_class_elements' => true,
|
||||
'php_unit_construct' => true,
|
||||
'pow_to_exponentiation' => true,
|
||||
'psr_autoloading' => true,
|
||||
'random_api_migration' => true,
|
||||
'return_assignment' => true,
|
||||
'self_accessor' => true,
|
||||
'semicolon_after_instruction' => true,
|
||||
'short_scalar_cast' => true,
|
||||
'simplified_null_return' => true,
|
||||
'single_class_element_per_statement' => true,
|
||||
'single_line_comment_style' => true,
|
||||
'single_quote' => true,
|
||||
'space_after_semicolon' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'strict_param' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
'trailing_comma_in_multiline' => true,
|
||||
'trim_array_spaces' => true,
|
||||
'unary_operator_spaces' => true,
|
||||
'global_namespace_import' => [
|
||||
'import_classes' => true,
|
||||
'import_functions' => true,
|
||||
'import_constants' => true,
|
||||
],
|
||||
))
|
||||
->setFinder($finder)
|
||||
->setRiskyAllowed(true)
|
||||
;
|
||||
53
vendor/robthree/twofactorauth/demo/demo.php
vendored
53
vendor/robthree/twofactorauth/demo/demo.php
vendored
@@ -1,53 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<ol>
|
||||
<?php
|
||||
// in practice you would require the composer loader if it was not already part of your framework or project
|
||||
spl_autoload_register(function ($className) {
|
||||
include_once str_replace(array('RobThree\\Auth', '\\'), array(__DIR__.'/../lib', '/'), $className) . '.php';
|
||||
});
|
||||
|
||||
$tfa = new RobThree\Auth\TwoFactorAuth(
|
||||
new RobThree\Auth\Providers\Qr\QRServerProvider(),
|
||||
"Acme Corp" // substitute your company or app name here
|
||||
);
|
||||
?>
|
||||
<li>First create a secret and associate it with a user</li>
|
||||
<?php
|
||||
$secret = $tfa->createSecret();
|
||||
?>
|
||||
<li>
|
||||
Next create a QR code and let the user scan it:<br>
|
||||
<img src="<?php echo $tfa->getQRCodeImageAsDataUri('Demo', $secret); ?>"><br>
|
||||
...or display the secret to the user for manual entry:
|
||||
<?php echo chunk_split($secret, 4, ' '); ?>
|
||||
</li>
|
||||
<?php
|
||||
$code = $tfa->getCode($secret);
|
||||
?>
|
||||
<li>Next, have the user verify the code; at this time the code displayed by a 2FA-app would be: <span style="color:#00c"><?php echo $code; ?></span> (but that changes periodically)</li>
|
||||
<li>When the code checks out, 2FA can be / is enabled; store (encrypted?) secret with user and have the user verify a code each time a new session is started.</li>
|
||||
<li>
|
||||
When aforementioned code (<?php echo $code; ?>) was entered, the result would be:
|
||||
<?php if ($tfa->verifyCode($secret, $code) === true) { ?>
|
||||
<span style="color:#0c0">OK</span>
|
||||
<?php } else { ?>
|
||||
<span style="color:#c00">FAIL</span>
|
||||
<?php } ?>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Note: Make sure your server-time is <a href="http://en.wikipedia.org/wiki/Network_Time_Protocol">NTP-synced</a>! Depending on the $discrepancy allowed your time cannot drift too much from the users' time!</p>
|
||||
<?php
|
||||
try {
|
||||
$tfa->ensureCorrectTime();
|
||||
echo 'Your hosts time seems to be correct / within margin';
|
||||
} catch (RobThree\Auth\TwoFactorAuthException $ex) {
|
||||
echo '<b>Warning:</b> Your hosts time seems to be off: ' . $ex->getMessage();
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
theme: jekyll-theme-minimal
|
||||
|
||||
logo: https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/multifactorauthforeveryone.png
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<a href="{{ site.baseurl }}">← contents</a>
|
||||
|
||||
<h1>{{ page.title }}</h1>
|
||||
|
||||
{{ content }}
|
||||
@@ -1,54 +0,0 @@
|
||||
---
|
||||
---
|
||||
|
||||
@import "{{ site.theme }}";
|
||||
|
||||
// undo some of the theme to allow code samples to be wider
|
||||
header {
|
||||
padding-right: 0;
|
||||
}
|
||||
@media print, screen and (min-width: 961px) {
|
||||
header {
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 30px;
|
||||
margin-right: 30px;
|
||||
padding-top: 20px;
|
||||
position: static;
|
||||
text-align: center;
|
||||
}
|
||||
section {
|
||||
float: none;
|
||||
width: auto;
|
||||
}
|
||||
footer {
|
||||
float: none;
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure code samples can be really wide
|
||||
.language-php.highlighter-rouge {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
// add missing consistency
|
||||
header img {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
// quick navigation hack needs some spacing
|
||||
section > a:first-child {
|
||||
display: block;
|
||||
margin-bottom:45px;
|
||||
}
|
||||
|
||||
// 100% width is treated like clear which makes it look bad
|
||||
table {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
// reset document block whatever so the bullets aren't disturbed by the float
|
||||
ul {
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
## 1. Installation
|
||||
|
||||
The best way of making use of this project is by installing it with [composer](https://getcomposer.org/doc/01-basic-usage.md).
|
||||
|
||||
```
|
||||
composer require robthree/twofactorauth
|
||||
```
|
||||
|
||||
## 2. Create an instance
|
||||
|
||||
`TwoFactorAuth` constructor requires an object able to provide a QR Code image. It is the only mandatory argument. This lets you select your preferred QR Code generator/library.
|
||||
|
||||
See [QR code providers documentation](qr-codes.md) for more information about the different possibilites.
|
||||
|
||||
Example code:
|
||||
|
||||
```php
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\Providers\Qr\QRServerProvider; // if using library's provider
|
||||
use RobThree\Auth\Providers\Qr\BaconQrCodeProvider; // if using Bacon
|
||||
use RobThree\Auth\Providers\Qr\EndroidQrCodeProvider; // if using Endroid
|
||||
|
||||
// using the default Qr Code provider from the library
|
||||
$tfa = new TwoFactorAuth(new QRServerProvider(), "Your app name");
|
||||
// using Bacon
|
||||
$tfa = new TwoFactorAuth(new BaconQrCodeProvider(), "Your app name");
|
||||
// using Endroid
|
||||
$tfa = new TwoFactorAuth(new EndroidQrCodeProvider(), "Your app name");
|
||||
// using a custom object implementing IQRCodeProvider interface
|
||||
$tfa = new TwoFactorAuth(new MyQrCodeProvider(), "Your app name");
|
||||
// using named argument and a variable
|
||||
$tfa = new TwoFactorAuth(qrcodeprovider: $qrGenerator, issuer: "Your app name");
|
||||
```
|
||||
|
||||
## 3. Shared secrets
|
||||
|
||||
When your user is setting up two-factor, or multi-factor, authentication in your project, you can create a secret from the instance.
|
||||
|
||||
```php
|
||||
$secret = $tfa->createSecret();
|
||||
```
|
||||
|
||||
Once you have a secret, it can be communicated to the user however you wish.
|
||||
|
||||
```php
|
||||
<p>Please enter the following code in your app: '<?php echo $secret; ?>'</p>
|
||||
```
|
||||
|
||||
**Note:** until you have verified the user is able to use the secret properly, you should store the secret as part of the current session and not save the secret against your user record.
|
||||
|
||||
## 4. Verifying
|
||||
|
||||
Having provided the user with the secret, the best practice is to verify their authenticator app can create the appropriate code.
|
||||
|
||||
```php
|
||||
$result = $tfa->verifyCode($secret, $_POST['verification']);
|
||||
```
|
||||
|
||||
If `$result` is `true` then your user has been able to successfully record the `$secret` in their authenticator app and it has generated an appropriate code.
|
||||
|
||||
You can now save the `$secret` to your user record and use the same `verifyCode` method each time they log in.
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: Improved Code Verification
|
||||
---
|
||||
|
||||
When verifying codes that a user has entered, there are other optional arguments which can improve verification of the code.
|
||||
|
||||
```php
|
||||
$result = $tfa->verifyCode($secret, $_POST['verification'], $discrepancy, $time, &$timeslice);
|
||||
```
|
||||
|
||||
## Discrepancy (default 1)
|
||||
|
||||
As the codes that are generated and accepted are consistent within a certain time window (i.e. a timeslice, 30 seconds long by default), it is very important that the server (and the users authenticator app) have the correct time (and date).
|
||||
|
||||
The value of `$discrepancy` is the number of timeslices checked in **both** directions of the current one. So when the current time is `14:34:21`, the 'current timeslice' is `14:34:00` to `14:34:30`. If the default is left unchanged, we also verify the code against the timeslice of `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`.
|
||||
|
||||
This should be sufficient for most cases however you can increase it if you wish. It would be unwise for this to be too high as it could allow a code to be valid for long enough that it could be used fraudulently.
|
||||
|
||||
## Time (default null)
|
||||
|
||||
The second, `$time`, allows you to check a code for a specific point in time. This argument has no real practical use but can be handy for unit testing. The default value, `null`, means: use the current time.
|
||||
|
||||
## Timeslice
|
||||
|
||||
`$timeslice` returns a value by reference. The value returned is the timeslice that matched the code (if any) or `0`.
|
||||
|
||||
You can store a timeslice alongside the secret and verify that any new timeslice is greater than the existing one.
|
||||
|
||||
i.e. if `verifyCode` returns true _and_ the returned timeslice is greater than the last used timeslice for this user/secret then this is the first time the code has been used and you should now store the higher timeslice to verify that the user.
|
||||
|
||||
This is an effective defense against a [replay attack](https://en.wikipedia.org/wiki/Replay_attack).
|
||||
18
vendor/robthree/twofactorauth/docs/index.md
vendored
18
vendor/robthree/twofactorauth/docs/index.md
vendored
@@ -1,18 +0,0 @@
|
||||
---
|
||||
title: Contents
|
||||
---
|
||||
|
||||
## [The Basics - Getting Started](getting-started.html)
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
[QR Codes](qr-codes.html)
|
||||
- [QRServerProvider](qr-codes/qr-server.html)
|
||||
- [ImageChartsQRCodeProvider](qr-codes/image-charts.html)
|
||||
- [QRicketProvider](qr-codes/qrickit.html)
|
||||
- [EndroidQrCodeProvider](qr-codes/endroid.html) (and EndroidQrCodeWithLogoProvider)
|
||||
- [BaconQRCodeProvider](qr-codes/bacon.html)
|
||||
|
||||
[Improved Code Verification](improved-code-verification.html)
|
||||
|
||||
[Other Optional Configuration](optional-configuration.html)
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: Optional Configuration
|
||||
---
|
||||
|
||||
## Instance Configuration
|
||||
|
||||
The instance (`new TwoFactorAuth()`) can only be configured by the constructor with the following optional arguments
|
||||
|
||||
Argument | Default value | Use
|
||||
------------------|-------------------|-----
|
||||
`$issuer` | `null` | Will be displayed in the users app as the default issuer name when using QR code to import the secret
|
||||
`$digits` | `6` | The number of digits the resulting codes will be
|
||||
`$period` | `30` | The number of seconds a code will be valid
|
||||
`$algorithm` | `Algorithm::Sha1` | The algorithm used (one of `Algorithm::Sha1`, `Algorithm::Sha256`, `Algorithm::Sha512`, `Algorithm::Md5`)
|
||||
`$qrcodeprovider` | `null` | QR-code provider
|
||||
`$rngprovider` | `null` | Random Number Generator provider
|
||||
`$timeprovider` | `null` | Time provider
|
||||
|
||||
**Note:** the default values for `$digits`, `$period`, and `$algorithm` provide the widest variety of support amongst common authenticator apps such as Google Authenticator. If you choose to use different values for these arguments you will likely have to instruct your users to use a specific app which supports your chosen configuration.
|
||||
|
||||
### RNG providers
|
||||
|
||||
Should you feel the need to use a CSPRNG different than `random_bytes()`, you can use the `rngprovider` argument of the constructor to provide an object implementing the [`IRNGProvider`](https://github.com/RobThree/TwoFactorAuth/blob/master/lib/Providers/Rng/IRNGProvider.php) interface.
|
||||
|
||||
### Time providers
|
||||
|
||||
These allow the TwoFactorAuth library to ensure the servers time is correct (or at least within a margin).
|
||||
|
||||
You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to the default `NTPTimeProvider` and `HttpTimeProvider`.
|
||||
|
||||
**Note:** the `NTPTimeProvider` requires your PHP to have the ability to create sockets. If you do not have that ability and wish to use this function, you should pass an array with only an instance of `HttpTimeProvider`.
|
||||
|
||||
Alternatively, you can pass an array of classes that implement the [`ITimeProvider` interface](https://github.com/RobThree/TwoFactorAuth/blob/master/lib/Providers/Time/ITimeProvider.php) to change this and specify the second argument, leniency in seconds (default: 5). An exception will be thrown if the time difference is greater than the leniency.
|
||||
|
||||
Ordinarily, you should not need to monitor that the time on the server is correct in this way however if you choose to, we advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `NTPTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the built-in ones (making use of a GPS signal for example).
|
||||
|
||||
## Secret Configuration
|
||||
|
||||
Secrets can be optionally configured with the following optional arguments
|
||||
|
||||
Argument | Default value | Use
|
||||
-----------------------|---------------|-----
|
||||
`$bits` | `80` | The number of bits (related to the length of the secret)
|
||||
`$requirecryptosecure` | `true` | Whether you want to require a cryptographically secure source of random numbers
|
||||
|
||||
**Note:** as above, these values provide the widest variety of support amongst common authenticator apps however you may choose to increase the value of `$bits` (160 or higher is recommended, see [RFC 4226 - Algorithm Requirements](https://tools.ietf.org/html/rfc4226#section-4)) as long as it is set to a multiple of 8.
|
||||
58
vendor/robthree/twofactorauth/docs/qr-codes.md
vendored
58
vendor/robthree/twofactorauth/docs/qr-codes.md
vendored
@@ -1,58 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: QR Codes
|
||||
---
|
||||
|
||||
An alternative way of communicating the secret to the user is through the use of [QR Codes](http://en.wikipedia.org/wiki/QR_code) which most if not all authenticator mobile apps can scan.
|
||||
|
||||
This can avoid accidental typing errors and also pre-set some text values within the two factor authentication mobile application.
|
||||
|
||||
You can display the QR Code as a base64 encoded image using the instance as follows, supplying the users name or other public identifier as the first argument
|
||||
|
||||
````php
|
||||
<p>Scan the following image with your app:</p>
|
||||
<img src="<?php echo $tfa->getQRCodeImageAsDataUri('Bob Ross', $secret); ?>">
|
||||
````
|
||||
|
||||
You can also specify a size as a third argument which is 200 by default.
|
||||
|
||||
## Offline Providers
|
||||
|
||||
[EndroidQrCodeProvider](qr-codes/endroid.md) and EndroidQrCodeWithLogoProvider
|
||||
|
||||
[BaconQRCodeProvider](qr-codes/bacon.md)
|
||||
|
||||
**Note:** offline providers may have additional PHP requirements in order to function, you should study what is required before trying to make use of them.
|
||||
|
||||
## Custom Provider
|
||||
|
||||
If you wish to make your own QR Code provider to reference another service or library, it must implement the [IQRCodeProvider interface](../lib/Providers/Qr/IQRCodeProvider.php).
|
||||
|
||||
It is recommended to use similar constructor arguments as the included providers to avoid big shifts when trying different providers.
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
// using a custom object implementing IQRCodeProvider
|
||||
$tfa = new TwoFactorAuth(new MyQrCodeProvider());
|
||||
// using named argument and a variable
|
||||
$tfa = new TwoFactorAuth(qrcodeprovider: $qrGenerator);
|
||||
```
|
||||
|
||||
## Online Providers
|
||||
|
||||
**Warning:** Using an external service for generating QR codes encoding authentication secrets is **not** recommended! You should instead make use of the included offline providers listed above.
|
||||
|
||||
* Gogr.me: [QRServerProvider](qr-codes/qr-server.md)
|
||||
* Image Charts: [ImageChartsQRCodeProvider](qr-codes/image-charts.md)
|
||||
* Qrickit: [QRicketProvider](qr-codes/qrickit.md)
|
||||
* Google Charts: [GoogleChartsQrCodeProvider](qr-codes/google-charts.md)
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\Providers\Qr\GoogleChartsQrCodeProvider;
|
||||
$tfa = new TwoFactorAuth(new GoogleChartsQrCodeProvider());
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: bacon/bacon-qr-code
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
In order to use this provider, you will need to install the library at version 2 (or later) and its dependencies
|
||||
|
||||
```
|
||||
composer require bacon/bacon-qr-code ^2.0
|
||||
```
|
||||
|
||||
You will also need the PHP imagick extension **if** you aren't using the SVG format.
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
--------------------|---------------
|
||||
`$borderWidth` | `4`
|
||||
`$backgroundColour` | `'#ffffff'`
|
||||
`$foregroundColour` | `'#000000'`
|
||||
`$format` | `'png'`
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: endroid/qr-code
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
In order to use this provider, you will need to install the library at version 3 and its dependencies
|
||||
|
||||
```
|
||||
composer require endroid/qr-code ^3.0
|
||||
```
|
||||
|
||||
You will also need the PHP gd extension installing.
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
------------------------|---------------
|
||||
`$bgcolor` | `'ffffff'`
|
||||
`$color` | `'000000'`
|
||||
`$margin` | `0`
|
||||
`$errorcorrectionlevel` | `'H'`
|
||||
|
||||
## Logo
|
||||
|
||||
If you make use of `EndroidQrCodeWithLogoProvider` then you have access to the `setLogo` function on the provider so you may add a logo to the centre of your QR code.
|
||||
|
||||
```php
|
||||
use RobThree\Auth\Providers\Qr\EndroidQrCodeWithLogoProvider;
|
||||
|
||||
$qrCodeProvider = new EndroidQrCodeWithLogoProvider();
|
||||
|
||||
$qrCodeProvider->setLogo('/path/to/your/image');
|
||||
```
|
||||
|
||||
You can see how to also set the size of the logo in the [source code](https://github.com/RobThree/TwoFactorAuth/blob/master/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php).
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: QR GoogleCharts
|
||||
---
|
||||
|
||||
See: https://developers.google.com/chart/infographics/docs/qr_codes
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
------------------------|---------------
|
||||
`$verifyssl` | `false`
|
||||
`$errorcorrectionlevel` | `'L'`
|
||||
`$margin` | `4`
|
||||
`$encoding` | `'UTF-8'`
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: Image-Charts
|
||||
---
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
------------------------|---------------
|
||||
`$verifyssl` | `true`
|
||||
`$errorcorrectionlevel` | `'L'`
|
||||
`$margin` | `4`
|
||||
|
||||
`$verifyssl` is used internally to help guarantee the security of the connection. It is possible that where you are running the code from will have problems verifying an SSL connection so if you know this is not the case, you can supply `true`.
|
||||
|
||||
The other parameters are passed to [Image-Charts](https://documentation.image-charts.com/qr-codes/) so you can refer to them for more detail on how the values are used.
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: QR Server
|
||||
---
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
------------------------|---------------
|
||||
`$verifyssl` | `true`
|
||||
`$errorcorrectionlevel` | `'L'`
|
||||
`$margin` | `4`
|
||||
`$qzone` | `1`
|
||||
`$bgcolor` | `'ffffff'`
|
||||
`$color` | `'000000'`
|
||||
`$format` | `'png'`
|
||||
|
||||
`$verifyssl` is used internally to help guarantee the security of the connection. It is possible that where you are running the code from will have problems verifying an SSL connection so if you know this is not the case, you can supply `true`.
|
||||
|
||||
The other parameters are passed to [goqr.me](http://goqr.me/api/doc/create-qr-code/) so you can refer to them for more detail on how the values are used.
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
title: QRickit
|
||||
---
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
Argument | Default value
|
||||
------------------------|---------------
|
||||
`$errorcorrectionlevel` | `'L'`
|
||||
`$bgcolor` | `'ffffff'`
|
||||
`$color` | `'000000'`
|
||||
`$format` | `'png'`
|
||||
|
||||
The parameters are passed to [QRickit](http://qrickit.com/qrickit_apps/qrickit_api.php) so you can refer to them for more detail on how the values are used.
|
||||
BIN
vendor/robthree/twofactorauth/logo.png
vendored
BIN
vendor/robthree/twofactorauth/logo.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
12
vendor/robthree/twofactorauth/phpstan.neon
vendored
12
vendor/robthree/twofactorauth/phpstan.neon
vendored
@@ -1,12 +0,0 @@
|
||||
parameters:
|
||||
level: 6
|
||||
|
||||
excludePaths:
|
||||
- %currentWorkingDirectory%/lib/Providers/Qr/BaconQrCodeProvider.php
|
||||
- %currentWorkingDirectory%/lib/Providers/Qr/EndroidQrCodeProvider.php
|
||||
- %currentWorkingDirectory%/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php
|
||||
|
||||
paths:
|
||||
- %currentWorkingDirectory%/lib
|
||||
- %currentWorkingDirectory%/tests
|
||||
|
||||
27
vendor/robthree/twofactorauth/phpunit.xml
vendored
27
vendor/robthree/twofactorauth/phpunit.xml
vendored
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./lib</directory>
|
||||
</include>
|
||||
<report>
|
||||
<html outputDirectory="build/coverage"/>
|
||||
<text outputFile="php://stdout"/>
|
||||
</report>
|
||||
</coverage>
|
||||
</phpunit>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Qr;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
use RobThree\Auth\Providers\Qr\IQRCodeProvider;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\TwoFactorAuthException;
|
||||
|
||||
class IQRCodeProviderTest extends TestCase
|
||||
{
|
||||
use HandlesDataUri;
|
||||
|
||||
protected IQRCodeProvider $qr;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->qr = new TestQrProvider();
|
||||
}
|
||||
|
||||
public function testTotpUriIsCorrect(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth($this->qr, 'Test&Issuer', 6, 30, Algorithm::Sha1);
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertSame('test/test', $data['mimetype']);
|
||||
$this->assertSame('base64', $data['encoding']);
|
||||
$this->assertSame('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']);
|
||||
}
|
||||
|
||||
public function testTotpUriIsCorrectNoIssuer(): void
|
||||
{
|
||||
/**
|
||||
* The library specifies the issuer is null by default however in PHP 8.1
|
||||
* there is a deprecation warning for passing null as a string argument to rawurlencode
|
||||
*/
|
||||
|
||||
$tfa = new TwoFactorAuth($this->qr, null, 6, 30, Algorithm::Sha1);
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertSame('test/test', $data['mimetype']);
|
||||
$this->assertSame('base64', $data['encoding']);
|
||||
$this->assertSame('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=&period=30&algorithm=SHA1&digits=6@200', $data['data']);
|
||||
}
|
||||
|
||||
public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth($this->qr, 'Test', 6, 30, Algorithm::Sha1);
|
||||
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
$tfa->getQRCodeImageAsDataUri('Test', 'VMR466AB62ZBOKHE', 0);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Qr;
|
||||
|
||||
use RobThree\Auth\Providers\Qr\IQRCodeProvider;
|
||||
|
||||
class TestQrProvider implements IQRCodeProvider
|
||||
{
|
||||
public function getQRCodeImage(string $qrText, int $size): string
|
||||
{
|
||||
return $qrText . '@' . $size;
|
||||
}
|
||||
|
||||
public function getMimeType(): string
|
||||
{
|
||||
return 'test/test';
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Rng;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Providers\Rng\CSRNGProvider;
|
||||
|
||||
class CSRNGProviderTest extends TestCase
|
||||
{
|
||||
use NeedsRngLengths;
|
||||
|
||||
public function testCSRNGProvidersReturnExpectedNumberOfBytes(): void
|
||||
{
|
||||
$rng = new CSRNGProvider();
|
||||
foreach ($this->rngTestLengths as $l) {
|
||||
$this->assertSame($l, strlen($rng->getRandomBytes($l)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Rng;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use Tests\Providers\Qr\TestQrProvider;
|
||||
|
||||
class IRNGProviderTest extends TestCase
|
||||
{
|
||||
public function testCreateSecret(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30, Algorithm::Sha1, null, null);
|
||||
$this->assertIsString($tfa->createSecret());
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Rng;
|
||||
|
||||
trait NeedsRngLengths
|
||||
{
|
||||
/** @var array<int> */
|
||||
protected $rngTestLengths = array(1, 16, 32, 256);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Time;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\TwoFactorAuthException;
|
||||
use Tests\Providers\Qr\TestQrProvider;
|
||||
|
||||
class ITimeProviderTest extends TestCase
|
||||
{
|
||||
public function testEnsureCorrectTimeDoesNotThrowForCorrectTime(): void
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$tpr1 = new TestTimeProvider(123);
|
||||
$tpr2 = new TestTimeProvider(128);
|
||||
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30, Algorithm::Sha1, null, $tpr1);
|
||||
$tfa->ensureCorrectTime(array($tpr2)); // 128 - 123 = 5 => within default leniency
|
||||
}
|
||||
|
||||
public function testEnsureCorrectTimeThrowsOnIncorrectTime(): void
|
||||
{
|
||||
$tpr1 = new TestTimeProvider(123);
|
||||
$tpr2 = new TestTimeProvider(124);
|
||||
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30, Algorithm::Sha1, null, $tpr1);
|
||||
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
$tfa->ensureCorrectTime(array($tpr2), 0); // We force a leniency of 0, 124-123 = 1 so this should throw
|
||||
}
|
||||
|
||||
public function testEnsureDefaultTimeProviderReturnsCorrectTime(): void
|
||||
{
|
||||
$this->expectNotToPerformAssertions();
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30, Algorithm::Sha1);
|
||||
$tfa->ensureCorrectTime(array(new TestTimeProvider(time())), 1); // Use a leniency of 1, should the time change between both time() calls
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Providers\Time;
|
||||
|
||||
use RobThree\Auth\Providers\Time\ITimeProvider;
|
||||
|
||||
class TestTimeProvider implements ITimeProvider
|
||||
{
|
||||
/** @var int */
|
||||
private $time;
|
||||
|
||||
/**
|
||||
* @param int $time
|
||||
*/
|
||||
public function __construct($time)
|
||||
{
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTime()
|
||||
{
|
||||
return $this->time;
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionMethod;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\Providers\Time\HttpTimeProvider;
|
||||
use RobThree\Auth\Providers\Time\NTPTimeProvider;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\TwoFactorAuthException;
|
||||
use Tests\Providers\Qr\TestQrProvider;
|
||||
|
||||
class TwoFactorAuthTest extends TestCase
|
||||
{
|
||||
public function testConstructorThrowsOnInvalidDigits(): void
|
||||
{
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
new TwoFactorAuth(new TestQrProvider(), 'Test', 0);
|
||||
}
|
||||
|
||||
public function testConstructorThrowsOnInvalidPeriod(): void
|
||||
{
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 0);
|
||||
}
|
||||
|
||||
public function testGetCodeReturnsCorrectResults(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test');
|
||||
$this->assertSame('543160', $tfa->getCode('VMR466AB62ZBOKHE', 1426847216));
|
||||
$this->assertSame('538532', $tfa->getCode('VMR466AB62ZBOKHE', 0));
|
||||
}
|
||||
|
||||
public function testEnsureAllTimeProvidersReturnCorrectTime(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30, Algorithm::Sha1);
|
||||
$tfa->ensureCorrectTime(array(
|
||||
new NTPTimeProvider(), // Uses pool.ntp.org by default
|
||||
//new \RobThree\Auth\Providers\Time\NTPTimeProvider('time.google.com'), // Somehow time.google.com and time.windows.com make travis timeout??
|
||||
new HttpTimeProvider(), // Uses google.com by default
|
||||
//new \RobThree\Auth\Providers\Time\HttpTimeProvider('https://github.com'), // github.com will periodically report times that are off by more than 5 sec
|
||||
new HttpTimeProvider('https://yahoo.com'),
|
||||
));
|
||||
$this->expectNotToPerformAssertions();
|
||||
}
|
||||
|
||||
public function testVerifyCodeWorksCorrectly(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847190));
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 29)); //Test discrepancy
|
||||
$this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 30)); //Test discrepancy
|
||||
$this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 - 1)); //Test discrepancy
|
||||
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205)); //Test discrepancy
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 35)); //Test discrepancy
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 35)); //Test discrepancy
|
||||
|
||||
$this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 65)); //Test discrepancy
|
||||
$this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 65)); //Test discrepancy
|
||||
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 + 65)); //Test discrepancy
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy
|
||||
}
|
||||
|
||||
public function testVerifyCorrectTimeSliceIsReturned(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 6, 30);
|
||||
|
||||
// We test with discrepancy 3 (so total of 7 codes: c-3, c-2, c-1, c, c+1, c+2, c+3
|
||||
// Ensure each corresponding timeslice is returned correctly
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '534113', 3, 1426847190, $timeslice1));
|
||||
$this->assertSame(47561570, $timeslice1);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '819652', 3, 1426847190, $timeslice2));
|
||||
$this->assertSame(47561571, $timeslice2);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '915954', 3, 1426847190, $timeslice3));
|
||||
$this->assertSame(47561572, $timeslice3);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 3, 1426847190, $timeslice4));
|
||||
$this->assertSame(47561573, $timeslice4);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '348401', 3, 1426847190, $timeslice5));
|
||||
$this->assertSame(47561574, $timeslice5);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '648525', 3, 1426847190, $timeslice6));
|
||||
$this->assertSame(47561575, $timeslice6);
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '170645', 3, 1426847190, $timeslice7));
|
||||
$this->assertSame(47561576, $timeslice7);
|
||||
|
||||
// Incorrect code should return false and a 0 timeslice
|
||||
$this->assertFalse($tfa->verifyCode('VMR466AB62ZBOKHE', '111111', 3, 1426847190, $timeslice8));
|
||||
$this->assertSame(0, $timeslice8);
|
||||
}
|
||||
|
||||
public function testGetCodeThrowsOnInvalidBase32String1(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test');
|
||||
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
$tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars
|
||||
}
|
||||
|
||||
public function testGetCodeThrowsOnInvalidBase32String2(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test');
|
||||
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
|
||||
$tfa->getCode('mzxw6==='); //Lowercase
|
||||
}
|
||||
|
||||
public function testKnownBase32DecodeTestVectors(): void
|
||||
{
|
||||
// We usually don't test internals (e.g. privates) but since we rely heavily on base32 decoding and don't want
|
||||
// to expose this method nor do we want to give people the possibility of implementing / providing their own base32
|
||||
// decoding/decoder (as we do with Rng/QR providers for example) we simply test the private base32Decode() method
|
||||
// with some known testvectors **only** to ensure base32 decoding works correctly following RFC's so there won't
|
||||
// be any bugs hiding in there. We **could** 'fool' ourselves by calling the public getCode() method (which uses
|
||||
// base32decode internally) and then make sure getCode's output (in digits) equals expected output since that would
|
||||
// mean the base32Decode() works as expected but that **could** hide some subtle bug(s) in decoding the base32 string.
|
||||
|
||||
// "In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't
|
||||
// expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods."
|
||||
// Dave Thomas and Andy Hunt -- "Pragmatic Unit Testing
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test');
|
||||
|
||||
$method = new ReflectionMethod(TwoFactorAuth::class, 'base32Decode');
|
||||
|
||||
// Test vectors from: https://tools.ietf.org/html/rfc4648#page-12
|
||||
$this->assertSame('', $method->invoke($tfa, ''));
|
||||
$this->assertSame('f', $method->invoke($tfa, 'MY======'));
|
||||
$this->assertSame('fo', $method->invoke($tfa, 'MZXQ===='));
|
||||
$this->assertSame('foo', $method->invoke($tfa, 'MZXW6==='));
|
||||
$this->assertSame('foob', $method->invoke($tfa, 'MZXW6YQ='));
|
||||
$this->assertSame('fooba', $method->invoke($tfa, 'MZXW6YTB'));
|
||||
$this->assertSame('foobar', $method->invoke($tfa, 'MZXW6YTBOI======'));
|
||||
}
|
||||
|
||||
public function testKnownBase32DecodeUnpaddedTestVectors(): void
|
||||
{
|
||||
// See testKnownBase32DecodeTestVectors() for the rationale behind testing the private base32Decode() method.
|
||||
// This test ensures that strings without the padding-char ('=') are also decoded correctly.
|
||||
// https://tools.ietf.org/html/rfc4648#page-4:
|
||||
// "In some circumstances, the use of padding ("=") in base-encoded data is not required or used."
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test');
|
||||
|
||||
$method = new ReflectionMethod(TwoFactorAuth::class, 'base32Decode');
|
||||
|
||||
// Test vectors from: https://tools.ietf.org/html/rfc4648#page-12
|
||||
$this->assertSame('', $method->invoke($tfa, ''));
|
||||
$this->assertSame('f', $method->invoke($tfa, 'MY'));
|
||||
$this->assertSame('fo', $method->invoke($tfa, 'MZXQ'));
|
||||
$this->assertSame('foo', $method->invoke($tfa, 'MZXW6'));
|
||||
$this->assertSame('foob', $method->invoke($tfa, 'MZXW6YQ'));
|
||||
$this->assertSame('fooba', $method->invoke($tfa, 'MZXW6YTB'));
|
||||
$this->assertSame('foobar', $method->invoke($tfa, 'MZXW6YTBOI'));
|
||||
}
|
||||
|
||||
public function testKnownTestVectors_sha1(): void
|
||||
{
|
||||
//Known test vectors for SHA1: https://tools.ietf.org/html/rfc6238#page-15
|
||||
$secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ'; //== base32encode('12345678901234567890')
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 8, 30, Algorithm::Sha1);
|
||||
$this->assertSame('94287082', $tfa->getCode($secret, 59));
|
||||
$this->assertSame('07081804', $tfa->getCode($secret, 1111111109));
|
||||
$this->assertSame('14050471', $tfa->getCode($secret, 1111111111));
|
||||
$this->assertSame('89005924', $tfa->getCode($secret, 1234567890));
|
||||
$this->assertSame('69279037', $tfa->getCode($secret, 2000000000));
|
||||
$this->assertSame('65353130', $tfa->getCode($secret, 20000000000));
|
||||
}
|
||||
|
||||
public function testKnownTestVectors_sha256(): void
|
||||
{
|
||||
//Known test vectors for SHA256: https://tools.ietf.org/html/rfc6238#page-15
|
||||
$secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA'; //== base32encode('12345678901234567890123456789012')
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 8, 30, Algorithm::Sha256);
|
||||
$this->assertSame('46119246', $tfa->getCode($secret, 59));
|
||||
$this->assertSame('68084774', $tfa->getCode($secret, 1111111109));
|
||||
$this->assertSame('67062674', $tfa->getCode($secret, 1111111111));
|
||||
$this->assertSame('91819424', $tfa->getCode($secret, 1234567890));
|
||||
$this->assertSame('90698825', $tfa->getCode($secret, 2000000000));
|
||||
$this->assertSame('77737706', $tfa->getCode($secret, 20000000000));
|
||||
}
|
||||
|
||||
public function testKnownTestVectors_sha512(): void
|
||||
{
|
||||
//Known test vectors for SHA512: https://tools.ietf.org/html/rfc6238#page-15
|
||||
$secret = 'GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNA'; //== base32encode('1234567890123456789012345678901234567890123456789012345678901234')
|
||||
$tfa = new TwoFactorAuth(new TestQrProvider(), 'Test', 8, 30, Algorithm::Sha512);
|
||||
$this->assertSame('90693936', $tfa->getCode($secret, 59));
|
||||
$this->assertSame('25091201', $tfa->getCode($secret, 1111111109));
|
||||
$this->assertSame('99943326', $tfa->getCode($secret, 1111111111));
|
||||
$this->assertSame('93441116', $tfa->getCode($secret, 1234567890));
|
||||
$this->assertSame('38618901', $tfa->getCode($secret, 2000000000));
|
||||
$this->assertSame('47863826', $tfa->getCode($secret, 20000000000));
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TestsDependency;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\Providers\Qr\BaconQrCodeProvider;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
use RobThree\Auth\Providers\Qr\IQRCodeProvider;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RuntimeException;
|
||||
|
||||
class BaconQRCodeTest extends TestCase
|
||||
{
|
||||
use HandlesDataUri;
|
||||
|
||||
protected IQRCodeProvider $qr;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->qr = new BaconQrCodeProvider(1, '#000', '#FFF', 'svg');
|
||||
;
|
||||
}
|
||||
|
||||
public function testDependency(): void
|
||||
{
|
||||
$tfa = new TwoFactorAuth($this->qr, 'Test&Issuer', 6, 30, Algorithm::Sha1);
|
||||
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertSame('image/svg+xml', $data['mimetype']);
|
||||
}
|
||||
|
||||
public function testBadTextColour(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, 'not-a-colour', '#FFF');
|
||||
}
|
||||
|
||||
public function testBadBackgroundColour(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#000', 'not-a-colour');
|
||||
}
|
||||
|
||||
public function testBadTextColourHexRef(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#AAAA', '#FFF');
|
||||
}
|
||||
|
||||
public function testBadBackgroundColourHexRef(): void
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#000', '#AAAA');
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TestsDependency;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Algorithm;
|
||||
use RobThree\Auth\Providers\Qr\EndroidQrCodeProvider;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
|
||||
class EndroidQRCodeTest extends TestCase
|
||||
{
|
||||
use HandlesDataUri;
|
||||
|
||||
public function testDependency(): void
|
||||
{
|
||||
$qr = new EndroidQrCodeProvider();
|
||||
$tfa = new TwoFactorAuth($qr, 'Test&Issuer', 6, 30, Algorithm::Sha1);
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertSame('image/png', $data['mimetype']);
|
||||
$this->assertSame('base64', $data['encoding']);
|
||||
$this->assertNotEmpty($data['data']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user