From da734895847ed789354250ca53387250745328e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Sezima?= Date: Fri, 7 Jun 2024 18:16:01 +0200 Subject: [PATCH] Add option to set CORS exposed headers (#16258) Co-authored-by: Vaclav Sezima Co-authored-by: Mike Alhayek Co-authored-by: Hisham Bin Ateya --- .../OrchardCore.Cors/Assets/Admin/cors-admin.js | 3 ++- .../OrchardCore.Cors/Controllers/AdminController.cs | 6 ++++-- .../Services/CorsOptionsConfiguration.cs | 5 +++++ .../OrchardCore.Cors/Settings/CorsPolicySetting.cs | 2 ++ .../ViewModels/CorsPolicyViewModel.cs | 2 ++ .../OrchardCore.Cors/Views/Admin/Index.cshtml | 12 ++++++++++++ .../OrchardCore.Cors/wwwroot/Scripts/cors-admin.js | 3 ++- .../wwwroot/Scripts/cors-admin.min.js | 2 +- 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/Assets/Admin/cors-admin.js b/src/OrchardCore.Modules/OrchardCore.Cors/Assets/Admin/cors-admin.js index 81621d50124..5801be7031e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/Assets/Admin/cors-admin.js +++ b/src/OrchardCore.Modules/OrchardCore.Cors/Assets/Admin/cors-admin.js @@ -51,7 +51,8 @@ var corsApp = new Vue({ allowedHeaders: [], allowAnyHeader: true, allowCredentials: true, - isDefaultPolicy: false + isDefaultPolicy: false, + exposedHeaders: [] }; }, editPolicy: function (policy) { diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Cors/Controllers/AdminController.cs index 629ee0e7d6d..e64c41eea4a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/Controllers/AdminController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Cors/Controllers/AdminController.cs @@ -68,7 +68,8 @@ public async Task Index() AllowAnyOrigin = policySetting.AllowAnyOrigin, AllowedOrigins = policySetting.AllowedOrigins, AllowCredentials = policySetting.AllowCredentials, - IsDefaultPolicy = policySetting.IsDefaultPolicy + IsDefaultPolicy = policySetting.IsDefaultPolicy, + ExposedHeaders = policySetting.ExposedHeaders, }; list.Add(policyViewModel); @@ -113,7 +114,8 @@ public async Task IndexPOST() AllowedHeaders = settingViewModel.AllowedHeaders, AllowedMethods = settingViewModel.AllowedMethods, AllowedOrigins = settingViewModel.AllowedOrigins, - IsDefaultPolicy = settingViewModel.IsDefaultPolicy + IsDefaultPolicy = settingViewModel.IsDefaultPolicy, + ExposedHeaders = settingViewModel.ExposedHeaders, }); if (settingViewModel.AllowAnyOrigin && settingViewModel.AllowCredentials) diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/Services/CorsOptionsConfiguration.cs b/src/OrchardCore.Modules/OrchardCore.Cors/Services/CorsOptionsConfiguration.cs index 08a8d08685e..47700a3dd81 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/Services/CorsOptionsConfiguration.cs +++ b/src/OrchardCore.Modules/OrchardCore.Cors/Services/CorsOptionsConfiguration.cs @@ -69,6 +69,11 @@ public void Configure(CorsOptions options) { configurePolicy.DisallowCredentials(); } + + if (corsPolicy.ExposedHeaders?.Length > 0) + { + configurePolicy.WithExposedHeaders(corsPolicy.ExposedHeaders); + } }); if (corsPolicy.IsDefaultPolicy) diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/Settings/CorsPolicySetting.cs b/src/OrchardCore.Modules/OrchardCore.Cors/Settings/CorsPolicySetting.cs index b26c07e0486..270e2405d4e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/Settings/CorsPolicySetting.cs +++ b/src/OrchardCore.Modules/OrchardCore.Cors/Settings/CorsPolicySetting.cs @@ -19,5 +19,7 @@ public class CorsPolicySetting public bool AllowCredentials { get; set; } public bool IsDefaultPolicy { get; set; } + + public string[] ExposedHeaders { get; set; } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/ViewModels/CorsPolicyViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Cors/ViewModels/CorsPolicyViewModel.cs index fcff2331da8..e9022f6ae4f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/ViewModels/CorsPolicyViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Cors/ViewModels/CorsPolicyViewModel.cs @@ -19,5 +19,7 @@ public class CorsPolicyViewModel public bool AllowCredentials { get; set; } public bool IsDefaultPolicy { get; set; } + + public string[] ExposedHeaders { get; set; } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/Views/Admin/Index.cshtml b/src/OrchardCore.Modules/OrchardCore.Cors/Views/Admin/Index.cshtml index 15b9fc0f122..1d0b46e21b0 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/Views/Admin/Index.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Cors/Views/Admin/Index.cshtml @@ -138,6 +138,18 @@ +
+
+
@T["Exposed headers"] + @T["Configure which headers should be exposed."] +
+ +
+ @T["Sets response header 'Access-Control-Expose-Headers'."] + +
+
+
diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.js b/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.js index a149ed0b229..a7093e42d87 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.js +++ b/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.js @@ -59,7 +59,8 @@ var corsApp = new Vue({ allowedHeaders: [], allowAnyHeader: true, allowCredentials: true, - isDefaultPolicy: false + isDefaultPolicy: false, + exposedHeaders: [] }; }, editPolicy: function editPolicy(policy) { diff --git a/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.min.js b/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.min.js index 2fc2cd87dd1..941ec23e41d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.min.js +++ b/src/OrchardCore.Modules/OrchardCore.Cors/wwwroot/Scripts/cors-admin.min.js @@ -1 +1 @@ -var optionsList=Vue.component("options-list",{props:["options","optionType","title","subTitle"],template:"#options-list",data:function(){return{newOption:""}},methods:{addOption:function(i){null!==i&&""!==i&&($.inArray(i.toLowerCase(),this.options.map((function(i){return i.toLowerCase()})))<0&&this.options.push(i))},deleteOption:function(i){this.options.splice($.inArray(i,this.options),1)}}}),policyDetails=Vue.component("policy-details",{components:{optionsList:optionsList},props:["policy"],template:"#policy-details"}),corsApp=new Vue({el:"#corsAdmin",components:{policyDetails:policyDetails,optionsList:optionsList},data:{selectedPolicy:null,policies:null,defaultPolicyName:null},updated:function(){this.searchBox()},methods:{newPolicy:function(){this.selectedPolicy={name:"New policy",allowedOrigins:[],allowAnyOrigin:!0,allowedMethods:[],allowAnyMethod:!0,allowedHeaders:[],allowAnyHeader:!0,allowCredentials:!0,isDefaultPolicy:!1}},editPolicy:function(i){this.selectedPolicy=Object.assign({},i),this.selectedPolicy.originalName=this.selectedPolicy.name},deletePolicy:function(i,e){this.selectedPolicy=null;var t=this.policies.filter((function(e){return e.name===i.name}));t.length>0&&this.policies.splice($.inArray(t[0],this.policies),1),e.stopPropagation(),this.save()},updatePolicy:function(i,e){if(i.isDefaultPolicy&&this.policies.forEach((function(i){return i.isDefaultPolicy=!1})),i.originalName){var t=this.policies.findIndex((function(e){return e.name===i.originalName}));this.policies[t]=i}else this.policies.push(i);this.save(),this.back()},save:function(){document.getElementById("corsSettings").value=JSON.stringify(this.policies),document.getElementById("corsForm").submit()},back:function(){this.selectedPolicy=null},searchBox:function(){var i=$("#search-box");i.keypress((function(i){if(13==i.which){var e=$("#corsAdmin > ul > li:visible");return 1==e.length&&(window.location=e.find(".edit").attr("href")),!1}})),i.keyup((function(e){var t=$(this).val().toLowerCase(),o=$("[data-filter-value]");if(27==e.keyCode||""==t)i.val(""),o.toggle(!0),$("#list-alert").addClass("d-none");else{var s=0;o.each((function(){var i=$(this).data("filter-value").toLowerCase().indexOf(t)>-1;$(this).toggle(i),i&&s++})),0==s?$("#list-alert").removeClass("d-none"):$("#list-alert").addClass("d-none")}}))}}}); +var optionsList=Vue.component("options-list",{props:["options","optionType","title","subTitle"],template:"#options-list",data:function(){return{newOption:""}},methods:{addOption:function(i){null!==i&&""!==i&&($.inArray(i.toLowerCase(),this.options.map((function(i){return i.toLowerCase()})))<0&&this.options.push(i))},deleteOption:function(i){this.options.splice($.inArray(i,this.options),1)}}}),policyDetails=Vue.component("policy-details",{components:{optionsList:optionsList},props:["policy"],template:"#policy-details"}),corsApp=new Vue({el:"#corsAdmin",components:{policyDetails:policyDetails,optionsList:optionsList},data:{selectedPolicy:null,policies:null,defaultPolicyName:null},updated:function(){this.searchBox()},methods:{newPolicy:function(){this.selectedPolicy={name:"New policy",allowedOrigins:[],allowAnyOrigin:!0,allowedMethods:[],allowAnyMethod:!0,allowedHeaders:[],allowAnyHeader:!0,allowCredentials:!0,isDefaultPolicy:!1,exposedHeaders:[]}},editPolicy:function(i){this.selectedPolicy=Object.assign({},i),this.selectedPolicy.originalName=this.selectedPolicy.name},deletePolicy:function(i,e){this.selectedPolicy=null;var t=this.policies.filter((function(e){return e.name===i.name}));t.length>0&&this.policies.splice($.inArray(t[0],this.policies),1),e.stopPropagation(),this.save()},updatePolicy:function(i,e){if(i.isDefaultPolicy&&this.policies.forEach((function(i){return i.isDefaultPolicy=!1})),i.originalName){var t=this.policies.findIndex((function(e){return e.name===i.originalName}));this.policies[t]=i}else this.policies.push(i);this.save(),this.back()},save:function(){document.getElementById("corsSettings").value=JSON.stringify(this.policies),document.getElementById("corsForm").submit()},back:function(){this.selectedPolicy=null},searchBox:function(){var i=$("#search-box");i.keypress((function(i){if(13==i.which){var e=$("#corsAdmin > ul > li:visible");return 1==e.length&&(window.location=e.find(".edit").attr("href")),!1}})),i.keyup((function(e){var t=$(this).val().toLowerCase(),o=$("[data-filter-value]");if(27==e.keyCode||""==t)i.val(""),o.toggle(!0),$("#list-alert").addClass("d-none");else{var s=0;o.each((function(){var i=$(this).data("filter-value").toLowerCase().indexOf(t)>-1;$(this).toggle(i),i&&s++})),0==s?$("#list-alert").removeClass("d-none"):$("#list-alert").addClass("d-none")}}))}}});