diff --git a/samples/apachemodule/Apache24/htdocs/css/milligram.css b/samples/apachemodule/Apache24/htdocs/css/milligram.css
new file mode 100644
index 000000000..d253355e5
--- /dev/null
+++ b/samples/apachemodule/Apache24/htdocs/css/milligram.css
@@ -0,0 +1,602 @@
+/*!
+ * Milligram v1.3.0
+ * https://milligram.github.io
+ *
+ * Copyright (c) 2017 CJ Patoilo
+ * Licensed under the MIT license
+ */
+
+*,
+*:after,
+*:before {
+ box-sizing: inherit;
+}
+
+html {
+ box-sizing: border-box;
+ font-size: 62.5%;
+}
+
+body {
+ color: #606c76;
+ font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
+ font-size: 1.6em;
+ font-weight: 300;
+ letter-spacing: .01em;
+ line-height: 1.6;
+}
+
+blockquote {
+ border-left: 0.3rem solid #d1d1d1;
+ margin-left: 0;
+ margin-right: 0;
+ padding: 1rem 1.5rem;
+}
+
+blockquote *:last-child {
+ margin-bottom: 0;
+}
+
+.button,
+button,
+input[type='button'],
+input[type='reset'],
+input[type='submit'] {
+ background-color: #9b4dca;
+ border: 0.1rem solid #9b4dca;
+ border-radius: .4rem;
+ color: #fff;
+ cursor: pointer;
+ display: inline-block;
+ font-size: 1.1rem;
+ font-weight: 700;
+ height: 3.8rem;
+ letter-spacing: .1rem;
+ line-height: 3.8rem;
+ padding: 0 3.0rem;
+ text-align: center;
+ text-decoration: none;
+ text-transform: uppercase;
+ white-space: nowrap;
+}
+
+.button:focus, .button:hover,
+button:focus,
+button:hover,
+input[type='button']:focus,
+input[type='button']:hover,
+input[type='reset']:focus,
+input[type='reset']:hover,
+input[type='submit']:focus,
+input[type='submit']:hover {
+ background-color: #606c76;
+ border-color: #606c76;
+ color: #fff;
+ outline: 0;
+}
+
+.button[disabled],
+button[disabled],
+input[type='button'][disabled],
+input[type='reset'][disabled],
+input[type='submit'][disabled] {
+ cursor: default;
+ opacity: .5;
+}
+
+.button[disabled]:focus, .button[disabled]:hover,
+button[disabled]:focus,
+button[disabled]:hover,
+input[type='button'][disabled]:focus,
+input[type='button'][disabled]:hover,
+input[type='reset'][disabled]:focus,
+input[type='reset'][disabled]:hover,
+input[type='submit'][disabled]:focus,
+input[type='submit'][disabled]:hover {
+ background-color: #9b4dca;
+ border-color: #9b4dca;
+}
+
+.button.button-outline,
+button.button-outline,
+input[type='button'].button-outline,
+input[type='reset'].button-outline,
+input[type='submit'].button-outline {
+ background-color: transparent;
+ color: #9b4dca;
+}
+
+.button.button-outline:focus, .button.button-outline:hover,
+button.button-outline:focus,
+button.button-outline:hover,
+input[type='button'].button-outline:focus,
+input[type='button'].button-outline:hover,
+input[type='reset'].button-outline:focus,
+input[type='reset'].button-outline:hover,
+input[type='submit'].button-outline:focus,
+input[type='submit'].button-outline:hover {
+ background-color: transparent;
+ border-color: #606c76;
+ color: #606c76;
+}
+
+.button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover,
+button.button-outline[disabled]:focus,
+button.button-outline[disabled]:hover,
+input[type='button'].button-outline[disabled]:focus,
+input[type='button'].button-outline[disabled]:hover,
+input[type='reset'].button-outline[disabled]:focus,
+input[type='reset'].button-outline[disabled]:hover,
+input[type='submit'].button-outline[disabled]:focus,
+input[type='submit'].button-outline[disabled]:hover {
+ border-color: inherit;
+ color: #9b4dca;
+}
+
+.button.button-clear,
+button.button-clear,
+input[type='button'].button-clear,
+input[type='reset'].button-clear,
+input[type='submit'].button-clear {
+ background-color: transparent;
+ border-color: transparent;
+ color: #9b4dca;
+}
+
+.button.button-clear:focus, .button.button-clear:hover,
+button.button-clear:focus,
+button.button-clear:hover,
+input[type='button'].button-clear:focus,
+input[type='button'].button-clear:hover,
+input[type='reset'].button-clear:focus,
+input[type='reset'].button-clear:hover,
+input[type='submit'].button-clear:focus,
+input[type='submit'].button-clear:hover {
+ background-color: transparent;
+ border-color: transparent;
+ color: #606c76;
+}
+
+.button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover,
+button.button-clear[disabled]:focus,
+button.button-clear[disabled]:hover,
+input[type='button'].button-clear[disabled]:focus,
+input[type='button'].button-clear[disabled]:hover,
+input[type='reset'].button-clear[disabled]:focus,
+input[type='reset'].button-clear[disabled]:hover,
+input[type='submit'].button-clear[disabled]:focus,
+input[type='submit'].button-clear[disabled]:hover {
+ color: #9b4dca;
+}
+
+code {
+ background: #f4f5f6;
+ border-radius: .4rem;
+ font-size: 86%;
+ margin: 0 .2rem;
+ padding: .2rem .5rem;
+ white-space: nowrap;
+}
+
+pre {
+ background: #f4f5f6;
+ border-left: 0.3rem solid #9b4dca;
+ overflow-y: hidden;
+}
+
+pre > code {
+ border-radius: 0;
+ display: block;
+ padding: 1rem 1.5rem;
+ white-space: pre;
+}
+
+hr {
+ border: 0;
+ border-top: 0.1rem solid #f4f5f6;
+ margin: 3.0rem 0;
+}
+
+input[type='email'],
+input[type='number'],
+input[type='password'],
+input[type='search'],
+input[type='tel'],
+input[type='text'],
+input[type='url'],
+textarea,
+select {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: transparent;
+ border: 0.1rem solid #d1d1d1;
+ border-radius: .4rem;
+ box-shadow: none;
+ box-sizing: inherit;
+ height: 3.8rem;
+ padding: .6rem 1.0rem;
+ width: 100%;
+}
+
+input[type='email']:focus,
+input[type='number']:focus,
+input[type='password']:focus,
+input[type='search']:focus,
+input[type='tel']:focus,
+input[type='text']:focus,
+input[type='url']:focus,
+textarea:focus,
+select:focus {
+ border-color: #9b4dca;
+ outline: 0;
+}
+
+select {
+ background: url('data:image/svg+xml;utf8,') center right no-repeat;
+ padding-right: 3.0rem;
+}
+
+select:focus {
+ background-image: url('data:image/svg+xml;utf8,');
+}
+
+textarea {
+ min-height: 6.5rem;
+}
+
+label,
+legend {
+ display: block;
+ font-size: 1.6rem;
+ font-weight: 700;
+ margin-bottom: .5rem;
+}
+
+fieldset {
+ border-width: 0;
+ padding: 0;
+}
+
+input[type='checkbox'],
+input[type='radio'] {
+ display: inline;
+}
+
+.label-inline {
+ display: inline-block;
+ font-weight: normal;
+ margin-left: .5rem;
+}
+
+.container {
+ margin: 0 auto;
+ max-width: 112.0rem;
+ padding: 0 2.0rem;
+ position: relative;
+ width: 100%;
+}
+
+.row {
+ display: flex;
+ flex-direction: column;
+ padding: 0;
+ width: 100%;
+}
+
+.row.row-no-padding {
+ padding: 0;
+}
+
+.row.row-no-padding > .column {
+ padding: 0;
+}
+
+.row.row-wrap {
+ flex-wrap: wrap;
+}
+
+.row.row-top {
+ align-items: flex-start;
+}
+
+.row.row-bottom {
+ align-items: flex-end;
+}
+
+.row.row-center {
+ align-items: center;
+}
+
+.row.row-stretch {
+ align-items: stretch;
+}
+
+.row.row-baseline {
+ align-items: baseline;
+}
+
+.row .column {
+ display: block;
+ flex: 1 1 auto;
+ margin-left: 0;
+ max-width: 100%;
+ width: 100%;
+}
+
+.row .column.column-offset-10 {
+ margin-left: 10%;
+}
+
+.row .column.column-offset-20 {
+ margin-left: 20%;
+}
+
+.row .column.column-offset-25 {
+ margin-left: 25%;
+}
+
+.row .column.column-offset-33, .row .column.column-offset-34 {
+ margin-left: 33.3333%;
+}
+
+.row .column.column-offset-50 {
+ margin-left: 50%;
+}
+
+.row .column.column-offset-66, .row .column.column-offset-67 {
+ margin-left: 66.6666%;
+}
+
+.row .column.column-offset-75 {
+ margin-left: 75%;
+}
+
+.row .column.column-offset-80 {
+ margin-left: 80%;
+}
+
+.row .column.column-offset-90 {
+ margin-left: 90%;
+}
+
+.row .column.column-10 {
+ flex: 0 0 10%;
+ max-width: 10%;
+}
+
+.row .column.column-20 {
+ flex: 0 0 20%;
+ max-width: 20%;
+}
+
+.row .column.column-25 {
+ flex: 0 0 25%;
+ max-width: 25%;
+}
+
+.row .column.column-33, .row .column.column-34 {
+ flex: 0 0 33.3333%;
+ max-width: 33.3333%;
+}
+
+.row .column.column-40 {
+ flex: 0 0 40%;
+ max-width: 40%;
+}
+
+.row .column.column-50 {
+ flex: 0 0 50%;
+ max-width: 50%;
+}
+
+.row .column.column-60 {
+ flex: 0 0 60%;
+ max-width: 60%;
+}
+
+.row .column.column-66, .row .column.column-67 {
+ flex: 0 0 66.6666%;
+ max-width: 66.6666%;
+}
+
+.row .column.column-75 {
+ flex: 0 0 75%;
+ max-width: 75%;
+}
+
+.row .column.column-80 {
+ flex: 0 0 80%;
+ max-width: 80%;
+}
+
+.row .column.column-90 {
+ flex: 0 0 90%;
+ max-width: 90%;
+}
+
+.row .column .column-top {
+ align-self: flex-start;
+}
+
+.row .column .column-bottom {
+ align-self: flex-end;
+}
+
+.row .column .column-center {
+ -ms-grid-row-align: center;
+ align-self: center;
+}
+
+@media (min-width: 40rem) {
+ .row {
+ flex-direction: row;
+ margin-left: -1.0rem;
+ width: calc(100% + 2.0rem);
+ }
+ .row .column {
+ margin-bottom: inherit;
+ padding: 0 1.0rem;
+ }
+}
+
+a {
+ color: #9b4dca;
+ text-decoration: none;
+}
+
+a:focus, a:hover {
+ color: #606c76;
+}
+
+dl,
+ol,
+ul {
+ list-style: none;
+ margin-top: 0;
+ padding-left: 0;
+}
+
+dl dl,
+dl ol,
+dl ul,
+ol dl,
+ol ol,
+ol ul,
+ul dl,
+ul ol,
+ul ul {
+ font-size: 90%;
+ margin: 1.5rem 0 1.5rem 3.0rem;
+}
+
+ol {
+ list-style: decimal inside;
+}
+
+ul {
+ list-style: circle inside;
+}
+
+.button,
+button,
+dd,
+dt,
+li {
+ margin-bottom: 1.0rem;
+}
+
+fieldset,
+input,
+select,
+textarea {
+ margin-bottom: 1.5rem;
+}
+
+blockquote,
+dl,
+figure,
+form,
+ol,
+p,
+pre,
+table,
+ul {
+ margin-bottom: 2.5rem;
+}
+
+table {
+ border-spacing: 0;
+ width: 100%;
+}
+
+td,
+th {
+ border-bottom: 0.1rem solid #e1e1e1;
+ padding: 1.2rem 1.5rem;
+ text-align: left;
+}
+
+td:first-child,
+th:first-child {
+ padding-left: 0;
+}
+
+td:last-child,
+th:last-child {
+ padding-right: 0;
+}
+
+b,
+strong {
+ font-weight: bold;
+}
+
+p {
+ margin-top: 0;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-weight: 300;
+ letter-spacing: -.1rem;
+ margin-bottom: 2.0rem;
+ margin-top: 0;
+}
+
+h1 {
+ font-size: 4.6rem;
+ line-height: 1.2;
+}
+
+h2 {
+ font-size: 3.6rem;
+ line-height: 1.25;
+}
+
+h3 {
+ font-size: 2.8rem;
+ line-height: 1.3;
+}
+
+h4 {
+ font-size: 2.2rem;
+ letter-spacing: -.08rem;
+ line-height: 1.35;
+}
+
+h5 {
+ font-size: 1.8rem;
+ letter-spacing: -.05rem;
+ line-height: 1.5;
+}
+
+h6 {
+ font-size: 1.6rem;
+ letter-spacing: 0;
+ line-height: 1.4;
+}
+
+img {
+ max-width: 100%;
+}
+
+.clearfix:after {
+ clear: both;
+ content: ' ';
+ display: table;
+}
+
+.float-left {
+ float: left;
+}
+
+.float-right {
+ float: right;
+}
+
+/*# sourceMappingURL=milligram.css.map */
\ No newline at end of file
diff --git a/samples/apachemodule/Apache24/htdocs/css/styles.css b/samples/apachemodule/Apache24/htdocs/css/styles.css
index 6971a0c2b..4c56f8b3d 100644
--- a/samples/apachemodule/Apache24/htdocs/css/styles.css
+++ b/samples/apachemodule/Apache24/htdocs/css/styles.css
@@ -1,12 +1,13 @@
-* {
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 18px;
-}
.header {
padding-top: 5px;
}
+#wineList {
+ overflow-y: scroll;
+ height: 80%;
+}
+
.leftArea {
position: absolute;
left: 10px;
diff --git a/samples/apachemodule/Apache24/htdocs/index.html b/samples/apachemodule/Apache24/htdocs/index.html
index 7675d93b0..2d908d266 100644
--- a/samples/apachemodule/Apache24/htdocs/index.html
+++ b/samples/apachemodule/Apache24/htdocs/index.html
@@ -1,63 +1,70 @@
+
-Cellar
-
+ Cellar
+
+
-
+
-
+
-
+
-
-
+
+
-
+
+
\ No newline at end of file
diff --git a/samples/apachemodule/WineCellarAppControllerU.pas b/samples/apachemodule/WineCellarAppControllerU.pas
index 9e0bf7eaa..9fcb4e866 100644
--- a/samples/apachemodule/WineCellarAppControllerU.pas
+++ b/samples/apachemodule/WineCellarAppControllerU.pas
@@ -55,10 +55,11 @@ implementation
uses
System.SysUtils, System.Classes, System.IOUtils,
- WinesBO, MVCFramework.Serializer.Commons;
+ WinesBO, MVCFramework.Serializer.Commons, MVCFramework.Logger;
procedure TWineCellarApp.FindWines(ctx: TWebContext);
begin
+ Log.Debug('','MYTAG');
Render(dm.FindWines(ctx.Request.Params['value']));
end;
diff --git a/samples/apachemodule/mod_dmvc.dproj b/samples/apachemodule/mod_dmvc.dproj
index fa9d9c7ae..f4d8ab3ed 100644
--- a/samples/apachemodule/mod_dmvc.dproj
+++ b/samples/apachemodule/mod_dmvc.dproj
@@ -1,7 +1,7 @@
{61ADE231-72F2-4E11-8EDD-62C5AFEF0463}
- 18.3
+ 18.4
VCL
mod_dmvc.dpr
True
diff --git a/samples/articles_crud_server/MainDM.pas b/samples/articles_crud_server/MainDM.pas
index 8c371fe13..20b0fc648 100644
--- a/samples/articles_crud_server/MainDM.pas
+++ b/samples/articles_crud_server/MainDM.pas
@@ -3,11 +3,27 @@
interface
uses
- System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option,
- FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
- FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.FB, Data.DB,
- FireDAC.Comp.Client, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf,
- FireDAC.DApt, FireDAC.Comp.DataSet, FireDAC.Phys.FBDef, FireDAC.VCLUI.Wait;
+ System.SysUtils,
+ System.Classes,
+ FireDAC.Stan.Intf,
+ FireDAC.Stan.Option,
+ FireDAC.Stan.Error,
+ FireDAC.UI.Intf,
+ FireDAC.Phys.Intf,
+ FireDAC.Stan.Def,
+ FireDAC.Stan.Pool,
+ FireDAC.Stan.Async,
+ FireDAC.Phys,
+ FireDAC.Phys.FB,
+ Data.DB,
+ FireDAC.Comp.Client,
+ FireDAC.Stan.Param,
+ FireDAC.DatS,
+ FireDAC.DApt.Intf,
+ FireDAC.DApt,
+ FireDAC.Comp.DataSet,
+ FireDAC.Phys.FBDef,
+ FireDAC.VCLUI.Wait;
type
TdmMain = class(TDataModule)
@@ -28,10 +44,13 @@ implementation
procedure TdmMain.ConnectionBeforeConnect(Sender: TObject);
begin
- // currently, this demo uses firebird 2.5
+{$IFNDEF WINDOWSSERVICE}
// if you want to use firebird 2.5, you can use the file ORDERSMANAGER_FB25.FDB
Connection.Params.Values['Database'] := '..\..\data\ORDERSMANAGER_FB30.FDB';
// Connection.Params.Values['Database'] := '..\..\data\ORDERSMANAGER_FB25.FDB';
+{$ELSE}
+ Connection.Params.Values['Database'] := 'C:\DEV\dmvcframework\samples\data\ORDERSMANAGER_FB30.FDB';
+{$ENDIF}
end;
end.
diff --git a/samples/articles_crud_server/WebModuleUnit1.dfm b/samples/articles_crud_server/WebModuleUnit1.dfm
index 417085809..b43b8558a 100644
--- a/samples/articles_crud_server/WebModuleUnit1.dfm
+++ b/samples/articles_crud_server/WebModuleUnit1.dfm
@@ -6,7 +6,6 @@ object WebModule1: TWebModule1
Default = True
Name = 'DefaultHandler'
PathInfo = '/'
- OnAction = WebModule1DefaultHandlerAction
end>
Height = 230
Width = 415
diff --git a/samples/articles_crud_server/WebModuleUnit1.pas b/samples/articles_crud_server/WebModuleUnit1.pas
index 46e2fe027..0d153074e 100644
--- a/samples/articles_crud_server/WebModuleUnit1.pas
+++ b/samples/articles_crud_server/WebModuleUnit1.pas
@@ -6,8 +6,6 @@ interface
type
TWebModule1 = class(TWebModule)
- procedure WebModule1DefaultHandlerAction(Sender: TObject;
- Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
procedure WebModuleCreate(Sender: TObject);
private
FEngine: TMVCEngine;
@@ -26,22 +24,12 @@ implementation
{$R *.dfm}
-procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
- Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
-begin
- Response.Content :=
- '' +
- 'Web Server Application' +
- 'Web Server Application' +
- '';
-end;
-
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
FEngine := TMVCEngine.Create(self);
FEngine.AddController(TArticlesController);
FEngine.AddMiddleware(TCORSMiddleware.Create);
- FEngine.AddMiddleware(TCompressionMiddleware.Create);
+ FEngine.AddMiddleware(TCompressionMiddleware.Create(256));
end;
diff --git a/samples/jsonwebtoken/vclclient/MainClientFormU.dfm b/samples/jsonwebtoken/vclclient/MainClientFormU.dfm
index 82b489d41..397421093 100644
--- a/samples/jsonwebtoken/vclclient/MainClientFormU.dfm
+++ b/samples/jsonwebtoken/vclclient/MainClientFormU.dfm
@@ -82,7 +82,6 @@ object Form5: TForm5
Caption = 'Get a protected resource'
TabOrder = 0
OnClick = btnGetClick
- ExplicitTop = 2
end
object btnLOGIN: TButton
AlignWithMargins = True
diff --git a/samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj b/samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj
index 5b1640ecc..64951b49b 100644
--- a/samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj
+++ b/samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj
@@ -1,7 +1,7 @@
{7B54055A-5749-4136-9FE2-35FDBEEA874C}
- 18.2
+ 18.4
VCL
JWTServer.dpr
True
diff --git a/samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas b/samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas
index b436f68ec..765abd793 100644
--- a/samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas
+++ b/samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas
@@ -27,7 +27,6 @@ implementation
{$R *.dfm}
-
uses
AppControllerU,
System.Generics.Collections,
@@ -45,11 +44,12 @@ procedure TWebModule1.WebModuleCreate(Sender: TObject);
JWT.Claims.Issuer := 'Delphi MVC Framework JWT Middleware Sample';
JWT.Claims.NotBefore := Now - OneMinute * 5; // valid since 5 minutes ago
JWT.Claims.IssuedAt := Now;
+ JWT.Claims.ExpirationTime := Now + OneSecond * 30;
JWT.CustomClaims['mycustomvalue'] := 'hello there';
// Here we dont use a fixed ExpirationTime but a LiveValidityWindowInSeconds
// to make the ExpirationTime dynamic, incrementing the
// ExpirationTime by LiveValidityWindowInSeconds seconds at each request
- JWT.LiveValidityWindowInSeconds := 5; // 60 * 60; // 1 hour
+ JWT.LiveValidityWindowInSeconds := 10; // 60 * 60; // 1 hour
end;
MVC := TMVCEngine.Create(Self);
@@ -57,17 +57,9 @@ procedure TWebModule1.WebModuleCreate(Sender: TObject);
MVC.Config[TMVCConfigKey.SessionTimeout] := '30';
MVC.Config[TMVCConfigKey.DefaultContentType] := 'text/html';
MVC.AddController(TApp1MainController).AddController(TAdminController)
- .AddMiddleware(TMVCJWTAuthenticationMiddleware.Create(
- TAuthenticationSample.Create,
- lClaimsSetup,
- 'mys3cr37',
- '/login',
- [
- TJWTCheckableClaim.ExpirationTime,
- TJWTCheckableClaim.NotBefore,
- TJWTCheckableClaim.IssuedAt
- ],
- 0 // just for test, Leeway seconds is zero.
+ .AddMiddleware(TMVCJWTAuthenticationMiddleware.Create(TAuthenticationSample.Create, lClaimsSetup, 'mys3cr37',
+ '/login', [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore, TJWTCheckableClaim.IssuedAt], 0
+ // just for test, Leeway seconds is zero.
));
end;
diff --git a/samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.dproj b/samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.dproj
index e82d3642b..c98e0cbe8 100644
--- a/samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.dproj
+++ b/samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.dproj
@@ -1,7 +1,7 @@
{E7317702-64D3-4A65-8734-030F3AE3DBBC}
- 18.2
+ 18.4
VCL
JWTClient.dpr
True
diff --git a/samples/middleware/MiddlewareSamples.dproj b/samples/middleware/MiddlewareSamples.dproj
index 0b8874c2d..1310da205 100644
--- a/samples/middleware/MiddlewareSamples.dproj
+++ b/samples/middleware/MiddlewareSamples.dproj
@@ -1,7 +1,7 @@
{0388D146-2B8B-427B-AEDD-EFD5F51D3139}
- 18.2
+ 18.4
VCL
MiddlewareSamples.dpr
True
diff --git a/samples/outputcachewithredis/OutputCacheWithRedis.dpr b/samples/outputcachewithredis/OutputCacheWithRedis.dpr
index 403fdc06f..b0f6af1a9 100644
--- a/samples/outputcachewithredis/OutputCacheWithRedis.dpr
+++ b/samples/outputcachewithredis/OutputCacheWithRedis.dpr
@@ -4,7 +4,6 @@ program OutputCacheWithRedis;
uses
System.SysUtils,
- Winapi.Windows,
IdHTTPWebBrokerBridge,
Web.WebReq,
Web.WebBroker,
@@ -20,9 +19,6 @@ uses
procedure RunServer(APort: Integer);
var
- LInputRecord: TInputRecord;
- LEvent: DWord;
- LHandle: THandle;
LServer: TIdHTTPWebBrokerBridge;
begin
Writeln(Format('Starting "OutputCacheWithRedis" HTTP Server or port %d', [APort]));
@@ -32,16 +28,8 @@ begin
LServer.ListenQueue := 200;
LServer.MaxConnections := 5000;
LServer.Active := True;
- Writeln('Press ESC to stop the server');
- LHandle := GetStdHandle(STD_INPUT_HANDLE);
- while True do
- begin
- Win32Check(ReadConsoleInput(LHandle, LInputRecord, 1, LEvent));
- if (LInputRecord.EventType = KEY_EVENT) and
- LInputRecord.Event.KeyEvent.bKeyDown and
- (LInputRecord.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE) then
- break;
- end;
+ Writeln('Press RETURN to stop the server');
+ ReadLn;
finally
LServer.Free;
end;
diff --git a/samples/outputcachewithredis/OutputCacheWithRedis.dproj b/samples/outputcachewithredis/OutputCacheWithRedis.dproj
index 9725bac2a..81fb0ceca 100644
--- a/samples/outputcachewithredis/OutputCacheWithRedis.dproj
+++ b/samples/outputcachewithredis/OutputCacheWithRedis.dproj
@@ -1,7 +1,7 @@
{BE3A3D14-17E0-45C1-BD21-4710DE4CBCC2}
- 18.2
+ 18.4
VCL
OutputCacheWithRedis.dpr
True
diff --git a/samples/renders/MyDataModuleU.pas b/samples/renders/MyDataModuleU.pas
index 8415d7117..f7ffb455d 100644
--- a/samples/renders/MyDataModuleU.pas
+++ b/samples/renders/MyDataModuleU.pas
@@ -64,8 +64,6 @@ TMyDataModule = class(TDataModule)
{ Public declarations }
end;
-var
- MyDataModule: TMyDataModule;
implementation
diff --git a/samples/renders/RenderSampleControllerU.pas b/samples/renders/RenderSampleControllerU.pas
index cef501362..6fa6b88fe 100644
--- a/samples/renders/RenderSampleControllerU.pas
+++ b/samples/renders/RenderSampleControllerU.pas
@@ -229,7 +229,7 @@ procedure TRenderSampleController.GetCustomers_AsDataSet(CTX: TWebContext);
lDM := TMyDataModule.Create(nil);
try
lDM.qryCustomers.Open;
- Render(lDM.qryCustomers);
+ Render(lDM.qryCustomers, False);
finally
lDM.Free;
end;
diff --git a/samples/renders/renders.dproj b/samples/renders/renders.dproj
index b0116ea5a..b269d5170 100644
--- a/samples/renders/renders.dproj
+++ b/samples/renders/renders.dproj
@@ -404,19 +404,19 @@
true
-
+
.\
true
-
-
+
+
.\
true
-
+
.\
true
@@ -428,13 +428,13 @@
true
-
-
+
+
.\
true
-
+
.\
true
diff --git a/samples/routing/RoutingSampleControllerU.pas b/samples/routing/RoutingSampleControllerU.pas
index 3c28b5516..3c76fb681 100644
--- a/samples/routing/RoutingSampleControllerU.pas
+++ b/samples/routing/RoutingSampleControllerU.pas
@@ -11,7 +11,7 @@ interface
TRoutingSampleController = class(TMVCController)
public
[MVCPath('/')]
- procedure Index(CTX: TWebContext);
+ procedure Index;
{ This action requires that the ACCEPT header is text/plain to be invocated }
[MVCHTTPMethod([httpGet])]
@@ -57,7 +57,7 @@ procedure TRoutingSampleController.CreatePerson;
lPerson := Context.Request.BodyAs;
lPerson.Validate;
// SavePerson(lPerson);
- Render(201, 'Person created');
+ Render(HTTP_STATUS.Created, 'Person created');
end;
procedure TRoutingSampleController.DeletePerson(const id: Integer);
@@ -83,7 +83,7 @@ procedure TRoutingSampleController.GetPerson(const id: Integer);
Render(P);
end;
-procedure TRoutingSampleController.Index(CTX: TWebContext);
+procedure TRoutingSampleController.Index;
begin
Render('This is the root path');
end;
diff --git a/samples/sessions/SessionSample.dproj b/samples/sessions/SessionSample.dproj
index 817a21bc5..cd3e5628c 100644
--- a/samples/sessions/SessionSample.dproj
+++ b/samples/sessions/SessionSample.dproj
@@ -1,7 +1,7 @@
{F9CBCE21-869A-478F-992C-88FCAC97BC8B}
- 18.2
+ 18.4
VCL
SessionSample.dpr
True
diff --git a/samples/winecellarserver/www/css/styles.css b/samples/winecellarserver/www/css/styles.css
index 6971a0c2b..4c56f8b3d 100644
--- a/samples/winecellarserver/www/css/styles.css
+++ b/samples/winecellarserver/www/css/styles.css
@@ -1,12 +1,13 @@
-* {
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 18px;
-}
.header {
padding-top: 5px;
}
+#wineList {
+ overflow-y: scroll;
+ height: 80%;
+}
+
.leftArea {
position: absolute;
left: 10px;
diff --git a/samples/winecellarserver/www/index.html b/samples/winecellarserver/www/index.html
index 7675d93b0..2d908d266 100644
--- a/samples/winecellarserver/www/index.html
+++ b/samples/winecellarserver/www/index.html
@@ -1,63 +1,70 @@
+
-Cellar
-
+ Cellar
+
+
-
+
-
+
-
+
-
-
+
+
-
+
+
\ No newline at end of file
diff --git a/sources/MVCFramework.JWT.pas b/sources/MVCFramework.JWT.pas
index 09adfd413..62e0d029f 100644
--- a/sources/MVCFramework.JWT.pas
+++ b/sources/MVCFramework.JWT.pas
@@ -208,8 +208,9 @@ TJWT = class
property LeewaySeconds: Cardinal read FLeewaySeconds;
property RegClaimsToChecks: TJWTCheckableClaims read FRegClaimsToChecks write SetChecks;
///
- /// Use LiveValidityWindowInSeconds to make the ExpirationTime dynamic at each request,
- /// incrementing the ExpirationTime by LiveValidityWindowInSeconds seconds at each request
+ /// Use LiveValidityWindowInSeconds to make the ExpirationTime dynamic at each request.
+ /// ExpirationTime will be incremented by LiveValidityWindowInSeconds seconds automatically
+ /// if the remaining seconds are less than the LiveValidityWindowInSeconds.
///
property LiveValidityWindowInSeconds: Cardinal read GetLiveValidityWindowInSeconds write SetLiveValidityWindowInSeconds;
end;
diff --git a/sources/MVCFramework.Middleware.JWT.pas b/sources/MVCFramework.Middleware.JWT.pas
index f9786ccc1..322d18257 100644
--- a/sources/MVCFramework.Middleware.JWT.pas
+++ b/sources/MVCFramework.Middleware.JWT.pas
@@ -50,67 +50,40 @@ TMVCJWTAuthenticationMiddleware = class(TInterfacedObject, IMVCMiddleware)
FLeewaySeconds: Cardinal;
FLoginURLSegment: string;
protected
- procedure InternalRender(
- AJSONValue: TJSONValue;
- AContentType: string;
- AContentEncoding: string;
- AContext: TWebContext;
- AInstanceOwner: Boolean = True
- );
-
- procedure RenderError(
- const AErrorCode: UInt16;
- const AErrorMessage: string;
- const AContext: TWebContext;
- const AErrorClassName: string = ''
- );
-
- procedure OnBeforeRouting(
- AContext: TWebContext;
- var AHandled: Boolean
- );
-
- procedure OnBeforeControllerAction(
- AContext: TWebContext;
- const AControllerQualifiedClassName: string;
- const AActionName: string;
- var AHandled: Boolean
- );
-
- procedure OnAfterControllerAction(
- AContext: TWebContext;
- const AActionName: string;
- const AHandled: Boolean
- );
+ function NeedsToBeExtended(const JWTValue: TJWT): Boolean;
+ procedure ExtendExpirationTime(const JWTValue: TJWT);
+ procedure InternalRender(AJSONValue: TJSONValue; AContentType: string; AContentEncoding: string;
+ AContext: TWebContext; AInstanceOwner: Boolean = True);
+
+ procedure RenderError(const AErrorCode: UInt16; const AErrorMessage: string; const AContext: TWebContext;
+ const AErrorClassName: string = '');
+
+ procedure OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
+
+ procedure OnBeforeControllerAction(AContext: TWebContext; const AControllerQualifiedClassName: string;
+ const AActionName: string; var AHandled: Boolean);
+
+ procedure OnAfterControllerAction(AContext: TWebContext; const AActionName: string; const AHandled: Boolean);
public
- constructor Create(AAuthenticationHandler: IMVCAuthenticationHandler;
- AConfigClaims: TJWTClaimsSetup;
- ASecret: string = 'D3lph1MVCFram3w0rk';
- ALoginURLSegment: string = '/login';
- AClaimsToCheck: TJWTCheckableClaims = [
- TJWTCheckableClaim.ExpirationTime,
- TJWTCheckableClaim.NotBefore,
- TJWTCheckableClaim.IssuedAt
- ];
- ALeewaySeconds: Cardinal = 300); virtual;
+ constructor Create(AAuthenticationHandler: IMVCAuthenticationHandler; AConfigClaims: TJWTClaimsSetup;
+ ASecret: string = 'D3lph1MVCFram3w0rk'; ALoginURLSegment: string = '/login';
+ AClaimsToCheck: TJWTCheckableClaims = [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore,
+ TJWTCheckableClaim.IssuedAt]; ALeewaySeconds: Cardinal = 300); virtual;
end;
implementation
-uses System.NetEncoding, System.DateUtils;
+uses
+ System.NetEncoding,
+ System.DateUtils,
+ System.Math;
{ TMVCJWTAuthenticationMiddleware }
constructor TMVCJWTAuthenticationMiddleware.Create(AAuthenticationHandler: IMVCAuthenticationHandler;
- AConfigClaims: TJWTClaimsSetup;
- ASecret: string = 'D3lph1MVCFram3w0rk';
- ALoginURLSegment: string = '/login';
- AClaimsToCheck: TJWTCheckableClaims = [
- TJWTCheckableClaim.ExpirationTime,
- TJWTCheckableClaim.NotBefore,
- TJWTCheckableClaim.IssuedAt
- ];
- ALeewaySeconds: Cardinal = 300);
+ AConfigClaims: TJWTClaimsSetup; ASecret: string = 'D3lph1MVCFram3w0rk'; ALoginURLSegment: string = '/login';
+ AClaimsToCheck: TJWTCheckableClaims = [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore,
+ TJWTCheckableClaim.IssuedAt]; ALeewaySeconds: Cardinal = 300);
begin
inherited Create;
FAuthenticationHandler := AAuthenticationHandler;
@@ -121,8 +94,13 @@ constructor TMVCJWTAuthenticationMiddleware.Create(AAuthenticationHandler: IMVCA
FLeewaySeconds := ALeewaySeconds;
end;
-procedure TMVCJWTAuthenticationMiddleware.InternalRender(
- AJSONValue: TJSONValue; AContentType, AContentEncoding: string;
+procedure TMVCJWTAuthenticationMiddleware.ExtendExpirationTime(const JWTValue: TJWT);
+begin
+ JWTValue.Claims.ExpirationTime := Max(JWTValue.Claims.ExpirationTime, Now) +
+ (JWTValue.LeewaySeconds + JWTValue.LiveValidityWindowInSeconds) * OneSecond;
+end;
+
+procedure TMVCJWTAuthenticationMiddleware.InternalRender(AJSONValue: TJSONValue; AContentType, AContentEncoding: string;
AContext: TWebContext; AInstanceOwner: Boolean);
var
Encoding: TEncoding;
@@ -135,9 +113,8 @@ procedure TMVCJWTAuthenticationMiddleware.InternalRender(
Encoding := TEncoding.GetEncoding(AContentEncoding);
try
- AContext.Response.SetContentStream(
- TBytesStream.Create(TEncoding.Convert(TEncoding.Default, Encoding, TEncoding.Default.GetBytes(JValue))),
- ContentType);
+ AContext.Response.SetContentStream(TBytesStream.Create(TEncoding.Convert(TEncoding.Default, Encoding,
+ TEncoding.Default.GetBytes(JValue))), ContentType);
finally
Encoding.Free;
end;
@@ -146,16 +123,28 @@ procedure TMVCJWTAuthenticationMiddleware.InternalRender(
FreeAndNil(AJSONValue)
end;
-procedure TMVCJWTAuthenticationMiddleware.OnAfterControllerAction(
- AContext: TWebContext; const AActionName: string;
+function TMVCJWTAuthenticationMiddleware.NeedsToBeExtended(const JWTValue: TJWT): Boolean;
+var
+ lWillExpireIn: Int64;
+begin
+ lWillExpireIn := SecondsBetween(Now, JWTValue.Claims.ExpirationTime);
+ Result := lWillExpireIn <= JWTValue.LiveValidityWindowInSeconds;
+// Log.Debug('--------------------------', 'EXPIRE');
+// Log.DebugFmt('Now : %s', [TimeToStr(Now)], 'EXPIRE');
+// Log.DebugFmt('ExpirationTime : %s', [TimeToStr(JWTValue.Claims.ExpirationTime)], 'EXPIRE');
+// Log.DebugFmt('WillExpireIn : %d', [lWillExpireIn], 'EXPIRE');
+// Log.DebugFmt('LVW : %d', [JWTValue.LiveValidityWindowInSeconds], 'EXPIRE');
+// Log.DebugFmt('NeedsToBeExtened: %s', [BoolToStr(Result, True)], 'EXPIRE');
+end;
+
+procedure TMVCJWTAuthenticationMiddleware.OnAfterControllerAction(AContext: TWebContext; const AActionName: string;
const AHandled: Boolean);
begin
// Implement as needed
end;
-procedure TMVCJWTAuthenticationMiddleware.OnBeforeControllerAction(
- AContext: TWebContext; const AControllerQualifiedClassName,
- AActionName: string; var AHandled: Boolean);
+procedure TMVCJWTAuthenticationMiddleware.OnBeforeControllerAction(AContext: TWebContext;
+ const AControllerQualifiedClassName, AActionName: string; var AHandled: Boolean);
var
AuthRequired: Boolean;
IsAuthorized: Boolean;
@@ -223,14 +212,19 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeControllerAction(
AContext.LoggedUser.LoggedSince := JWTValue.Claims.IssuedAt;
AContext.LoggedUser.CustomData := JWTValue.CustomClaims.AsCustomData;
- FAuthenticationHandler.OnAuthorization(AContext.LoggedUser.Roles, AControllerQualifiedClassName, AActionName, IsAuthorized);
+ FAuthenticationHandler.OnAuthorization(AContext.LoggedUser.Roles, AControllerQualifiedClassName, AActionName,
+ IsAuthorized);
if IsAuthorized then
begin
if JWTValue.LiveValidityWindowInSeconds > 0 then
begin
- JWTValue.Claims.ExpirationTime := Now + JWTValue.LiveValidityWindowInSeconds * OneSecond;
- AContext.Response.SetCustomHeader('Authentication', 'bearer ' + JWTValue.GetToken);
+ if NeedsToBeExtended(JWTValue) then
+ begin
+ ExtendExpirationTime(JWTValue);
+ // .Claims.ExpirationTime := Now + JWTValue.LiveValidityWindowInSeconds * OneSecond;
+ AContext.Response.SetCustomHeader('Authentication', 'bearer ' + JWTValue.GetToken);
+ end;
end;
AHandled := False
end
@@ -245,8 +239,7 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeControllerAction(
end;
end;
-procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
- AContext: TWebContext; var AHandled: Boolean);
+procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
var
UserName: string;
Password: string;
@@ -284,7 +277,8 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
// these claims are mandatory and managed by the middleware
if not JWTValue.CustomClaims['username'].IsEmpty then
- raise EMVCJWTException.Create('Custom claim "username" is reserved and cannot be modified in the JWT setup');
+ raise EMVCJWTException.Create
+ ('Custom claim "username" is reserved and cannot be modified in the JWT setup');
if not JWTValue.CustomClaims['roles'].IsEmpty then
raise EMVCJWTException.Create('Custom claim "roles" is reserved and cannot be modified in the JWT setup');
@@ -294,7 +288,10 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
if JWTValue.LiveValidityWindowInSeconds > 0 then
begin
- JWTValue.Claims.ExpirationTime := Now + (JWTValue.LeewaySeconds + JWTValue.LiveValidityWindowInSeconds) * OneSecond;
+ if NeedsToBeExtended(JWTValue) then
+ begin
+ ExtendExpirationTime(JWTValue);
+ end;
end;
// setup the current logged user from the JWT
@@ -315,12 +312,8 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
end;
end;
- InternalRender(
- TJSONObject.Create(TJSONPair.Create('token', JWTValue.GetToken)),
- TMVCMediaType.APPLICATION_JSON,
- TMVCConstants.DEFAULT_CONTENT_CHARSET,
- AContext
- );
+ InternalRender(TJSONObject.Create(TJSONPair.Create('token', JWTValue.GetToken)),
+ TMVCMediaType.APPLICATION_JSON, TMVCConstants.DEFAULT_CONTENT_CHARSET, AContext);
AHandled := True;
finally
JWTValue.Free;
@@ -340,9 +333,8 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
end;
end;
-procedure TMVCJWTAuthenticationMiddleware.RenderError(const AErrorCode: UInt16;
- const AErrorMessage: string; const AContext: TWebContext;
- const AErrorClassName: string);
+procedure TMVCJWTAuthenticationMiddleware.RenderError(const AErrorCode: UInt16; const AErrorMessage: string;
+ const AContext: TWebContext; const AErrorClassName: string);
var
Jo: TJSONObject;
Status: string;