Serenity 6.1.8 Release Notes (2022-09-29)
We'll publish these release notes for versions that deserve more explanation than short descriptions available in our change log.
Added SourceMapSecurity Middleware (StartSharp)
Even though source maps are very useful in development, they can be a security concern in production. We added a middleware to block access to your .js.map
and .css.map
files in non development environments, so that prying eyes can't look at your TypeScript source code. It is enabled in Startup via:
if (!env.IsDevelopment())
{
app.UseSourceMapSecurity(new()
{
SkipPermission = Configuration["SourceMapSkipPermission"]
});
}
This blocks access to map files in environments except development.
There is also an option to specify a permission in appsettings.json
-> SourceMapSkipPermission
so that a user with that permission can still access .map.js
files even in production (use with care!).
The middleware for this feature resides in Serenity.Pro.Extensions
package.
We strongly recommend enabling ScriptBundling / CssBundling in production sites via appsettings.json files.
You may try this middleware in action at serenity.is and our demo
Added a Workaround for getPropertyItemsData Change
In Serenity 6.1.0, we added an ability to send more metadata, in addition to what available in form / columns properties by changing the format of the JSON returned from Form / Columns scripts.
Before that a form / columns script was simply a JSON array of PropertyItem objects:
[
{
"name": "LanguageId",
"title": "Db.Administration.Language.LanguageId",
"editorParams": {
"maxLength": 10
},
"maxLength": 10,
"required": true,
"width": 150
},
{
"name": "LanguageName",
"title": "Db.Administration.Language.LanguageName",
"editorParams": {
"maxLength": 50
},
"maxLength": 50,
"required": true,
"width": 150
}
]
Now it is a class:
{
"items": [
{
"name": "LanguageId",
"title": "Db.Administration.Language.LanguageId",
"editorParams": {
"maxLength": 10
},
"maxLength": 10,
"required": true,
"width": 150
},
{
"name": "LanguageName",
"title": "Db.Administration.Language.LanguageName",
"editorParams": {
"maxLength": 50
},
"maxLength": 50,
"required": true,
"width": 150
}
],
"additionalItems": []
}
As you see, the items are moved into a items
property, and there is an additionalItems
property that is unused in this sample. We would like to use these additionalItems
to pass some info about items that are not used in the Form
or Columns
definitions.
For example, if a columns definition has Country
property, but not its related CountryId
property, we may not know if the foreign key property CountryId
is mandatory (not null) or not, or what its editor / formatter type is.
We used these additionalItems
for a new inline grid editing sample in StartSharp (https://demo.serenity.is/AdvancedSamples/InlineEditing) that is more advanced than Product editing sample (https://demo.serenity.is/Northwind/Product). It uses SleekGrid's (our SlickGrid rewrite) cell navigation / editing functionality, while the legacy sample uses, well a legacy method.
The code written for new inline editing sample is just 36 lines of code (actually just 5 lines for editing), compared to 297 lines required in the legacy sample ;)
This is made possible by this additionalItems
property, passing some server side information about editing in columns script.
We added Q.getFormData()
, Q.getColumnsData()
(and their Async
versions) to support this new format. But, to keep backwards compatibility, we left Q.getForm()
, Q.getColumns
methods as is, e.g. they return an array as they did before.
These functions are also used in classes like PropertyDialog
, EntityDialog
, EntityGrid
via their getPropertyItems()
methods to receive information about Columns
and Form
items. Again, to keep compatibility as much as possible, we left them as is, but there is now getPropertyItemsData
methods in those classes, that should be overridden instead of getPropertyItems
where possible.
The getPropertyItems
methods in those classes are now just a return this.propertyItemsData.items
line and the actual loading is done in getPropertyItemsData
methods:
protected getPropertyItems() {
return this.propertyItemsData?.items || [];
}
protected getPropertyItemsData(): PropertyItemsData {
var formKey = this.getFormKey();
if (!Q.isEmptyOrNull(formKey)) {
return Q.getFormData(formKey);
}
return { items: [], additionalItems: [] };
}
The code above is an excerpt from EntityDialog.ts
. This is not a breaking change for ordinary subclasses, as long as both the Serenity.Web
and Serenity.Scripts
are 6.1.0+. Otherwise, as the JSON sent by the server is different than what the script code expects, it might break your forms / grids.
Anyway, this still caused a breaking change in rare case where a dialog's getFormKey
is not overriden (e.g. the dialog does not have a corresponding form class), but the dialog returns it's hardcoded form items by overriding its getPropertyItems
method:
class SomeDialog {
// note, there is no getFormKey() method here
getPropertyItems() {
return [
{
name: 'Some',
//...
}
]
}
}
So this code does not call super.getPropertyItems()
. The original getPropertyItems
used to call getFormKey
followed by Q.getFormData
, which tried to load that form script from the server.
But, when this user updated to 6.1.0+, the dialog broke because even though he didn't call super.getPropertyItems()
, getPropertyItemsData()
method is still called from EntityDialog
itself, and tried to load the default form based on class name (Form.SomeDialog
), resulting in a can't load script data ...
error.
We are aware that not many users actually read change log / release notes so we added a workaround in 6.1.8:
protected getPropertyItems() {
return this.propertyItemsData?.items || [];
}
protected getPropertyItemsData(): PropertyItemsData {
var formKey = this.getFormKey();
if (this.getFormKey === EntityDialog.prototype.getFormKey &&
this.getPropertyItems !== EntityDialog.prototype.getPropertyItems &&
!ScriptData.canLoad('Form.' + formKey)) {
return {
items: this.getPropertyItems(),
additionalItems: []
}
}
if (!Q.isEmptyOrNull(formKey)) {
return Q.getFormData(formKey);
}
return { items: [], additionalItems: [] };
}
Above, we try to identify in getPropertyItemsData
method, if the user overriden getPropertyItems
in its subclass, while not overriding getFormKey
method (e.g. don't have a form), and the default form name calculated from the class name is not available in registered scripts. This will probably handle 99% percent of cases, but if you are reading this, please override getPropertyItemsData
instead to be sure.