diff --git a/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml b/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml index bbbc22238..e0d8e06e4 100644 --- a/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml +++ b/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml @@ -19,6 +19,7 @@ @await RenderSectionAsync("head", false) +@Html.AntiForgeryToken() @await Component.InvokeAsync("Widget", new { widgetZone = "body_start_html_tag_after" }) diff --git a/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs b/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs index 5b5afee97..6521f45ef 100644 --- a/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs +++ b/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs @@ -8,6 +8,7 @@ namespace Grand.Web.Common.Controllers; [ClosedStore] [Language] [Affiliate] +[AutoValidateAntiforgeryToken] [SharedKernel.Attributes.ApiController] public abstract class BasePublicController : BaseController { diff --git a/src/Web/Grand.Web/Controllers/AccountController.cs b/src/Web/Grand.Web/Controllers/AccountController.cs index 8169012a0..683cfe44e 100644 --- a/src/Web/Grand.Web/Controllers/AccountController.cs +++ b/src/Web/Grand.Web/Controllers/AccountController.cs @@ -195,7 +195,6 @@ public virtual IActionResult Login(bool? checkoutAsGuest) //available even when navigation is not allowed [PublicStore(true)] [ClosedStore(true)] - [AutoValidateAntiforgeryToken] [IgnoreApi] public virtual async Task Login(LoginModel model, string returnUrl) { @@ -367,7 +366,6 @@ public virtual IActionResult PasswordRecovery() } [HttpPost] - [AutoValidateAntiforgeryToken] [PublicStore(true)] public virtual async Task> PasswordRecovery(PasswordRecoveryModel model) { @@ -400,7 +398,6 @@ public virtual async Task> PasswordRe } [HttpPost] - [AutoValidateAntiforgeryToken] //available even when navigation is not allowed [PublicStore(true)] public virtual async Task PasswordRecoveryConfirm(PasswordRecoveryConfirmModel model) @@ -447,7 +444,6 @@ public virtual async Task> Register() } [HttpPost] - [AutoValidateAntiforgeryToken] //available even when navigation is not allowed [PublicStore(true)] public virtual async Task Register(RegisterModel model, string returnUrl) @@ -570,7 +566,6 @@ public virtual IActionResult RegisterResult(int resultId) } [HttpPost] - [AutoValidateAntiforgeryToken] //available even when navigation is not allowed [PublicStore(true)] public virtual async Task CheckUsernameAvailability(string username) @@ -647,7 +642,6 @@ public virtual async Task> Info() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task> Info(CustomerInfoModel model) { @@ -683,7 +677,6 @@ await _mediator.Send(new UpdateCustomerInfoCommand { } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task RemoveExternalAssociation(string id, [FromServices] IExternalAuthenticationService openAuthenticationService) @@ -733,7 +726,6 @@ public virtual async Task> Addresses() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task AddressDelete(string addressId) { @@ -776,7 +768,6 @@ public virtual async Task> AddressAdd() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task> AddressAdd(CustomerAddressEditModel model, [FromServices] AddressSettings addressSettings) @@ -841,7 +832,6 @@ public virtual async Task> AddressEdit(st } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task> AddressEdit(CustomerAddressEditModel model, [FromServices] AddressSettings addressSettings) @@ -929,7 +919,6 @@ public virtual async Task ChangePassword() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task ChangePassword(ChangePasswordModel model) { @@ -965,7 +954,6 @@ public virtual IActionResult DeleteAccount() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task DeleteAccount(DeleteAccountModel model) { @@ -1152,7 +1140,6 @@ public virtual async Task SubAccountAdd() } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task SubAccountAdd(SubAccountCreateModel model) { @@ -1184,7 +1171,6 @@ public virtual async Task SubAccountEdit(string id) } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task SubAccountEdit(SubAccountEditModel model) { @@ -1203,7 +1189,6 @@ public virtual async Task SubAccountEdit(SubAccountEditModel mode } [HttpPost] - [AutoValidateAntiforgeryToken] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task SubAccountDelete(string id) { diff --git a/src/Web/Grand.Web/Controllers/BlogController.cs b/src/Web/Grand.Web/Controllers/BlogController.cs index 7fa0f9adb..083bcf71e 100644 --- a/src/Web/Grand.Web/Controllers/BlogController.cs +++ b/src/Web/Grand.Web/Controllers/BlogController.cs @@ -130,7 +130,6 @@ await permissionService.Authorize(StandardPermission.ManageBlog)) } [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task> BlogPost(AddBlogCommentModel model, [FromServices] IAclService aclService) diff --git a/src/Web/Grand.Web/Controllers/CatalogController.cs b/src/Web/Grand.Web/Controllers/CatalogController.cs index 0ba64bc6b..953f1b310 100644 --- a/src/Web/Grand.Web/Controllers/CatalogController.cs +++ b/src/Web/Grand.Web/Controllers/CatalogController.cs @@ -318,7 +318,6 @@ public virtual async Task VendorAll(VendorPagingModel command) #region Vendor reviews [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task VendorReviews(VendorReviewsModel model) { diff --git a/src/Web/Grand.Web/Controllers/ContactController.cs b/src/Web/Grand.Web/Controllers/ContactController.cs index c45557336..206ebc5ef 100644 --- a/src/Web/Grand.Web/Controllers/ContactController.cs +++ b/src/Web/Grand.Web/Controllers/ContactController.cs @@ -59,7 +59,6 @@ public virtual async Task> Index( } [HttpPost] - [AutoValidateAntiforgeryToken] [ClosedStore(true)] [DenySystemAccount] public virtual async Task> Index( diff --git a/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs b/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs index de16e61d0..353165f54 100644 --- a/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs +++ b/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs @@ -264,7 +264,6 @@ private async Task PrepareKnowledgebaseArticleModel(KnowledgebaseArticleModel mo } [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task ArticleCommentAdd(KnowledgebaseArticleModel model, [FromServices] ICustomerService customerService) diff --git a/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs b/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs index a8cebfab4..61e0fd2a8 100644 --- a/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs +++ b/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs @@ -138,7 +138,6 @@ public virtual async Task MerchandiseReturn(string orderId) } [HttpPost] - [AutoValidateAntiforgeryToken] public virtual async Task MerchandiseReturn(MerchandiseReturnModel model) { var order = await _orderService.GetOrderById(model.OrderId); diff --git a/src/Web/Grand.Web/Controllers/NewsController.cs b/src/Web/Grand.Web/Controllers/NewsController.cs index 5851d33be..2b7694469 100644 --- a/src/Web/Grand.Web/Controllers/NewsController.cs +++ b/src/Web/Grand.Web/Controllers/NewsController.cs @@ -91,7 +91,6 @@ await _permissionService.Authorize(StandardPermission.ManageNews)) } [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task NewsCommentAdd(AddNewsCommentModel model) { diff --git a/src/Web/Grand.Web/Controllers/OrderController.cs b/src/Web/Grand.Web/Controllers/OrderController.cs index 883634f00..647be5489 100644 --- a/src/Web/Grand.Web/Controllers/OrderController.cs +++ b/src/Web/Grand.Web/Controllers/OrderController.cs @@ -135,7 +135,6 @@ public virtual async Task GetPdfInvoice(string orderId, [FromServ //My account / Order details page / Add order note [HttpPost] - [AutoValidateAntiforgeryToken] public virtual async Task> AddOrderNote(AddOrderNoteModel model) { if (!_orderSettings.AllowCustomerToAddOrderNote) @@ -174,7 +173,6 @@ public virtual async Task ReOrder(string orderId) //My account / Order details page / Complete payment [HttpPost] - [AutoValidateAntiforgeryToken] public virtual async Task RePostPayment(string orderId) { var order = await _orderService.GetOrderById(orderId); diff --git a/src/Web/Grand.Web/Controllers/ProductController.cs b/src/Web/Grand.Web/Controllers/ProductController.cs index 6e45d6a83..d751d31c3 100644 --- a/src/Web/Grand.Web/Controllers/ProductController.cs +++ b/src/Web/Grand.Web/Controllers/ProductController.cs @@ -136,7 +136,6 @@ public virtual async Task NewProducts() #region Email a friend [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task ProductEmailAFriend(ProductEmailAFriendModel model) { @@ -180,7 +179,6 @@ await _mediator.Send(new SendProductEmailAFriendMessageCommand { #region Ask question [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task AskQuestionOnProduct(ProductAskQuestionSimpleModel model) { @@ -549,7 +547,6 @@ public virtual async Task QuickView(string productId) #region Product reviews [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task ProductReviews( ProductReviewsModel model) diff --git a/src/Web/Grand.Web/Controllers/ShoppingCartController.cs b/src/Web/Grand.Web/Controllers/ShoppingCartController.cs index 3f28df28c..e1fc0fd35 100644 --- a/src/Web/Grand.Web/Controllers/ShoppingCartController.cs +++ b/src/Web/Grand.Web/Controllers/ShoppingCartController.cs @@ -301,7 +301,6 @@ public async Task> CartTotal() } - [AutoValidateAntiforgeryToken] [DenySystemAccount] [HttpPost] public virtual async Task UpdateQuantity(UpdateQuantityModel model) @@ -497,7 +496,6 @@ public virtual async Task StartCheckout(CheckoutAttributeSelected return RedirectToRoute("LoginCheckoutAsGuest", new { returnUrl = Url.RouteUrl("ShoppingCart") }); } - [AutoValidateAntiforgeryToken] [DenySystemAccount] [HttpPost] public virtual async Task ApplyDiscountCoupon(DiscountCouponModel model) @@ -541,7 +539,6 @@ await _customerService.UpdateUserField(_contextAccessor.WorkContext.CurrentCusto }); } - [AutoValidateAntiforgeryToken] [DenySystemAccount] [HttpPost] public virtual async Task ApplyGiftVoucher(GiftVoucherCouponModel model) @@ -586,7 +583,6 @@ await _customerService.UpdateUserField(_contextAccessor.WorkContext.CurrentCusto }); } - [AutoValidateAntiforgeryToken] [HttpPost] public virtual async Task GetEstimateShipping(EstimateShippingModel model) { diff --git a/src/Web/Grand.Web/Controllers/VendorController.cs b/src/Web/Grand.Web/Controllers/VendorController.cs index 4b7efcdaf..7f2c04cf2 100644 --- a/src/Web/Grand.Web/Controllers/VendorController.cs +++ b/src/Web/Grand.Web/Controllers/VendorController.cs @@ -128,7 +128,6 @@ public virtual async Task ApplyVendor() [HttpPost] [ActionName("ApplyVendor")] - [AutoValidateAntiforgeryToken] [DenySystemAccount] [CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)] public virtual async Task ApplyVendorSubmit(ApplyVendorModel model, [FromServices] ISeNameService seNameService) @@ -195,7 +194,6 @@ await _messageProviderService.SendNewVendorAccountApplyStoreOwnerMessage(_contex } [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task ContactVendor(ContactVendorModel model) { diff --git a/src/Web/Grand.Web/Controllers/WishlistController.cs b/src/Web/Grand.Web/Controllers/WishlistController.cs index 050c6bf34..9965c0485 100644 --- a/src/Web/Grand.Web/Controllers/WishlistController.cs +++ b/src/Web/Grand.Web/Controllers/WishlistController.cs @@ -111,7 +111,6 @@ public virtual async Task> Index(Guid? customerGuid) return View(model); } - [AutoValidateAntiforgeryToken] [DenySystemAccount] [HttpPost] public virtual async Task UpdateQuantity(UpdateQuantityModel model) @@ -208,7 +207,6 @@ public virtual async Task DeleteItemFromWishlist(string shoppingC } [HttpPost] - [AutoValidateAntiforgeryToken] [DenySystemAccount] public virtual async Task EmailWishlist(WishlistEmailAFriendModel model, [FromServices] IMessageProviderService messageProviderService, diff --git a/src/Web/Grand.Web/Views/Shared/_Layout.cshtml b/src/Web/Grand.Web/Views/Shared/_Layout.cshtml index 104332ff4..51951c577 100644 --- a/src/Web/Grand.Web/Views/Shared/_Layout.cshtml +++ b/src/Web/Grand.Web/Views/Shared/_Layout.cshtml @@ -19,6 +19,7 @@ @await RenderSectionAsync("head", false) +@Html.AntiForgeryToken() diff --git a/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml b/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml index 8fc177288..9400d4a11 100644 --- a/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml +++ b/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml @@ -15,6 +15,7 @@ +@Html.AntiForgeryToken() @RenderBody() diff --git a/src/Web/Grand.Web/wwwroot/theme/script/public.common.js b/src/Web/Grand.Web/wwwroot/theme/script/public.common.js index 49776e565..7c881fd3e 100644 --- a/src/Web/Grand.Web/wwwroot/theme/script/public.common.js +++ b/src/Web/Grand.Web/wwwroot/theme/script/public.common.js @@ -12,6 +12,28 @@ function addAntiForgeryToken(data) { return data; }; +//attach the CSRF token as a header to every AJAX request (axios and jQuery), +//so requests are covered regardless of body type (json/form/FormData) +(function () { + const tokenInput = document.querySelector('input[name=__RequestVerificationToken]'); + if (!tokenInput) { + return; + } + const token = tokenInput.value; + + if (typeof axios !== 'undefined') { + axios.defaults.headers.common['X-CSRF-TOKEN'] = token; + } + + if (typeof $ !== 'undefined' && typeof $.ajaxSetup === 'function') { + $.ajaxSetup({ + beforeSend: function (xhr) { + xhr.setRequestHeader('X-CSRF-TOKEN', token); + } + }); + } +})(); + // runs an array of async functions in sequential order function seq(arr, callback, index) { // first call, without an index