fix create invoice token issue (#3007)

This commit is contained in:
Kevin Papst
2021-12-09 01:36:58 +01:00
committed by GitHub
parent 22ce6b047a
commit 573fa9f7f3
4 changed files with 23 additions and 26 deletions

View File

@@ -17,11 +17,11 @@ class Constants
/** /**
* The current release version * The current release version
*/ */
public const VERSION = '1.16.7'; public const VERSION = '1.16.8';
/** /**
* The current release: major * 10000 + minor * 100 + patch * The current release: major * 10000 + minor * 100 + patch
*/ */
public const VERSION_ID = 11607; public const VERSION_ID = 11608;
/** /**
* The current release status, either "stable" or "dev" * The current release status, either "stable" or "dev"
*/ */

View File

@@ -134,22 +134,16 @@ final class InvoiceController extends AbstractController
} }
/** /**
* @Route(path="/preview/{customer}", name="invoice_preview", methods={"GET"}) * @Route(path="/preview/{customer}/{token}", name="invoice_preview", methods={"GET"})
* @Security("is_granted('access', customer)") * @Security("is_granted('access', customer)")
* @Security("is_granted('create_invoice')") * @Security("is_granted('create_invoice')")
*/ */
public function previewAction(Customer $customer, Request $request, SystemConfiguration $configuration): Response public function previewAction(Customer $customer, string $token, Request $request, SystemConfiguration $configuration): Response
{ {
if (!$this->templateRepository->hasTemplate()) { if (!$this->templateRepository->hasTemplate()) {
return $this->redirectToRoute('invoice'); return $this->redirectToRoute('invoice');
} }
$token = null;
if ($request->query->has('token')) {
$token = $request->query->get('token');
$request->query->remove('token');
}
if (!$this->isCsrfTokenValid('invoice.preview', $token)) { if (!$this->isCsrfTokenValid('invoice.preview', $token)) {
$this->flashError('action.csrf.error'); $this->flashError('action.csrf.error');
@@ -183,30 +177,22 @@ final class InvoiceController extends AbstractController
} }
/** /**
* @Route(path="/save-invoice/{customer}/{template}", name="invoice_create", methods={"GET"}) * @Route(path="/save-invoice/{customer}/{template}/{token}", name="invoice_create", methods={"GET"})
* @Security("is_granted('access', customer)") * @Security("is_granted('access', customer)")
* @Security("is_granted('create_invoice')") * @Security("is_granted('create_invoice')")
*/ */
public function createInvoiceAction(Customer $customer, InvoiceTemplate $template, Request $request, SystemConfiguration $configuration, CsrfTokenManagerInterface $csrfTokenManager): Response public function createInvoiceAction(Customer $customer, InvoiceTemplate $template, string $token, Request $request, SystemConfiguration $configuration, CsrfTokenManagerInterface $csrfTokenManager): Response
{ {
if (!$this->templateRepository->hasTemplate()) { if (!$this->templateRepository->hasTemplate()) {
return $this->redirectToRoute('invoice'); return $this->redirectToRoute('invoice');
} }
$token = null;
if ($request->query->has('token')) {
$token = $request->query->get('token');
$request->query->remove('token');
}
if (!$this->isCsrfTokenValid('invoice.create', $token)) { if (!$this->isCsrfTokenValid('invoice.create', $token)) {
$this->flashError('action.csrf.error'); $this->flashError('action.csrf.error');
return $this->redirectToRoute('invoice'); return $this->redirectToRoute('invoice');
} }
$csrfTokenManager->refreshToken('invoice.create');
$query = $this->getDefaultQuery(); $query = $this->getDefaultQuery();
$form = $this->getToolbarForm($query, $configuration->find('invoice.simple_form')); $form = $this->getToolbarForm($query, $configuration->find('invoice.simple_form'));
if ($this->handleSearch($form, $request)) { if ($this->handleSearch($form, $request)) {

View File

@@ -109,8 +109,8 @@
</td> </td>
<td class="w-min text-center"> <td class="w-min text-center">
{{ widgets.action_button('show', {'url': '#invoice_preview_details_' ~ model.customer.id, 'title': 'timesheet.all'|trans, 'class': 'btn btn-sm hidden-xs hidden-sm'}, 'link') }} {{ widgets.action_button('show', {'url': '#invoice_preview_details_' ~ model.customer.id, 'title': 'timesheet.all'|trans, 'class': 'btn btn-sm hidden-xs hidden-sm'}, 'link') }}
{{ widgets.action_button('print', {'url': '#', 'onclick': 'return singleInvoice(this)', 'title': 'button.preview'|trans, 'target': '_blank', 'class': 'btn btn-sm', 'attr': {'data-customer': model.customer.id, 'data-template': model.template.id, 'data-href': path('invoice_preview', {'customer': model.customer.id})}}) }} {{ widgets.action_button('print', {'url': '#', 'onclick': 'return singleInvoice(this)', 'title': 'button.preview'|trans, 'target': '_blank', 'class': 'btn btn-sm', 'attr': {'data-customer': model.customer.id, 'data-template': model.template.id, 'data-href': path('invoice_preview', {'customer': model.customer.id, 'token': csrf_token('invoice.preview')})}}) }}
{{ widgets.action_button('save', {'url': '#', 'onclick': 'return singleInvoice(this)', 'title': 'action.save'|trans, 'class': 'btn btn-sm', 'attr': {'data-customer': model.customer.id, 'data-template': model.template.id, 'data-href': path('invoice_create', {'customer': model.customer.id, 'template': model.template.id})}}, 'success') }} {{ widgets.action_button('save', {'url': '#', 'onclick': 'return singleInvoice(this)', 'title': 'action.save'|trans, 'class': 'btn btn-sm', 'attr': {'data-customer': model.customer.id, 'data-template': model.template.id, 'data-href': path('invoice_create', {'customer': model.customer.id, 'template': model.template.id, 'token': csrf_token('invoice.create')})}}, 'success') }}
</td> </td>
<td class="w-min text-right hidden-xs"> <td class="w-min text-right hidden-xs">
{{ model.calculator.timeWorked|duration(isDecimal) }} {{ model.calculator.timeWorked|duration(isDecimal) }}
@@ -218,7 +218,7 @@
const overwrites = {'customers[]': link.dataset['customer'], 'template': link.dataset['template']}; const overwrites = {'customers[]': link.dataset['customer'], 'template': link.dataset['template']};
const uri = formPlugin.convertFormDataToQueryString(document.getElementById('{{ formId }}'), overwrites); const uri = formPlugin.convertFormDataToQueryString(document.getElementById('{{ formId }}'), overwrites);
link.href = link.dataset['href'] + '?token={{ csrf_token('invoice.preview') }}&' + uri; link.href = link.dataset['href'] + '?' + uri;
return true; return true;
} }

View File

@@ -194,7 +194,7 @@ class InvoiceControllerTest extends ControllerBaseTest
/** @var CsrfToken $token */ /** @var CsrfToken $token */
$token = self::$container->get('security.csrf.token_manager')->getToken('invoice.create'); $token = self::$container->get('security.csrf.token_manager')->getToken('invoice.create');
$action = '/invoice/save-invoice/1/' . $template->getId() . '?token=' . $token->getValue() . '&' . http_build_query($urlParams); $action = '/invoice/save-invoice/1/' . $template->getId() . '/' . $token->getValue() . '?' . http_build_query($urlParams);
$this->request($client, $action); $this->request($client, $action);
$this->assertIsRedirect($client); $this->assertIsRedirect($client);
$this->assertRedirectUrl($client, '/invoice/show?id=', false); $this->assertRedirectUrl($client, '/invoice/show?id=', false);
@@ -234,18 +234,29 @@ class InvoiceControllerTest extends ControllerBaseTest
$dateRange = $begin->format('Y-m-d') . DateRangeType::DATE_SPACER . $end->format('Y-m-d'); $dateRange = $begin->format('Y-m-d') . DateRangeType::DATE_SPACER . $end->format('Y-m-d');
$form = $client->getCrawler()->filter('#invoice-print-form')->form();
$node = $form->getFormNode();
$node->setAttribute('action', $this->createUrl('/invoice/'));
$node->setAttribute('method', 'GET');
$client->submit($form, [
'template' => $id,
'daterange' => $dateRange,
'customers' => [1],
]);
$this->assertTrue($client->getResponse()->isSuccessful());
/** @var CsrfToken $token */ /** @var CsrfToken $token */
$token = self::$container->get('security.csrf.token_manager')->getToken('invoice.preview'); $token = self::$container->get('security.csrf.token_manager')->getToken('invoice.preview');
$params = [ $params = [
'token' => $token->getValue(),
'daterange' => $dateRange, 'daterange' => $dateRange,
'projects' => [1], 'projects' => [1],
'template' => $id, 'template' => $id,
'customers[]' => 1 'customers[]' => 1
]; ];
$action = '/invoice/preview/1?' . http_build_query($params); $action = '/invoice/preview/1/' . $token->getValue() . '?' . http_build_query($params);
$this->request($client, $action); $this->request($client, $action);
$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isSuccessful());
$node = $client->getCrawler()->filter('body'); $node = $client->getCrawler()->filter('body');