diff --git a/README.md b/README.md index b3e53de4..1887cc85 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ CEF4Delphi is an open source project created by Salvador D CEF4Delphi is based on DCEF3, made by Henri Gourvest. The original license of DCEF3 still applies to CEF4Delphi. Read the license terms in the first lines of any *.pas file. -CEF4Delphi uses CEF 79.1.3 which includes Chromium 79.0.3945.88. +CEF4Delphi uses CEF 79.1.10 which includes Chromium 79.0.3945.117. The CEF binaries used by CEF4Delphi are available for download at spotify : -* [32 bits](http://opensource.spotify.com/cefbuilds/cef_binary_79.1.3%2Bga5342ed%2Bchromium-79.0.3945.88_windows32.tar.bz2) -* [64 bits](http://opensource.spotify.com/cefbuilds/cef_binary_79.1.3%2Bga5342ed%2Bchromium-79.0.3945.88_windows64.tar.bz2) +* [32 bits](http://opensource.spotify.com/cefbuilds/cef_binary_79.1.10%2Bg7ec49fa%2Bchromium-79.0.3945.117_windows32.tar.bz2) +* [64 bits](http://opensource.spotify.com/cefbuilds/cef_binary_79.1.10%2Bg7ec49fa%2Bchromium-79.0.3945.117_windows64.tar.bz2) CEF4Delphi was developed and tested on Delphi 10.3 Rio and it has been tested in Delphi 7, Delphi XE, Delphi 10, Delphi 10.2 and Lazarus 2.0.6/FPC 3.0.4. CEF4Delphi includes VCL, FireMonkey (FMX) and Lazarus components. diff --git a/demos/Delphi_VCL/OAuth2Tester/00-DeleteDCUs.bat b/demos/Delphi_VCL/OAuth2Tester/00-DeleteDCUs.bat new file mode 100644 index 00000000..a9a84095 --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/00-DeleteDCUs.bat @@ -0,0 +1,18 @@ +del /s /q *.dcu +del /s /q *.exe +del /s /q *.res +del /s /q *.rsm +del /s /q *.log +del /s /q *.dsk +del /s /q *.identcache +del /s /q *.stat +del /s /q *.local +del /s /q *.~* +rmdir Win32\Debug +rmdir Win32\Release +rmdir Win32 +rmdir Win64\Debug +rmdir Win64\Release +rmdir Win64 +rmdir __history +rmdir __recovery diff --git a/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dpr b/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dpr new file mode 100644 index 00000000..3cb78080 --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dpr @@ -0,0 +1,66 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2018 Salvador Díaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + +program OAuth2Tester; + +{$I cef.inc} + +uses + {$IFDEF DELPHI16_UP} + Vcl.Forms, + {$ELSE} + Forms, + {$ENDIF } + uCEFApplication, + uCEFConstants, + uOAuth2TesterFrm in 'uOAuth2TesterFrm.pas' {OAuth2TesterFrm}; + +{$R *.res} + +begin + GlobalCEFApp := TCefApplication.Create; + + if GlobalCEFApp.StartMainProcess then + begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TOAuth2TesterFrm, OAuth2TesterFrm); + Application.Run; + end; + + DestroyGlobalCEFApp; +end. diff --git a/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dproj b/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dproj new file mode 100644 index 00000000..86d20148 --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/OAuth2Tester.dproj @@ -0,0 +1,977 @@ + + + {FF0090FB-12B4-40DE-86E7-6E71DD3624CA} + 18.8 + VCL + OAuth2Tester.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + OAuth2Tester + + + DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;svnui;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;Componentes_UI;vcldb;bindcompfmx;svn;Detours;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;SVGPackage;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;VisualStyles;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + true + PerMonitorV2 + ..\..\..\bin + true + 1033 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + PerMonitorV2 + + + + MainSource + + +
OAuth2TesterFrm
+
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + OAuth2Tester.dpr + + + IP Abstraction Indy Implementation Design Time + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + OAuth2Tester.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/demos/Delphi_VCL/OAuth2Tester/cef.inc b/demos/Delphi_VCL/OAuth2Tester/cef.inc new file mode 100644 index 00000000..8334dc78 --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/cef.inc @@ -0,0 +1,409 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2017 Salvador Diaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + + // The complete list of compiler versions is here : + // http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Compiler_Versions + +{$DEFINE DELPHI_VERSION_UNKNOW} + +// Delphi 5 +{$IFDEF VER130} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} +{$ENDIF} + +// Delphi 6 +{$IFDEF VER140} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} +{$ENDIF} + +// Delphi 7 +{$IFDEF VER150} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} +{$ENDIF} + +// Delphi 8 +{$IFDEF VER160} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} +{$ENDIF} + +// Delphi 2005 +{$IFDEF VER170} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} +{$ENDIF} + +{$IFDEF VER180} + {$UNDEF DELPHI_VERSION_UNKNOW} + // Delphi 2007 + {$IFDEF VER185} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + // Delphi 2006 + {$ELSE} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$ENDIF} +{$ENDIF} + +// Delphi 2009 +{$IFDEF VER200} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} +{$ENDIF} + +//Delphi 2010 +{$IFDEF VER210} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} +{$ENDIF} + +// Delphi XE +{$IFDEF VER220} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} +{$ENDIF} + +// Delphi XE2 (First FireMonkey and 64bit compiler) +{$IFDEF VER230} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} +{$ENDIF} + +// Delphi XE3 +{$IFDEF VER240} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} +{$ENDIF} + +// Delphi XE4 +{$IFDEF VER250} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} +{$ENDIF} + +// Delphi XE5 +{$IFDEF VER260} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} +{$ENDIF} + +// Delphi XE6 +{$IFDEF VER270} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} +{$ENDIF} + +// Delphi XE7 +{$IFDEF VER280} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} +{$ENDIF} + +// Delphi XE8 +{$IFDEF VER290} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} +{$ENDIF VER290} + +// Rad Studio 10 - Delphi Seattle +{$IFDEF VER300} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} +{$ENDIF} + +// Rad Studio 10.1 - Delphi Berlin +{$IFDEF VER310} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} +{$ENDIF} + +// Rad Studio 10.2 - Delphi Tokyo +{$IFDEF VER320} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} +{$ENDIF} + +// Rad Studio 10.3 - Delphi Rio +{$IFDEF VER330} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI26_UP} +{$ENDIF} + +{$IFDEF FPC} + {$DEFINE SUPPORTS_INLINE} +{$ELSE} + {$IFDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI26_UP} + {$ENDIF} +{$ENDIF} + +{$IFDEF DELPHI9_UP} + {$DEFINE SUPPORTS_INLINE} +{$ENDIF} + diff --git a/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.dfm b/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.dfm new file mode 100644 index 00000000..fbfd4e18 --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.dfm @@ -0,0 +1,213 @@ +object OAuth2TesterFrm: TOAuth2TesterFrm + Left = 0 + Top = 0 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'OAuth 2.0 Browser' + ClientHeight = 686 + ClientWidth = 620 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Padding.Left = 10 + Padding.Top = 10 + Padding.Right = 10 + Padding.Bottom = 10 + OldCreateOrder = False + Position = poScreenCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + PixelsPerInch = 96 + TextHeight = 13 + object LoginGrp: TGroupBox + Left = 10 + Top = 10 + Width = 600 + Height = 219 + Align = alTop + Caption = 'Login information ' + TabOrder = 0 + object ClientIDLbl: TLabel + Left = 12 + Top = 27 + Width = 41 + Height = 13 + Caption = 'Client ID' + Layout = tlCenter + end + object ClientSecretLbl: TLabel + Left = 12 + Top = 53 + Width = 60 + Height = 13 + Caption = 'Client secret' + Layout = tlCenter + end + object ScopeLbl: TLabel + Left = 12 + Top = 80 + Width = 29 + Height = 13 + Caption = 'Scope' + Layout = tlCenter + end + object AccessTokenLbl: TLabel + Left = 12 + Top = 107 + Width = 63 + Height = 13 + Caption = 'Access token' + Layout = tlCenter + end + object RefreshTokenLbl: TLabel + Left = 12 + Top = 134 + Width = 68 + Height = 13 + Caption = 'Refresh token' + Layout = tlCenter + end + object ClientIDEdt: TEdit + Left = 88 + Top = 24 + Width = 500 + Height = 21 + TabOrder = 0 + end + object ClientSecretEdt: TEdit + Left = 88 + Top = 50 + Width = 500 + Height = 21 + TabOrder = 1 + end + object ScopeEdt: TEdit + Left = 88 + Top = 77 + Width = 500 + Height = 21 + TabOrder = 2 + Text = 'openid' + end + object AccessTokenEdt: TEdit + Left = 88 + Top = 104 + Width = 500 + Height = 21 + ReadOnly = True + TabOrder = 3 + end + object RefreshTokenEdt: TEdit + Left = 88 + Top = 131 + Width = 500 + Height = 21 + ReadOnly = True + TabOrder = 4 + end + object LoginBtn: TButton + Left = 88 + Top = 169 + Width = 196 + Height = 30 + Caption = 'User login' + TabOrder = 5 + OnClick = LoginBtnClick + end + object RefreshBtn: TButton + Left = 392 + Top = 169 + Width = 196 + Height = 30 + Caption = 'Request new token' + TabOrder = 6 + OnClick = RefreshBtnClick + end + end + object LogGrp: TGroupBox + Left = 10 + Top = 312 + Width = 600 + Height = 364 + Align = alBottom + Caption = ' Log ' + Padding.Left = 10 + Padding.Top = 10 + Padding.Right = 10 + Padding.Bottom = 10 + TabOrder = 1 + object LogMem: TMemo + Left = 12 + Top = 25 + Width = 576 + Height = 327 + Align = alClient + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + WordWrap = False + end + end + object ApiPnl: TPanel + Left = 10 + Top = 229 + Width = 600 + Height = 83 + Align = alClient + BevelOuter = bvNone + Padding.Top = 10 + Padding.Bottom = 10 + TabOrder = 2 + object ApiGrp: TGroupBox + Left = 0 + Top = 10 + Width = 600 + Height = 63 + Align = alClient + Caption = 'API information ' + TabOrder = 0 + object EndpointLbl: TLabel + Left = 12 + Top = 27 + Width = 42 + Height = 13 + Caption = 'Endpoint' + end + object EndpointEdt: TEdit + Left = 88 + Top = 24 + Width = 425 + Height = 21 + TabOrder = 0 + Text = 'https://www.googleapis.com/oauth2/v3/userinfo' + end + object RequestBtn: TButton + Left = 519 + Top = 22 + Width = 69 + Height = 25 + Caption = 'Request' + TabOrder = 1 + OnClick = RequestBtnClick + end + end + end + object CEFServerComponent1: TCEFServerComponent + OnServerDestroyed = CEFServerComponent1ServerDestroyed + OnHttpRequest = CEFServerComponent1HttpRequest + Left = 383 + Top = 480 + end + object CEFUrlRequestClientComponent1: TCEFUrlRequestClientComponent + OnRequestComplete = CEFUrlRequestClientComponent1RequestComplete + OnDownloadProgress = CEFUrlRequestClientComponent1DownloadProgress + OnDownloadData = CEFUrlRequestClientComponent1DownloadData + OnCreateURLRequest = CEFUrlRequestClientComponent1CreateURLRequest + Left = 383 + Top = 544 + end +end diff --git a/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.pas b/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.pas new file mode 100644 index 00000000..5c04529c --- /dev/null +++ b/demos/Delphi_VCL/OAuth2Tester/uOAuth2TesterFrm.pas @@ -0,0 +1,605 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2020 Salvador Diaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + +unit uOAuth2TesterFrm; + +{$I cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, WinApi.ShellApi, + {$ELSE} + Windows, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ShellApi, + {$ENDIF} + uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFConstants, uCEFTypes, + uCEFWinControl, uCEFSentinel, uCEFChromiumCore, uCEFServerComponent, + uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest, uCEFOAuth2Helper; + + +const + URLREQUEST_SUCCESS = WM_APP + $101; + URLREQUEST_ERROR = WM_APP + $102; + AUTHCODE_ERROR = WM_APP + $103; + +type + TOAuthTesterStatus = (tsIdle, tsLogin, tsRefresh, tsRequest); + + TOAuth2TesterFrm = class(TForm) + CEFServerComponent1: TCEFServerComponent; + CEFUrlRequestClientComponent1: TCEFUrlRequestClientComponent; + LoginGrp: TGroupBox; + ClientIDEdt: TEdit; + ClientIDLbl: TLabel; + ClientSecretLbl: TLabel; + ClientSecretEdt: TEdit; + ScopeLbl: TLabel; + ScopeEdt: TEdit; + AccessTokenLbl: TLabel; + AccessTokenEdt: TEdit; + RefreshTokenLbl: TLabel; + RefreshTokenEdt: TEdit; + LoginBtn: TButton; + RefreshBtn: TButton; + LogGrp: TGroupBox; + LogMem: TMemo; + ApiPnl: TPanel; + ApiGrp: TGroupBox; + EndpointLbl: TLabel; + EndpointEdt: TEdit; + RequestBtn: TButton; + + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + + procedure LoginBtnClick(Sender: TObject); + procedure RefreshBtnClick(Sender: TObject); + procedure RequestBtnClick(Sender: TObject); + + procedure CEFUrlRequestClientComponent1CreateURLRequest(Sender: TObject); + procedure CEFUrlRequestClientComponent1DownloadData(Sender: TObject; const request: ICefUrlRequest; data: Pointer; dataLength: NativeUInt); + procedure CEFUrlRequestClientComponent1DownloadProgress( Sender: TObject; const request: ICefUrlRequest; current, total: Int64); + procedure CEFUrlRequestClientComponent1RequestComplete(Sender: TObject; const request: ICefUrlRequest); + + procedure CEFServerComponent1HttpRequest(Sender: TObject; const server: ICefServer; connection_id: Integer; const client_address: ustring; const request: ICefRequest); + procedure CEFServerComponent1ServerDestroyed(Sender: TObject; const server: ICefServer); + + protected + FCanClose : boolean; // Set to True in TChromium.OnBeforeClose + FClosing : boolean; // Set to True in the CloseQuery event. + + FMemStream : TMemoryStream; + FBusy : boolean; + FOAuthHelper : TCEFOAuth2Helper; + FStatus : TOAuthTesterStatus; + + procedure CreateLoginRequest; + procedure CreateTokenRefreshRequest; + procedure CreateAPIRequest; + procedure AppendAuthorizationHeader(const aRequest : ICefRequest); + + procedure URLRequestSuccessMsg(var aMessage : TMessage); message URLREQUEST_SUCCESS; + procedure URLRequestErrorMsg(var aMessage : TMessage); message URLREQUEST_ERROR; + procedure AuthCodeErrorMsg(var aMessage : TMessage); message AUTHCODE_ERROR; + end; + +var + OAuth2TesterFrm: TOAuth2TesterFrm; + +implementation + +{$R *.dfm} + +// This demo shows how to authenticate users using OAuth 2.0 and how +// to make requests to REST APIs that requiere authenticated users. + +// Before you begin, please read the code comments in the URLRequest and SimpleServer +// demos because this demo uses the TCEFUrlRequestClientComponent and TCEFServerComponent +// components too. + +// This demo was tested with the Google API only. If you need to access other REST APIs you +// may need to override some TCEFOAuth2Helper functions to send the right URL parameters. + +// This is an alternative to the "REST Client Library" found in the +// latest Delphi but this time using CEF classes and functions like +// TCEFUrlRequestClientComponent, TCEFServerComponent, etc. + +// As you can see in the REFERENCES, you need to follow a few steps +// to implement OAuth 2.0 in windows applications. + +// STEP 1 : +// ======== +// Obtain OAuth 2.0 client credentials from the API server. + +// In this case, open the Google API Console at https://console.developers.google.com/ +// and go to the "Credentials" page at https://console.developers.google.com/apis/credentials +// Then click "Create credentials -> OAuth client ID" and select "other" to create +// credentials for "native" applications. + +// When it finishes you will see a "Client ID" and a "Client Secret" that you will need +// to run this demo. + +// STEP 2 : +// ======== +// Run this demo and fill the "Client ID" and "Client Secret" edit boxes with the credentials +// you got from Google. + +// STEP 3 : +// ======== +// Click on the "User login" button to launch the system browser and login to google with +// another user account. The URL in that login page was created by TCEFOAuth2Helper and it +// includes the credentials and other safety parameters. + +// Once the user authenticated and he/she has granted permissions the browser will be +// redirected to a local URL served by TCEFServerComponent but Google has added some +// parameters to the redirected URL that will be used in later steps. + +// STEP 4 : +// ======== +// This demo uses TCEFOAuth2Helper to parse the parameters in the redirected URL which includes an +// "authentication code" and then it uses TCEFUrlRequestClientComponent to send a POST request +// to exchange that "authentication code" for an "access token". + +// STEP 5 : +// ======== +// TCEFUrlRequestClientComponent receives the "access token" and a "refresh token" that we'll use to +// request whatever we need to the REST API. + +// STEP 6 : +// ======== +// Click on the "Request" button to request some user information to the REST API using a +// GET request with TCEFUrlRequestClientComponent. This request includes the "access token" in the +// "Authorization" HTTP header. + +// STEP 7 : +// ======== +// The "access token" is only valid for some time and we we'll need to click the "Request new token" +// button to receive a new token when it expires. This function uses TCEFOAuth2Helper and +// TCEFUrlRequestClientComponent to generate the parameters in a POST request needed to +// refresh the token. + +// Read the TCEFOAuth2Helper.TokenExpiry property to know the amount of seconds that the +// "access token" will be valid. + +// Destruction steps +// ================= +// 1- Set CanClose to FALSE in the TForm.OnCloseQuery event, set FClosing to TRUE and call TCEFServerComponent.shutdown. +// 2- If there are pending URLRequests and the TCEFUrlRequestClientComponent.OnDownloadProgress +// event is executed then call request.Cancel, which triggers the TCEFUrlRequestClientComponent.OnRequestComplete event. +// 3- In the TCEFUrlRequestClientComponent.OnRequestComplete event set FCanClose := True and send WM_CLOSE to the form. +// 4- If the TCEFServerComponent was initialized it will trigger TCEFServerComponent.OnServerDestroyed that sets +// FCanClose := True and sends WM_CLOSE to the form. + + +// REFERENCES : +// ============ +// https://tools.ietf.org/html/rfc6749 +// https://tools.ietf.org/html/rfc6750 +// https://tools.ietf.org/html/rfc8252 +// https://tools.ietf.org/html/rfc6819 +// https://tools.ietf.org/html/rfc7636 +// https://tools.ietf.org/html/draft-ietf-oauth-native-apps-12 +// https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13 +// https://developers.google.com/identity/protocols/OAuth2 +// https://developers.google.com/identity/protocols/OAuth2InstalledApp +// https://developers.google.com/identity/protocols/googlescopes +// https://developers.google.com/identity/protocols/OpenIDConnect +// https://aaronparecki.com/oauth-2-simplified/ +// https://example-app.com/pkce + +uses + uCEFApplication, uCEFMiscFunctions, uCEFPostData, uCEFPostDataElement, uCEFStringMultimap; + +procedure TOAuth2TesterFrm.CEFServerComponent1HttpRequest(Sender: TObject; + const server: ICefServer; connection_id: Integer; + const client_address: ustring; const request: ICefRequest); +var + TempData : ustring; +begin + TempData := 'User authentication successfull' + + '

User authentication successfull.

You can close this window now.

'; + + CEFServerComponent1.SendHttp200response(connection_id, 'text/html', @TempData[1], length(TempData) * SizeOf(char)); + + if (request <> nil) then + begin + if FOAuthHelper.ParseCodeRequestResponse(request.url) then + CEFUrlRequestClientComponent1.AddURLRequest + else + PostMessage(Handle, AUTHCODE_ERROR, 0, 0); + end; +end; + +procedure TOAuth2TesterFrm.CEFServerComponent1ServerDestroyed(Sender: TObject; const server: ICefServer); +begin + if FClosing then + begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); + end; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1DownloadData( + Sender: TObject; const request: ICefUrlRequest; data: Pointer; + dataLength: NativeUInt); +begin + try + if FClosing then + request.Cancel + else + if (data <> nil) and (dataLength > 0) then + FMemStream.WriteBuffer(data^, dataLength); + except + on e : exception do + if CustomExceptionHandler('TOAuth2BrowserFrm.CEFUrlRequestClientComponent1DownloadData', e) then raise; + end; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1DownloadProgress( + Sender: TObject; const request: ICefUrlRequest; current, total: Int64); +begin + if FClosing then request.Cancel; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1RequestComplete( + Sender: TObject; const request: ICefUrlRequest); +begin + FBusy := False; + + if FClosing then + begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); + end + else + if (request <> nil) then + begin + if (request.response <> nil) and + (request.RequestStatus = UR_SUCCESS) and + (pos('application/json', request.response.MimeType) > 0) then + PostMessage(Handle, URLREQUEST_SUCCESS, 0, 0) + else + PostMessage(Handle, URLREQUEST_ERROR, 0, request.RequestError); + end + else + PostMessage(Handle, URLREQUEST_ERROR, 0, 0); +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1CreateURLRequest(Sender: TObject); +begin + case FStatus of + tsLogin : CreateLoginRequest; + tsRefresh : CreateTokenRefreshRequest; + tsRequest : CreateAPIRequest; + end; +end; + +procedure TOAuth2TesterFrm.CreateLoginRequest; +var + TempRequest : ICefRequest; + TempPostData : ICefPostData; + TempElement : ICefPostDataElement; + TempElementData : AnsiString; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := FOAuthHelper.TokenEndpoint; + TempRequest.Method := 'POST'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + TempElementData := AnsiString(FOAuthHelper.TokeExchangeParams); + + TempElement := TCefPostDataElementRef.New; + TempElement.SetToBytes(length(TempElementData), @TempElementData[1]); + + TempPostData := TCefPostDataRef.New; + TempPostData.AddElement(TempElement); + + TempRequest.PostData := TempPostData; + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempElement := nil; + TempPostData := nil; + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.CreateTokenRefreshRequest; +var + TempRequest : ICefRequest; + TempPostData : ICefPostData; + TempElement : ICefPostDataElement; + TempElementData : AnsiString; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := FOAuthHelper.TokenEndpoint; + TempRequest.Method := 'POST'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + TempElementData := AnsiString(FOAuthHelper.RefreshParams); + + TempElement := TCefPostDataElementRef.New; + TempElement.SetToBytes(length(TempElementData), @TempElementData[1]); + + TempPostData := TCefPostDataRef.New; + TempPostData.AddElement(TempElement); + + TempRequest.PostData := TempPostData; + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempElement := nil; + TempPostData := nil; + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.CreateAPIRequest; +var + TempRequest : ICefRequest; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := EndpointEdt.Text; + TempRequest.Method := 'GET'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + + AppendAuthorizationHeader(TempRequest); + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.AppendAuthorizationHeader(const aRequest : ICefRequest); +var + TempOldMap, TempNewMap : ICefStringMultimap; + i : NativeUInt; +begin + try + TempNewMap := TCefStringMultimapOwn.Create; + TempOldMap := TCefStringMultimapOwn.Create; + + aRequest.GetHeaderMap(TempOldMap); + + i := 0; + while (i < TempOldMap.Size) do + begin + TempNewMap.Append(TempOldMap.Key[i], TempOldMap.Value[i]); + inc(i); + end; + + TempNewMap.Append('Authorization', FOAuthHelper.TokenType + ' ' + FOAuthHelper.AccessToken); + + aRequest.SetHeaderMap(TempNewMap); + finally + TempNewMap := nil; + TempOldMap := nil; + end; +end; + +procedure TOAuth2TesterFrm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + CanClose := FCanClose and not(FBusy) and not(CEFServerComponent1.Initialized); + + if not(FClosing) then + begin + FClosing := True; + Visible := False; + + if CEFServerComponent1.Initialized then CEFServerComponent1.Shutdown; + end; +end; + +procedure TOAuth2TesterFrm.FormCreate(Sender: TObject); +begin + FMemStream := TMemoryStream.Create; + FCanClose := False; + FClosing := False; + FBusy := False; + FStatus := tsIdle; + + FOAuthHelper := TCEFOAuth2Helper.Create; + {$IFDEF DELPHI22_UP} + // SHA256 is not implemented in TCEFOAuth2Helper for older Delphi versions + FOAuthHelper.ChallengeMethod := cmSHA256; + {$ENDIF} + + CEFServerComponent1.CreateServer(FOAuthHelper.RedirectHost, FOAuthHelper.RedirectPort, 10); +end; + +procedure TOAuth2TesterFrm.FormDestroy(Sender: TObject); +begin + if (FMemStream <> nil) then FreeAndNil(FMemStream); + if (FOAuthHelper <> nil) then FreeAndNil(FOAuthHelper); +end; + +procedure TOAuth2TesterFrm.LoginBtnClick(Sender: TObject); +var + TempAuthURI : string; +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) then + exit; + + FStatus := tsLogin; + screen.cursor := crAppStart; + + FOAuthHelper.ClientID := ClientIDEdt.Text; + FOAuthHelper.ClientSecret := ClientSecretEdt.Text; + FOAuthHelper.Scope := ScopeEdt.Text; + TempAuthURI := FOAuthHelper.AuthCodeURI; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Opening authorization request in the system browser : ' + TempAuthURI); + + ShellExecute(Handle, 'open', PWideChar(TempAuthURI + #0), nil, nil, SW_SHOWNORMAL); +end; + +procedure TOAuth2TesterFrm.RefreshBtnClick(Sender: TObject); +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) or + (length(RefreshTokenEdt.Text) = 0) then + exit; + + FStatus := tsRefresh; + screen.cursor := crAppStart; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Requesting a new token.'); + + CEFUrlRequestClientComponent1.AddURLRequest; +end; + +procedure TOAuth2TesterFrm.RequestBtnClick(Sender: TObject); +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) or + (length(EndpointEdt.Text) = 0) then + exit; + + FStatus := tsRequest; + screen.cursor := crAppStart; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Requesting information to the API endpoint.'); + + CEFUrlRequestClientComponent1.AddURLRequest; +end; + +procedure TOAuth2TesterFrm.URLRequestSuccessMsg(var aMessage : TMessage); +var + TempStream : TStringStream; + TempBuffer : TBytes; +begin + if (FMemStream = nil) or (FMemStream.Size = 0) then exit; + + try + TempStream := nil; + FMemStream.position := 0; + SetLength(TempBuffer, FMemStream.Size); + + if (FMemStream.Read(TempBuffer[0], FMemStream.Size) > 0) then + begin + TempStream := TStringStream.Create(TempBuffer); + + case FStatus of + tsLogin : + begin + LogMem.Lines.Add('Token exchange response : ' + TempStream.DataString); + + if FOAuthHelper.ParseTokenExchangeResponse(TempStream.DataString) then + begin + AccessTokenEdt.Text := FOAuthHelper.AccessToken; + RefreshTokenEdt.Text := FOAuthHelper.RefreshToken; + end + else + begin + AccessTokenEdt.Text := ''; + RefreshTokenEdt.Text := ''; + + showmessage('Login error : ' + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription); + end; + end; + + tsRefresh : + begin + LogMem.Lines.Add('Token refresh response : ' + TempStream.DataString); + + if FOAuthHelper.ParseRefreshTokenResponse(TempStream.DataString) then + AccessTokenEdt.Text := FOAuthHelper.AccessToken + else + showmessage('Token refresh error : ' + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription); + end; + + tsRequest : + LogMem.Lines.Add('API request response : ' + TempStream.DataString); + end; + end; + finally + FMemStream.Clear; + if (TempStream <> nil) then FreeAndNil(TempStream); + SetLength(TempBuffer, 0); + FStatus := tsIdle; + screen.cursor := crDefault; + end; +end; + +procedure TOAuth2TesterFrm.URLRequestErrorMsg(var aMessage : TMessage); +begin + case FStatus of + tsLogin : showmessage('Login error code : ' + inttostr(aMessage.lParam)); + tsRefresh : showmessage('Token refresh error code : ' + inttostr(aMessage.lParam)); + tsRequest : showmessage('API request error code : ' + inttostr(aMessage.lParam)); + end; + + FMemStream.Clear; + FStatus := tsIdle; + screen.cursor := crDefault; +end; + +procedure TOAuth2TesterFrm.AuthCodeErrorMsg(var aMessage : TMessage); +var + TempMessage : string; +begin + TempMessage := 'Authentication error' + #13 + #10; + + if not(FOAuthHelper.ValidState) then + TempMessage := TempMessage + #13 + #10 + 'Received request with invalid state'; + + if (length(FOAuthHelper.Error) > 0) then + TempMessage := TempMessage + #13 + #10 + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription; + + showmessage(TempMessage); +end; + +end. diff --git a/demos/Delphi_VCL/URLRequest/uURLRequest.pas b/demos/Delphi_VCL/URLRequest/uURLRequest.pas index 4efb6bfd..c294ce32 100644 --- a/demos/Delphi_VCL/URLRequest/uURLRequest.pas +++ b/demos/Delphi_VCL/URLRequest/uURLRequest.pas @@ -47,8 +47,7 @@ uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, {$ENDIF} - uCEFInterfaces, uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest, - uCEFSentinel; + uCEFInterfaces, uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest; const URLREQUEST_SUCCESS = WM_APP + $101; @@ -134,8 +133,7 @@ implementation // 1- Set CanClose to FALSE in the TForm.OnCloseQuery event and set FClosing to TRUE. // 2- The next time TCEFUrlRequestClientComponent.OnDownloadProgress is executed we call request.Cancel, which triggers the // TCEFUrlRequestClientComponent.OnRequestComplete event. -// 3- in the TCEFUrlRequestClientComponent.OnRequestComplete event we call TCEFSentinel.Start, which will trigger TCEFSentinel.OnClose when the renderer processes are closed. -// 4- TCEFSentinel.OnClose sets FCanClose := True and sends WM_CLOSE to the form. +// 3- The TCEFUrlRequestClientComponent.OnRequestComplete event sets FCanClose := True and sends WM_CLOSE to the form. uses ShellApi, diff --git a/demos/Lazarus/OAuth2Tester/00-Delete.bat b/demos/Lazarus/OAuth2Tester/00-Delete.bat new file mode 100644 index 00000000..0b5ba5c8 --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/00-Delete.bat @@ -0,0 +1,2 @@ +rmdir /S /Q lib +rmdir /S /Q backup diff --git a/demos/Lazarus/OAuth2Tester/OAuth2Tester.dproj b/demos/Lazarus/OAuth2Tester/OAuth2Tester.dproj new file mode 100644 index 00000000..86d20148 --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/OAuth2Tester.dproj @@ -0,0 +1,977 @@ + + + {FF0090FB-12B4-40DE-86E7-6E71DD3624CA} + 18.8 + VCL + OAuth2Tester.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + OAuth2Tester + + + DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;svnui;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;Componentes_UI;vcldb;bindcompfmx;svn;Detours;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;SVGPackage;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;VisualStyles;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + true + PerMonitorV2 + ..\..\..\bin + true + 1033 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + PerMonitorV2 + + + + MainSource + + +
OAuth2TesterFrm
+
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + OAuth2Tester.dpr + + + IP Abstraction Indy Implementation Design Time + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + OAuth2Tester.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpi b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpi new file mode 100644 index 00000000..67d6422b --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpi @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="CEF4Delphi_Lazarus"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="OAuth2Tester.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="uOAuth2TesterFrm.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="OAuth2TesterFrm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + <Unit2> + <Filename Value="..\..\..\source\uCEFApplication.pas"/> + <IsPartOfProject Value="True"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\..\..\bin\OAuth2Tester"/> + </Target> + <SearchPaths> + <IncludeFiles Value="..\..\..\source;$(ProjOutDir)"/> + <OtherUnitFiles Value="..\..\..\source"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpr b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpr new file mode 100644 index 00000000..92363296 --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lpr @@ -0,0 +1,70 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2018 Salvador Díaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest <hgourvest@gmail.com> + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + +program OAuth2Tester; + +{$MODE Delphi} + +{$I cef.inc} + +uses + {$IFDEF DELPHI16_UP} + WinApi.Windows, + Vcl.Forms, + {$ELSE} + Forms, + LCLIntf, LCLType, LMessages, Interfaces, + {$ENDIF } + uCEFApplication, + uCEFConstants, + uOAuth2TesterFrm in 'uOAuth2TesterFrm.pas' {OAuth2TesterFrm}; + +{.$R *.res} + +begin + GlobalCEFApp := TCefApplication.Create; + + if GlobalCEFApp.StartMainProcess then + begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TOAuth2TesterFrm, OAuth2TesterFrm); + Application.Run; + end; + + DestroyGlobalCEFApp; +end. diff --git a/demos/Lazarus/OAuth2Tester/OAuth2Tester.lps b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lps new file mode 100644 index 00000000..b47df3fe --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/OAuth2Tester.lps @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <PathDelim Value="\"/> + <Version Value="11"/> + <BuildModes Active="Default"/> + <Units Count="10"> + <Unit0> + <Filename Value="OAuth2Tester.lpr"/> + <IsPartOfProject Value="True"/> + <TopLine Value="39"/> + <CursorPos X="56" Y="56"/> + <UsageCount Value="23"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit0> + <Unit1> + <Filename Value="uOAuth2TesterFrm.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="OAuth2TesterFrm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="1"/> + <TopLine Value="130"/> + <CursorPos X="90" Y="141"/> + <UsageCount Value="23"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit1> + <Unit2> + <Filename Value="..\..\..\source\uCEFApplication.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <WindowIndex Value="-1"/> + <TopLine Value="-1"/> + <CursorPos X="-1" Y="-1"/> + <UsageCount Value="23"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit2> + <Unit3> + <Filename Value="..\URLRequest\uURLRequest.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="385"/> + <CursorPos X="15" Y="409"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit3> + <Unit4> + <Filename Value="C:\lazarus\fpc\3.0.4\source\rtl\objpas\classes\classesh.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="1820"/> + <CursorPos X="17" Y="1840"/> + <UsageCount Value="10"/> + </Unit4> + <Unit5> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <EditorIndex Value="2"/> + <TopLine Value="469"/> + <CursorPos X="62" Y="473"/> + <UsageCount Value="11"/> + <Bookmarks Count="1"> + <Item0 X="88" Y="307" ID="1"/> + </Bookmarks> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit5> + <Unit6> + <Filename Value="..\..\..\source\uCEFTypes.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="289"/> + <CursorPos X="3" Y="291"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit6> + <Unit7> + <Filename Value="..\SimpleServer\uSimpleServer.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="152"/> + <CursorPos X="50" Y="176"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit7> + <Unit8> + <Filename Value="C:\lazarus\fpc\3.0.4\source\rtl\win64\windows.pp"/> + <EditorIndex Value="-1"/> + <UsageCount Value="10"/> + </Unit8> + <Unit9> + <Filename Value="..\..\..\..\..\..\..\..\AppData\Local\lazarus\onlinepackagemanager\packages\dcpcrypt-2.0.4.1\Hashes\dcpsha256.pas"/> + <UnitName Value="DCPsha256"/> + <EditorIndex Value="-1"/> + <TopLine Value="255"/> + <CursorPos Y="282"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit9> + </Units> + <JumpHistory Count="20" HistoryIndex="19"> + <Position1> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="314" TopLine="307"/> + </Position1> + <Position2> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="324" TopLine="307"/> + </Position2> + <Position3> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="323" TopLine="307"/> + </Position3> + <Position4> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="324" TopLine="307"/> + </Position4> + <Position5> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="284" Column="49" TopLine="270"/> + </Position5> + <Position6> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="286" TopLine="270"/> + </Position6> + <Position7> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="289" TopLine="270"/> + </Position7> + <Position8> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="290" TopLine="270"/> + </Position8> + <Position9> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="293" TopLine="270"/> + </Position9> + <Position10> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="294" TopLine="270"/> + </Position10> + <Position11> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="293" TopLine="270"/> + </Position11> + <Position12> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="208" Column="24" TopLine="181"/> + </Position12> + <Position13> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="196" Column="47" TopLine="181"/> + </Position13> + <Position14> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="241" Column="31" TopLine="226"/> + </Position14> + <Position15> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="244" Column="75" TopLine="243"/> + </Position15> + <Position16> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="465" Column="34" TopLine="450"/> + </Position16> + <Position17> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="466" Column="34" TopLine="451"/> + </Position17> + <Position18> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="467" Column="34" TopLine="452"/> + </Position18> + <Position19> + <Filename Value="..\..\..\source\uCEFOAuth2Helper.pas"/> + <Caret Line="468" Column="34" TopLine="454"/> + </Position19> + <Position20> + <Filename Value="uOAuth2TesterFrm.pas"/> + <Caret Line="354" Column="77" TopLine="314"/> + </Position20> + </JumpHistory> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0" ActiveMode=""/> + </RunParams> + </ProjectSession> +</CONFIG> diff --git a/demos/Lazarus/OAuth2Tester/cef.inc b/demos/Lazarus/OAuth2Tester/cef.inc new file mode 100644 index 00000000..8334dc78 --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/cef.inc @@ -0,0 +1,409 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2017 Salvador Diaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest <hgourvest@gmail.com> + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + + // The complete list of compiler versions is here : + // http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Compiler_Versions + +{$DEFINE DELPHI_VERSION_UNKNOW} + +// Delphi 5 +{$IFDEF VER130} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} +{$ENDIF} + +// Delphi 6 +{$IFDEF VER140} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} +{$ENDIF} + +// Delphi 7 +{$IFDEF VER150} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} +{$ENDIF} + +// Delphi 8 +{$IFDEF VER160} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} +{$ENDIF} + +// Delphi 2005 +{$IFDEF VER170} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} +{$ENDIF} + +{$IFDEF VER180} + {$UNDEF DELPHI_VERSION_UNKNOW} + // Delphi 2007 + {$IFDEF VER185} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + // Delphi 2006 + {$ELSE} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$ENDIF} +{$ENDIF} + +// Delphi 2009 +{$IFDEF VER200} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} +{$ENDIF} + +//Delphi 2010 +{$IFDEF VER210} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} +{$ENDIF} + +// Delphi XE +{$IFDEF VER220} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} +{$ENDIF} + +// Delphi XE2 (First FireMonkey and 64bit compiler) +{$IFDEF VER230} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} +{$ENDIF} + +// Delphi XE3 +{$IFDEF VER240} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} +{$ENDIF} + +// Delphi XE4 +{$IFDEF VER250} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} +{$ENDIF} + +// Delphi XE5 +{$IFDEF VER260} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} +{$ENDIF} + +// Delphi XE6 +{$IFDEF VER270} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} +{$ENDIF} + +// Delphi XE7 +{$IFDEF VER280} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} +{$ENDIF} + +// Delphi XE8 +{$IFDEF VER290} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} +{$ENDIF VER290} + +// Rad Studio 10 - Delphi Seattle +{$IFDEF VER300} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} +{$ENDIF} + +// Rad Studio 10.1 - Delphi Berlin +{$IFDEF VER310} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} +{$ENDIF} + +// Rad Studio 10.2 - Delphi Tokyo +{$IFDEF VER320} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} +{$ENDIF} + +// Rad Studio 10.3 - Delphi Rio +{$IFDEF VER330} + {$UNDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI26_UP} +{$ENDIF} + +{$IFDEF FPC} + {$DEFINE SUPPORTS_INLINE} +{$ELSE} + {$IFDEF DELPHI_VERSION_UNKNOW} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI26_UP} + {$ENDIF} +{$ENDIF} + +{$IFDEF DELPHI9_UP} + {$DEFINE SUPPORTS_INLINE} +{$ENDIF} + diff --git a/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.lfm b/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.lfm new file mode 100644 index 00000000..ded1319d --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.lfm @@ -0,0 +1,215 @@ +object OAuth2TesterFrm: TOAuth2TesterFrm + Left = 352 + Height = 658 + Top = 162 + Width = 609 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'OAuth 2.0 Browser' + ClientHeight = 658 + ClientWidth = 609 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + Position = poScreenCenter + LCLVersion = '2.0.6.0' + object LoginGrp: TGroupBox + Left = 0 + Height = 230 + Top = 0 + Width = 609 + Align = alTop + Caption = 'Login information ' + ClientHeight = 212 + ClientWidth = 605 + TabOrder = 0 + object ClientIDLbl: TLabel + Left = 12 + Height = 13 + Top = 27 + Width = 41 + Caption = 'Client ID' + Layout = tlCenter + ParentColor = False + end + object ClientSecretLbl: TLabel + Left = 12 + Height = 13 + Top = 53 + Width = 60 + Caption = 'Client secret' + Layout = tlCenter + ParentColor = False + end + object ScopeLbl: TLabel + Left = 12 + Height = 13 + Top = 80 + Width = 29 + Caption = 'Scope' + Layout = tlCenter + ParentColor = False + end + object AccessTokenLbl: TLabel + Left = 12 + Height = 13 + Top = 107 + Width = 63 + Caption = 'Access token' + Layout = tlCenter + ParentColor = False + end + object RefreshTokenLbl: TLabel + Left = 12 + Height = 13 + Top = 134 + Width = 68 + Caption = 'Refresh token' + Layout = tlCenter + ParentColor = False + end + object ClientIDEdt: TEdit + Left = 88 + Height = 21 + Top = 24 + Width = 500 + TabOrder = 0 + end + object ClientSecretEdt: TEdit + Left = 88 + Height = 21 + Top = 50 + Width = 500 + TabOrder = 1 + end + object ScopeEdt: TEdit + Left = 88 + Height = 21 + Top = 77 + Width = 500 + TabOrder = 2 + Text = 'openid' + end + object AccessTokenEdt: TEdit + Left = 88 + Height = 21 + Top = 104 + Width = 500 + ReadOnly = True + TabOrder = 3 + end + object RefreshTokenEdt: TEdit + Left = 88 + Height = 21 + Top = 131 + Width = 500 + ReadOnly = True + TabOrder = 4 + end + object LoginBtn: TButton + Left = 88 + Height = 30 + Top = 169 + Width = 196 + Caption = 'User login' + OnClick = LoginBtnClick + TabOrder = 5 + end + object RefreshBtn: TButton + Left = 392 + Height = 30 + Top = 169 + Width = 196 + Caption = 'Request new token' + OnClick = RefreshBtnClick + TabOrder = 6 + end + end + object LogGrp: TGroupBox + Left = 0 + Height = 364 + Top = 294 + Width = 609 + Align = alBottom + Caption = ' Log ' + ClientHeight = 346 + ClientWidth = 605 + TabOrder = 1 + object LogMem: TMemo + Left = 0 + Height = 346 + Top = 0 + Width = 605 + Align = alClient + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + WordWrap = False + end + end + object ApiPnl: TPanel + Left = 0 + Height = 64 + Top = 230 + Width = 609 + Align = alClient + BevelOuter = bvNone + ClientHeight = 64 + ClientWidth = 609 + TabOrder = 2 + object ApiGrp: TGroupBox + Left = 0 + Height = 64 + Top = 0 + Width = 609 + Align = alClient + Caption = 'API information ' + ClientHeight = 46 + ClientWidth = 605 + TabOrder = 0 + object EndpointLbl: TLabel + Left = 12 + Height = 13 + Top = 12 + Width = 42 + Caption = 'Endpoint' + ParentColor = False + end + object EndpointEdt: TEdit + Left = 88 + Height = 21 + Top = 9 + Width = 425 + TabOrder = 0 + Text = 'https://www.googleapis.com/oauth2/v3/userinfo' + end + object RequestBtn: TButton + Left = 519 + Height = 25 + Top = 7 + Width = 69 + Caption = 'Request' + OnClick = RequestBtnClick + TabOrder = 1 + end + end + end + object CEFServerComponent1: TCEFServerComponent + OnServerDestroyed = CEFServerComponent1ServerDestroyed + OnHttpRequest = CEFServerComponent1HttpRequest + left = 383 + top = 480 + end + object CEFUrlRequestClientComponent1: TCEFUrlRequestClientComponent + OnRequestComplete = CEFUrlRequestClientComponent1RequestComplete + OnDownloadProgress = CEFUrlRequestClientComponent1DownloadProgress + OnDownloadData = CEFUrlRequestClientComponent1DownloadData + OnCreateURLRequest = CEFUrlRequestClientComponent1CreateURLRequest + left = 383 + top = 544 + end +end diff --git a/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.pas b/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.pas new file mode 100644 index 00000000..dcadf155 --- /dev/null +++ b/demos/Lazarus/OAuth2Tester/uOAuth2TesterFrm.pas @@ -0,0 +1,602 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2020 Salvador Diaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest <hgourvest@gmail.com> + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + +unit uOAuth2TesterFrm; + +{$MODE Delphi} + +{$I cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, WinApi.ShellApi, + {$ELSE} + LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, + {$ENDIF} + uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFConstants, uCEFTypes, + uCEFWinControl, uCEFSentinel, uCEFChromiumCore, uCEFServerComponent, + uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest, uCEFOAuth2Helper; + + +const + URLREQUEST_SUCCESS = WM_APP + $101; + URLREQUEST_ERROR = WM_APP + $102; + AUTHCODE_ERROR = WM_APP + $103; + +type + TOAuthTesterStatus = (tsIdle, tsLogin, tsRefresh, tsRequest); + + TOAuth2TesterFrm = class(TForm) + CEFServerComponent1: TCEFServerComponent; + CEFUrlRequestClientComponent1: TCEFUrlRequestClientComponent; + LoginGrp: TGroupBox; + ClientIDEdt: TEdit; + ClientIDLbl: TLabel; + ClientSecretLbl: TLabel; + ClientSecretEdt: TEdit; + ScopeLbl: TLabel; + ScopeEdt: TEdit; + AccessTokenLbl: TLabel; + AccessTokenEdt: TEdit; + RefreshTokenLbl: TLabel; + RefreshTokenEdt: TEdit; + LoginBtn: TButton; + RefreshBtn: TButton; + LogGrp: TGroupBox; + LogMem: TMemo; + ApiPnl: TPanel; + ApiGrp: TGroupBox; + EndpointLbl: TLabel; + EndpointEdt: TEdit; + RequestBtn: TButton; + + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + + procedure LoginBtnClick(Sender: TObject); + procedure RefreshBtnClick(Sender: TObject); + procedure RequestBtnClick(Sender: TObject); + + procedure CEFUrlRequestClientComponent1CreateURLRequest(Sender: TObject); + procedure CEFUrlRequestClientComponent1DownloadData(Sender: TObject; const request: ICefUrlRequest; data: Pointer; dataLength: NativeUInt); + procedure CEFUrlRequestClientComponent1DownloadProgress( Sender: TObject; const request: ICefUrlRequest; current, total: Int64); + procedure CEFUrlRequestClientComponent1RequestComplete(Sender: TObject; const request: ICefUrlRequest); + + procedure CEFServerComponent1HttpRequest(Sender: TObject; const server: ICefServer; connection_id: Integer; const client_address: ustring; const request: ICefRequest); + procedure CEFServerComponent1ServerDestroyed(Sender: TObject; const server: ICefServer); + + protected + FCanClose : boolean; // Set to True in TChromium.OnBeforeClose + FClosing : boolean; // Set to True in the CloseQuery event. + + FMemStream : TMemoryStream; + FBusy : boolean; + FOAuthHelper : TCEFOAuth2Helper; + FStatus : TOAuthTesterStatus; + + procedure CreateLoginRequest; + procedure CreateTokenRefreshRequest; + procedure CreateAPIRequest; + procedure AppendAuthorizationHeader(const aRequest : ICefRequest); + + procedure URLRequestSuccessMsg(var aMessage : TMessage); message URLREQUEST_SUCCESS; + procedure URLRequestErrorMsg(var aMessage : TMessage); message URLREQUEST_ERROR; + procedure AuthCodeErrorMsg(var aMessage : TMessage); message AUTHCODE_ERROR; + end; + +var + OAuth2TesterFrm: TOAuth2TesterFrm; + +implementation + +{$R *.lfm} + +// This demo shows how to authenticate users using OAuth 2.0 and how +// to make requests to REST APIs that requiere authenticated users. + +// Before you begin, please read the code comments in the URLRequest and SimpleServer +// demos because this demo uses the TCEFUrlRequestClientComponent and TCEFServerComponent +// components too. + +// This demo was tested with the Google API only. If you need to access other REST APIs you +// may need to override some TCEFOAuth2Helper functions to send the right URL parameters. + +// This is an alternative to the "REST Client Library" found in the +// latest Delphi but this time using CEF classes and functions like +// TCEFUrlRequestClientComponent, TCEFServerComponent, etc. + +// As you can see in the REFERENCES, you need to follow a few steps +// to implement OAuth 2.0 in windows applications. + +// STEP 1 : +// ======== +// Obtain OAuth 2.0 client credentials from the API server. + +// In this case, open the Google API Console at https://console.developers.google.com/ +// and go to the "Credentials" page at https://console.developers.google.com/apis/credentials +// Then click "Create credentials -> OAuth client ID" and select "other" to create +// credentials for "native" applications. + +// When it finishes you will see a "Client ID" and a "Client Secret" that you will need +// to run this demo. + +// STEP 2 : +// ======== +// Run this demo and fill the "Client ID" and "Client Secret" edit boxes with the credentials +// you got from Google. + +// STEP 3 : +// ======== +// Click on the "User login" button to launch the system browser and login to google with +// another user account. The URL in that login page was created by TCEFOAuth2Helper and it +// includes the credentials and other safety parameters. + +// Once the user authenticated and he/she has granted permissions the browser will be +// redirected to a local URL served by TCEFServerComponent but Google has added some +// parameters to the redirected URL that will be used in later steps. + +// STEP 4 : +// ======== +// This demo uses TCEFOAuth2Helper to parse the parameters in the redirected URL which includes an +// "authentication code" and then it uses TCEFUrlRequestClientComponent to send a POST request +// to exchange that "authentication code" for an "access token". + +// STEP 5 : +// ======== +// TCEFUrlRequestClientComponent receives the "access token" and a "refresh token" that we'll use to +// request whatever we need to the REST API. + +// STEP 6 : +// ======== +// Click on the "Request" button to request some user information to the REST API using a +// GET request with TCEFUrlRequestClientComponent. This request includes the "access token" in the +// "Authorization" HTTP header. + +// STEP 7 : +// ======== +// The "access token" is only valid for some time and we we'll need to click the "Request new token" +// button to receive a new token when it expires. This function uses TCEFOAuth2Helper and +// TCEFUrlRequestClientComponent to generate the parameters in a POST request needed to +// refresh the token. + +// Read the TCEFOAuth2Helper.TokenExpiry property to know the amount of seconds that the +// "access token" will be valid. + +// Destruction steps +// ================= +// 1- Set CanClose to FALSE in the TForm.OnCloseQuery event, set FClosing to TRUE and call TCEFServerComponent.shutdown. +// 2- If there are pending URLRequests and the TCEFUrlRequestClientComponent.OnDownloadProgress +// event is executed then call request.Cancel, which triggers the TCEFUrlRequestClientComponent.OnRequestComplete event. +// 3- In the TCEFUrlRequestClientComponent.OnRequestComplete event set FCanClose := True and send WM_CLOSE to the form. +// 4- If the TCEFServerComponent was initialized it will trigger TCEFServerComponent.OnServerDestroyed that sets +// FCanClose := True and sends WM_CLOSE to the form. + + +// REFERENCES : +// ============ +// https://tools.ietf.org/html/rfc6749 +// https://tools.ietf.org/html/rfc6750 +// https://tools.ietf.org/html/rfc8252 +// https://tools.ietf.org/html/rfc6819 +// https://tools.ietf.org/html/rfc7636 +// https://tools.ietf.org/html/draft-ietf-oauth-native-apps-12 +// https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13 +// https://developers.google.com/identity/protocols/OAuth2 +// https://developers.google.com/identity/protocols/OAuth2InstalledApp +// https://developers.google.com/identity/protocols/googlescopes +// https://developers.google.com/identity/protocols/OpenIDConnect +// https://aaronparecki.com/oauth-2-simplified/ +// https://example-app.com/pkce + +uses + uCEFApplication, uCEFMiscFunctions, uCEFPostData, uCEFPostDataElement, uCEFStringMultimap; + +procedure TOAuth2TesterFrm.CEFServerComponent1HttpRequest(Sender: TObject; + const server: ICefServer; connection_id: Integer; + const client_address: ustring; const request: ICefRequest); +var + TempData : string; +begin + TempData := '<html><head><title>User authentication successfull' + + '

User authentication successfull.

You can close this window now.

'; + + CEFServerComponent1.SendHttp200response(connection_id, 'text/html', @TempData[1], length(TempData) * SizeOf(char)); + + if (request <> nil) then + begin + if FOAuthHelper.ParseCodeRequestResponse(request.url) then + CEFUrlRequestClientComponent1.AddURLRequest + else + PostMessage(Handle, AUTHCODE_ERROR, 0, 0); + end; +end; + +procedure TOAuth2TesterFrm.CEFServerComponent1ServerDestroyed(Sender: TObject; const server: ICefServer); +begin + if FClosing then + begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); + end; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1DownloadData( + Sender: TObject; const request: ICefUrlRequest; data: Pointer; + dataLength: NativeUInt); +begin + try + if FClosing then + request.Cancel + else + if (data <> nil) and (dataLength > 0) then + FMemStream.WriteBuffer(data^, dataLength); + except + on e : exception do + if CustomExceptionHandler('TOAuth2BrowserFrm.CEFUrlRequestClientComponent1DownloadData', e) then raise; + end; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1DownloadProgress( + Sender: TObject; const request: ICefUrlRequest; current, total: Int64); +begin + if FClosing then request.Cancel; +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1RequestComplete( + Sender: TObject; const request: ICefUrlRequest); +begin + FBusy := False; + + if FClosing then + begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); + end + else + if (request <> nil) then + begin + if (request.response <> nil) and + (request.RequestStatus = UR_SUCCESS) and + (pos('application/json', request.response.MimeType) > 0) then + PostMessage(Handle, URLREQUEST_SUCCESS, 0, 0) + else + PostMessage(Handle, URLREQUEST_ERROR, 0, request.RequestError); + end + else + PostMessage(Handle, URLREQUEST_ERROR, 0, 0); +end; + +procedure TOAuth2TesterFrm.CEFUrlRequestClientComponent1CreateURLRequest(Sender: TObject); +begin + case FStatus of + tsLogin : CreateLoginRequest; + tsRefresh : CreateTokenRefreshRequest; + tsRequest : CreateAPIRequest; + end; +end; + +procedure TOAuth2TesterFrm.CreateLoginRequest; +var + TempRequest : ICefRequest; + TempPostData : ICefPostData; + TempElement : ICefPostDataElement; + TempElementData : AnsiString; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := FOAuthHelper.TokenEndpoint; + TempRequest.Method := 'POST'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + TempElementData := AnsiString(FOAuthHelper.TokeExchangeParams); + + TempElement := TCefPostDataElementRef.New; + TempElement.SetToBytes(length(TempElementData), @TempElementData[1]); + + TempPostData := TCefPostDataRef.New; + TempPostData.AddElement(TempElement); + + TempRequest.PostData := TempPostData; + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempElement := nil; + TempPostData := nil; + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.CreateTokenRefreshRequest; +var + TempRequest : ICefRequest; + TempPostData : ICefPostData; + TempElement : ICefPostDataElement; + TempElementData : AnsiString; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := FOAuthHelper.TokenEndpoint; + TempRequest.Method := 'POST'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + TempElementData := AnsiString(FOAuthHelper.RefreshParams); + + TempElement := TCefPostDataElementRef.New; + TempElement.SetToBytes(length(TempElementData), @TempElementData[1]); + + TempPostData := TCefPostDataRef.New; + TempPostData.AddElement(TempElement); + + TempRequest.PostData := TempPostData; + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempElement := nil; + TempPostData := nil; + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.CreateAPIRequest; +var + TempRequest : ICefRequest; +begin + try + FBusy := True; + TempRequest := TCefRequestRef.New; + TempRequest.URL := EndpointEdt.Text; + TempRequest.Method := 'GET'; + TempRequest.Flags := UR_FLAG_ALLOW_STORED_CREDENTIALS; + + AppendAuthorizationHeader(TempRequest); + + TCefUrlRequestRef.New(TempRequest, CEFUrlRequestClientComponent1.Client, nil); + finally + TempRequest := nil; + end; +end; + +procedure TOAuth2TesterFrm.AppendAuthorizationHeader(const aRequest : ICefRequest); +var + TempOldMap, TempNewMap : ICefStringMultimap; + i : NativeUInt; +begin + try + TempNewMap := TCefStringMultimapOwn.Create; + TempOldMap := TCefStringMultimapOwn.Create; + + aRequest.GetHeaderMap(TempOldMap); + + i := 0; + while (i < TempOldMap.Size) do + begin + TempNewMap.Append(TempOldMap.Key[i], TempOldMap.Value[i]); + inc(i); + end; + + TempNewMap.Append('Authorization', FOAuthHelper.TokenType + ' ' + FOAuthHelper.AccessToken); + + aRequest.SetHeaderMap(TempNewMap); + finally + TempNewMap := nil; + TempOldMap := nil; + end; +end; + +procedure TOAuth2TesterFrm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + CanClose := FCanClose and not(FBusy) and not(CEFServerComponent1.Initialized); + + if not(FClosing) then + begin + FClosing := True; + Visible := False; + + if CEFServerComponent1.Initialized then CEFServerComponent1.Shutdown; + end; +end; + +procedure TOAuth2TesterFrm.FormCreate(Sender: TObject); +begin + FMemStream := TMemoryStream.Create; + FCanClose := False; + FClosing := False; + FBusy := False; + FStatus := tsIdle; + + FOAuthHelper := TCEFOAuth2Helper.Create; + FOAuthHelper.ChallengeMethod := cmSHA256; + + CEFServerComponent1.CreateServer(FOAuthHelper.RedirectHost, FOAuthHelper.RedirectPort, 10); +end; + +procedure TOAuth2TesterFrm.FormDestroy(Sender: TObject); +begin + if (FMemStream <> nil) then FreeAndNil(FMemStream); + if (FOAuthHelper <> nil) then FreeAndNil(FOAuthHelper); +end; + +procedure TOAuth2TesterFrm.LoginBtnClick(Sender: TObject); +var + TempAuthURI : string; +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) then + exit; + + FStatus := tsLogin; + screen.cursor := crAppStart; + + FOAuthHelper.ClientID := ClientIDEdt.Text; + FOAuthHelper.ClientSecret := ClientSecretEdt.Text; + FOAuthHelper.Scope := ScopeEdt.Text; + TempAuthURI := FOAuthHelper.AuthCodeURI; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Opening authorization request in the system browser : ' + TempAuthURI); + + OpenURL(TempAuthURI); +end; + +procedure TOAuth2TesterFrm.RefreshBtnClick(Sender: TObject); +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) or + (length(RefreshTokenEdt.Text) = 0) then + exit; + + FStatus := tsRefresh; + screen.cursor := crAppStart; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Requesting a new token.'); + + CEFUrlRequestClientComponent1.AddURLRequest; +end; + +procedure TOAuth2TesterFrm.RequestBtnClick(Sender: TObject); +begin + if (FStatus <> tsIdle) or + (length(ClientIDEdt.Text) = 0) or + (length(ClientSecretEdt.Text) = 0) or + (length(ScopeEdt.Text) = 0) or + (length(EndpointEdt.Text) = 0) then + exit; + + FStatus := tsRequest; + screen.cursor := crAppStart; + + LogMem.Lines.Add('-----------------------------------------------------------------'); + LogMem.Lines.Add('Requesting information to the API endpoint.'); + + CEFUrlRequestClientComponent1.AddURLRequest; +end; + +procedure TOAuth2TesterFrm.URLRequestSuccessMsg(var aMessage : TMessage); +var + TempRawResponse : AnsiString; + TempResponse : ustring; +begin + if (FMemStream = nil) or (FMemStream.Size = 0) then exit; + + try + FMemStream.position := 0; + SetLength(TempRawResponse, FMemStream.Size); + + if (FMemStream.Read(TempRawResponse[1], FMemStream.Size) > 0) then + begin + TempResponse := UTF8Decode(TempRawResponse); + + case FStatus of + tsLogin : + begin + LogMem.Lines.Add('Token exchange response : ' + TempResponse); + + if FOAuthHelper.ParseTokenExchangeResponse(TempResponse) then + begin + AccessTokenEdt.Text := FOAuthHelper.AccessToken; + RefreshTokenEdt.Text := FOAuthHelper.RefreshToken; + end + else + begin + AccessTokenEdt.Text := ''; + RefreshTokenEdt.Text := ''; + + showmessage('Login error : ' + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription); + end; + end; + + tsRefresh : + begin + LogMem.Lines.Add('Token refresh response : ' + TempResponse); + + if FOAuthHelper.ParseRefreshTokenResponse(TempResponse) then + AccessTokenEdt.Text := FOAuthHelper.AccessToken + else + showmessage('Token refresh error : ' + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription); + end; + + tsRequest : + LogMem.Lines.Add('API request response : ' + TempResponse); + end; + + end; + finally + FMemStream.Clear; + FStatus := tsIdle; + screen.cursor := crDefault; + end; +end; + +procedure TOAuth2TesterFrm.URLRequestErrorMsg(var aMessage : TMessage); +begin + case FStatus of + tsLogin : showmessage('Login error code : ' + inttostr(aMessage.lParam)); + tsRefresh : showmessage('Token refresh error code : ' + inttostr(aMessage.lParam)); + tsRequest : showmessage('API request error code : ' + inttostr(aMessage.lParam)); + end; + + FMemStream.Clear; + FStatus := tsIdle; + screen.cursor := crDefault; +end; + +procedure TOAuth2TesterFrm.AuthCodeErrorMsg(var aMessage : TMessage); +var + TempMessage : string; +begin + TempMessage := 'Authentication error' + #13 + #10; + + if not(FOAuthHelper.ValidState) then + TempMessage := TempMessage + #13 + #10 + 'Received request with invalid state'; + + if (length(FOAuthHelper.Error) > 0) then + TempMessage := TempMessage + #13 + #10 + FOAuthHelper.Error + #13 + #10 + FOAuthHelper.ErrorDescription; + + showmessage(TempMessage); +end; + +end. diff --git a/packages/CEF4Delphi.dpk b/packages/CEF4Delphi.dpk index a92e5518..988ded6e 100644 --- a/packages/CEF4Delphi.dpk +++ b/packages/CEF4Delphi.dpk @@ -174,7 +174,8 @@ contains uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFSentinel in '..\source\uCEFSentinel.pas', - uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; + uCEFApplicationCore in '..\source\uCEFApplicationCore.pas', + uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas'; end. diff --git a/packages/CEF4Delphi.dproj b/packages/CEF4Delphi.dproj index ef6dea49..7671efbf 100644 --- a/packages/CEF4Delphi.dproj +++ b/packages/CEF4Delphi.dproj @@ -2,7 +2,7 @@ {2F51F1BD-0529-4B4A-BFD2-86FE96910A62} CEF4Delphi.dpk - 18.5 + 18.8 VCL True Debug @@ -269,6 +269,7 @@ + Base @@ -324,12 +325,20 @@ classes 1 + + classes + 1 + res\xml 1 + + res\xml + 1 + @@ -342,96 +351,242 @@ library\lib\armeabi 1 + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + library\lib\mips 1 + + library\lib\mips + 1 + library\lib\armeabi-v7a 1 + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + res\drawable 1 + + res\drawable + 1 + res\values 1 + + res\values + 1 + res\values-v21 1 + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + res\drawable 1 + + res\drawable + 1 + res\drawable-xxhdpi 1 + + res\drawable-xxhdpi + 1 + res\drawable-ldpi 1 + + res\drawable-ldpi + 1 + res\drawable-mdpi 1 + + res\drawable-mdpi + 1 + res\drawable-hdpi 1 + + res\drawable-hdpi + 1 + res\drawable-xhdpi 1 + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + res\drawable-small 1 + + res\drawable-small + 1 + res\drawable-normal 1 + + res\drawable-normal + 1 + res\drawable-large 1 + + res\drawable-large + 1 + res\drawable-xlarge 1 + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + @@ -501,6 +656,9 @@ 0 + + 0 + 0 @@ -531,6 +689,17 @@ 1 + + + 1 + + + 1 + + + 1 + + 1 @@ -542,6 +711,39 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -553,6 +755,61 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -564,6 +821,116 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -597,10 +964,35 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 + + 1 + @@ -644,6 +1036,10 @@ library\lib\armeabi-v7a 1 + + library\lib\arm64-v8a + 1 + 1 @@ -666,6 +1062,12 @@ 0 + + + library\lib\armeabi-v7a + 1 + + 1 @@ -703,6 +1105,7 @@ + True diff --git a/packages/CEF4Delphi_D7.dpk b/packages/CEF4Delphi_D7.dpk index 46da4b8f..f9e53257 100644 --- a/packages/CEF4Delphi_D7.dpk +++ b/packages/CEF4Delphi_D7.dpk @@ -171,6 +171,7 @@ contains uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFSentinel in '..\source\uCEFSentinel.pas', - uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; + uCEFApplicationCore in '..\source\uCEFApplicationCore.pas', + uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas'; end. diff --git a/packages/CEF4Delphi_FMX.dpk b/packages/CEF4Delphi_FMX.dpk index ed0a0240..1b354776 100644 --- a/packages/CEF4Delphi_FMX.dpk +++ b/packages/CEF4Delphi_FMX.dpk @@ -22,7 +22,7 @@ package CEF4Delphi_FMX; {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} -{$IMAGEBASE $54C00000} +{$IMAGEBASE $400000} {$DEFINE $(FrameworkType)} {$ENDIF IMPLICITBUILDING} {$DESCRIPTION 'CEF4Delphi'} @@ -179,7 +179,8 @@ contains uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFSentinel in '..\source\uCEFSentinel.pas', - uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; + uCEFApplicationCore in '..\source\uCEFApplicationCore.pas', + uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas'; end. diff --git a/packages/CEF4Delphi_FMX.dproj b/packages/CEF4Delphi_FMX.dproj index fe984416..63bbf7ce 100644 --- a/packages/CEF4Delphi_FMX.dproj +++ b/packages/CEF4Delphi_FMX.dproj @@ -295,6 +295,7 @@ + Base diff --git a/packages/cef4delphi_lazarus.lpk b/packages/cef4delphi_lazarus.lpk index 139aecee..74de05a0 100644 --- a/packages/cef4delphi_lazarus.lpk +++ b/packages/cef4delphi_lazarus.lpk @@ -21,8 +21,8 @@ - - + + @@ -616,17 +616,24 @@ + + + + - + - + - + - + + + + diff --git a/packages/cef4delphi_lazarus.pas b/packages/cef4delphi_lazarus.pas index 30c4fd4b..e6e69335 100644 --- a/packages/cef4delphi_lazarus.pas +++ b/packages/cef4delphi_lazarus.pas @@ -50,7 +50,7 @@ uses uCEFUrlRequestClientComponent, uCEFOSRIMEHandler, uCEFCookieAccessFilter, uCEFResourceReadCallback, uCEFResourceRequestHandler, uCEFResourceSkipCallback, uCEFSentinel, uCEFApplicationCore, - LazarusPackageIntf; + uCEFOAuth2Helper, LazarusPackageIntf; implementation diff --git a/source/uCEFApplicationCore.pas b/source/uCEFApplicationCore.pas index e4a5b3ad..e1ca77ad 100644 --- a/source/uCEFApplicationCore.pas +++ b/source/uCEFApplicationCore.pas @@ -62,13 +62,13 @@ uses const CEF_SUPPORTED_VERSION_MAJOR = 79; CEF_SUPPORTED_VERSION_MINOR = 1; - CEF_SUPPORTED_VERSION_RELEASE = 3; + CEF_SUPPORTED_VERSION_RELEASE = 10; CEF_SUPPORTED_VERSION_BUILD = 0; CEF_CHROMEELF_VERSION_MAJOR = 79; CEF_CHROMEELF_VERSION_MINOR = 0; CEF_CHROMEELF_VERSION_RELEASE = 3945; - CEF_CHROMEELF_VERSION_BUILD = 88; + CEF_CHROMEELF_VERSION_BUILD = 117; {$IFDEF MSWINDOWS} LIBCEF_DLL = 'libcef.dll'; diff --git a/source/uCEFMiscFunctions.pas b/source/uCEFMiscFunctions.pas index 7e64084c..e42f889e 100644 --- a/source/uCEFMiscFunctions.pas +++ b/source/uCEFMiscFunctions.pas @@ -61,6 +61,22 @@ uses const Kernel32DLL = 'kernel32.dll'; SHLWAPIDLL = 'shlwapi.dll'; + NTDLL = 'ntdll.dll'; + +type + TOSVersionInfoEx = record + dwOSVersionInfoSize: DWORD; + dwMajorVersion: DWORD; + dwMinorVersion: DWORD; + dwBuildNumber: DWORD; + dwPlatformId: DWORD; + szCSDVersion: array[0..127] of WideChar; + wServicePackMajor: WORD; + wServicePackMinor: WORD; + wSuiteMask: WORD; + wProductType: BYTE; + wReserved:BYTE; + end; function CefColorGetA(color: TCefColor): Byte; function CefColorGetR(color: TCefColor): byte; @@ -135,6 +151,7 @@ function PathIsUNCAnsi(pszPath: LPCSTR): BOOL; stdcall; external SHLWAPIDLL name function PathIsUNCUnicode(pszPath: LPCWSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsUNCW'; function PathIsURLAnsi(pszPath: LPCSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLA'; function PathIsURLUnicode(pszPath: LPCWSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLW'; +function RtlGetVersion(var lpVersionInformation : TOSVersionInfoEx): LongInt; stdcall; external NTDLL; {$IFNDEF DELPHI12_UP} const @@ -232,6 +249,9 @@ function GetCefKeyboardModifiers(aWparam : WPARAM; aLparam : LPARAM) : TCefEvent procedure DropEffectToDragOperation(aEffect : Longint; var aAllowedOps : TCefDragOperations); procedure DragOperationToDropEffect(const aDragOperations : TCefDragOperations; var aEffect: Longint); + +function GetWindowsMajorMinorVersion(var wMajorVersion, wMinorVersion : DWORD) : boolean; +function GetDefaultCEFUserAgent : string; {$ENDIF} function DeviceToLogical(aValue : integer; const aDeviceScaleFactor : double) : integer; overload; @@ -1996,6 +2016,54 @@ begin if ((aDragOperations and DRAG_OPERATION_LINK) <> 0) then aEffect := aEffect or DROPEFFECT_LINK; if ((aDragOperations and DRAG_OPERATION_MOVE) <> 0) then aEffect := aEffect or DROPEFFECT_MOVE; end; + +function GetWindowsMajorMinorVersion(var wMajorVersion, wMinorVersion : DWORD) : boolean; +var + TempInfo : TOSVersionInfoEx; +begin + Result := False; + wMajorVersion := 0; + wMinorVersion := 0; + + ZeroMemory(@TempInfo, SizeOf(TOSVersionInfoEx)); + + if (RtlGetVersion(TempInfo) = 0) then + begin + Result := True; + wMajorVersion := TempInfo.dwMajorVersion; + wMinorVersion := TempInfo.dwMinorVersion; + end; +end; + +function GetDefaultCEFUserAgent : string; +var + TempOS, TempChromiumVersion : string; + TempMajorVer, TempMinorVer : DWORD; + Temp64bit : BOOL; +begin + if GetWindowsMajorMinorVersion(TempMajorVer, TempMinorVer) and + (TempMajorVer >= 4) then + TempOS := 'Windows NT' + else + TempOS := 'Windows'; + + TempOS := TempOS + ' ' + inttostr(TempMajorVer) + '.' + inttostr(TempMinorVer); + + if ProcessUnderWow64(GetCurrentProcess(), Temp64bit) and Temp64bit then + TempOS := TempOS + '; WOW64'; + + if (GlobalCEFApp <> nil) then + TempChromiumVersion := GlobalCEFApp.ChromeVersion + else + TempChromiumVersion := inttostr(CEF_CHROMEELF_VERSION_MAJOR) + '.' + + inttostr(CEF_CHROMEELF_VERSION_MINOR) + '.' + + inttostr(CEF_CHROMEELF_VERSION_RELEASE) + '.' + + inttostr(CEF_CHROMEELF_VERSION_BUILD); + + Result := 'Mozilla/5.0' + ' (' + TempOS + ') ' + + 'AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome/' + TempChromiumVersion + ' Safari/537.36'; +end; {$ENDIF} function DeviceToLogical(aValue : integer; const aDeviceScaleFactor : double) : integer; diff --git a/source/uCEFOAuth2Helper.pas b/source/uCEFOAuth2Helper.pas new file mode 100644 index 00000000..69dbc2f3 --- /dev/null +++ b/source/uCEFOAuth2Helper.pas @@ -0,0 +1,515 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2020 Salvador Diaz Fau. All rights reserved. +// +// ************************************************************************ +// ************ vvvv Original license and comments below vvvv ************* +// ************************************************************************ +(* + * Delphi Chromium Embedded 3 + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Unit owner : Henri Gourvest + * Web site : http://www.progdigy.com + * Repository : http://code.google.com/p/delphichromiumembedded/ + * Group : http://groups.google.com/group/delphichromiumembedded + * + * Embarcadero Technologies, Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + *) + +unit uCEFOAuth2Helper; + +{$I cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + {$IFDEF MSWINDOWS}WinApi.Windows,{$ENDIF}System.Classes, System.UITypes, System.SysUtils, + {$ELSE} + {$IFDEF MSWINDOWS}Windows,{$ENDIF} Classes, {$IFDEF FPC}dynlibs,{$ENDIF}SysUtils, + {$ENDIF} + uCEFInterfaces, uCEFTypes; + +// REFERENCES : +// ============ +// https://tools.ietf.org/html/rfc6749 +// https://tools.ietf.org/html/rfc6750 +// https://tools.ietf.org/html/rfc8252 +// https://tools.ietf.org/html/rfc6819 +// https://tools.ietf.org/html/rfc7636 +// https://tools.ietf.org/html/draft-ietf-oauth-native-apps-12 +// https://tools.ietf.org/html/draft-ietf-oauth-security-topics-13 +// https://developers.google.com/identity/protocols/OAuth2 +// https://developers.google.com/identity/protocols/OAuth2InstalledApp +// https://developers.google.com/identity/protocols/googlescopes +// https://developers.google.com/identity/protocols/OpenIDConnect +// https://aaronparecki.com/oauth-2-simplified/ +// https://example-app.com/pkce + +const + DEFAULT_REDIRECT_IPV4_HOST = '127.0.0.1'; + DEFAULT_REDIRECT_IPV6_HOST = '[::1]'; + DEFAULT_REDIRECT_PORT = 50000; + + GOOGLE_DISCOVERY_DOCUMENT = 'https://accounts.google.com/.well-known/openid-configuration'; + +type + TOAuthChallengeMethod = (cmPlain, cmSHA256); + + TCEFOAuth2Helper = class + protected + FRedirectHost : ustring; + FRedirectPort : integer; + FAuthEndpoint : ustring; + FTokenEndpoint : ustring; + FClientID : ustring; + FClientSecret : ustring; + FAuthCode : ustring; + FError : ustring; + FErrorDescription : ustring; + FCodeVerifier : ustring; + FCodeChallenge : ustring; + FScope : ustring; + FAccessToken : ustring; + FIDToken : ustring; + FState : ustring; + FIncState : ustring; + FRefreshToken : ustring; + FTokenExpiry : integer; + FTokenType : ustring; + FLoginHint : ustring; + FChallengeMethod : TOAuthChallengeMethod; + + function GetRedirectURI : ustring; virtual; + function GetAuthCodeURI : ustring; virtual; + function GetRefreshParams : ustring; virtual; + function GetTokeExchangeParams : ustring; virtual; + function GetValidState : boolean; virtual; + + procedure GenerateRandomCodeChallenge; virtual; + procedure GenerateRandomState; virtual; + function GenerateRandomString(aLength : cardinal) : ustring; + procedure ParseQueryPair(const aPair : ustring); + function ReadJSONString(const aDictionary : ICefDictionaryValue; const aKey : ustring) : ustring; + function ReadJSONInteger(const aDictionary : ICefDictionaryValue; const aKey : ustring) : integer; + function CalculateSHA256Hash(const aString : ustring) : TCefCustomByteArray; + + public + constructor Create; + procedure Initialize; virtual; + function ParseTokenExchangeResponse(const aResponse : ustring) : boolean; virtual; + function ParseRefreshTokenResponse(const aResponse : ustring) : boolean; virtual; + function ParseCodeRequestResponse(const aURL : ustring) : boolean; virtual; + + property AuthEndpoint : ustring read FAuthEndpoint write FAuthEndpoint; + property TokenEndpoint : ustring read FTokenEndpoint write FTokenEndpoint; + + property ClientID : ustring read FClientID write FClientID; + property ClientSecret : ustring read FClientSecret write FClientSecret; + + property RedirectHost : ustring read FRedirectHost write FRedirectHost; + property RedirectPort : integer read FRedirectPort write FRedirectPort; + + property ChallengeMethod : TOAuthChallengeMethod read FChallengeMethod write FChallengeMethod; + property Scope : ustring read FScope write FScope; + + property Error : ustring read FError; + property ErrorDescription : ustring read FErrorDescription; + + property AccessToken : ustring read FAccessToken; + property IDToken : ustring read FIDToken; + property RefreshToken : ustring read FRefreshToken; + property TokenExpiry : integer read FTokenExpiry; + property TokenType : ustring read FTokenType; + + property CodeVerifier : ustring read FCodeVerifier; + property CodeChallenge : ustring read FCodeChallenge; + + property RedirectURI : ustring read GetRedirectURI; + property AuthCodeURI : ustring read GetAuthCodeURI; + property TokeExchangeParams : ustring read GetTokeExchangeParams; + property RefreshParams : ustring read GetRefreshParams; + property ValidState : boolean read GetValidState; + end; + +implementation + +uses + {$IFDEF DELPHI22_UP}System.Hash,{$ENDIF} + {$IFDEF FPC}DCPSha256,{$ENDIF} + uCEFMiscFunctions; + +constructor TCEFOAuth2Helper.Create; +begin + inherited Create; + + Initialize; +end; + +procedure TCEFOAuth2Helper.Initialize; +begin + FRedirectHost := DEFAULT_REDIRECT_IPV4_HOST; + FRedirectPort := DEFAULT_REDIRECT_PORT; // This should be a random unused port + FAuthEndpoint := 'https://accounts.google.com/o/oauth2/v2/auth'; // obtained from GOOGLE_DISCOVERY_DOCUMENT + FTokenEndpoint := 'https://oauth2.googleapis.com/token'; // obtained from GOOGLE_DISCOVERY_DOCUMENT + FClientID := ''; + FClientSecret := ''; + FAuthCode := ''; + FError := ''; + FErrorDescription := ''; + FCodeVerifier := ''; + FCodeChallenge := ''; + FScope := 'openid'; + FAccessToken := ''; + FIDToken := ''; + FState := ''; + FIncState := ''; + FRefreshToken := ''; + FTokenExpiry := 0; + FTokenType := ''; + FLoginHint := ''; + FChallengeMethod := cmPlain; +end; + +function TCEFOAuth2Helper.GetRedirectURI : ustring; +begin + Result := 'http://' + FRedirectHost + ':' + inttostr(FRedirectPort); +end; + +function TCEFOAuth2Helper.GetAuthCodeURI : ustring; +begin + GenerateRandomCodeChallenge; + GenerateRandomState; + + Result := FAuthEndpoint + + '?response_type=code' + + '&client_id=' + CefUriEncode(FClientID, True) + + '&redirect_uri=' + CefUriEncode(RedirectURI, True) + + '&scope=' + CefUriEncode(FScope, True) + + '&state=' + FState + + '&code_challenge=' + CefUriEncode(FCodeChallenge, True); + + if (ChallengeMethod = cmPlain) then + Result := Result + '&code_challenge_method=plain' + else + Result := Result + '&code_challenge_method=S256'; + + if (length(FLoginHint) > 0) then + Result := Result + '&login_hint=' + CefUriEncode(FLoginHint, True); +end; + +function TCEFOAuth2Helper.GetTokeExchangeParams : ustring; +begin + Result := 'grant_type=authorization_code' + + '&code=' + FAuthCode + + '&client_id=' + CefUriEncode(FClientID, True) + + '&client_secret=' + CefUriEncode(FClientSecret, True) + + '&redirect_uri=' + CefUriEncode(RedirectURI, True) + + '&code_verifier=' + CefUriEncode(FCodeVerifier, True); +end; + +function TCEFOAuth2Helper.GetRefreshParams : ustring; +begin + Result := 'grant_type=refresh_token' + + '&client_id=' + CefUriEncode(FClientID, True) + + '&client_secret=' + CefUriEncode(FClientSecret, True) + + '&refresh_token=' + CefUriEncode(FRefreshToken, True); +end; + +function TCEFOAuth2Helper.GetValidState : boolean; +begin + Result := (CompareStr(FState, FIncState) = 0); +end; + +function TCEFOAuth2Helper.GenerateRandomString(aLength : cardinal) : ustring; +const + UnreservedCharValuesLen = 66; + UnreservedCharValues : array [0..pred(UnreservedCharValuesLen)] of + char = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '.', '_', '~'); +var + i : cardinal; +begin + Result := ''; + i := 0; + + Randomize; + + while (i < aLength) do + begin + Result := Result + UnreservedCharValues[Random(UnreservedCharValuesLen)]; + inc(i); + end; +end; + +procedure TCEFOAuth2Helper.GenerateRandomCodeChallenge; +var + TempHash : TCefCustomByteArray; +begin + // The "code_verifier" can have a minimum length of 43 characters + // and a maximum length of 128 characters. + FCodeVerifier := GenerateRandomString(64); + + case ChallengeMethod of + cmPlain : FCodeChallenge := FCodeVerifier; + + cmSHA256 : + try + TempHash := CalculateSHA256Hash(FCodeVerifier); + + if (length(TempHash) > 0) then + begin + FCodeChallenge := CefBase64Encode(@TempHash[0], length(TempHash)); + + // Converts base64 to base64url. + FCodeChallenge := StringReplace(FCodeChallenge, '+', '-', [rfReplaceAll]); + FCodeChallenge := StringReplace(FCodeChallenge, '/', '_', [rfReplaceAll]); + + // Strips padding. + while (length(FCodeChallenge) > 0) and (FCodeChallenge[length(FCodeChallenge)] = '=') do + FCodeChallenge := copy(FCodeChallenge, 1, pred(length(FCodeChallenge))); + end + else + FCodeChallenge := ''; + finally + if (TempHash <> nil) then + begin + Finalize(TempHash); + TempHash := nil; + end; + end; + end; +end; + +{$IFDEF FPC} +function TCEFOAuth2Helper.CalculateSHA256Hash(const aString : ustring) : TCefCustomByteArray; +var + TempSHA256 : TDCP_sha256; + TempString : AnsiString; +begin + Result := nil; + try + TempSHA256 := TDCP_sha256.Create(nil); + TempSHA256.Burn; + TempSHA256.Init; + TempString := AnsiString(aString); + TempSHA256.Update(TempString[1], length(TempString)); + SetLength(Result, 32); + TempSHA256.Final(Result[0]); + finally + FreeAndNil(TempSHA256); + end; +end; +{$ELSE} +{$IFDEF DELPHI22_UP} +function TCEFOAuth2Helper.CalculateSHA256Hash(const aString : ustring) : TCefCustomByteArray; +var + TempBytes : TBytes; +begin + TempBytes := THashSHA2.GetHashBytes(FCodeVerifier); + SetLength(Result, length(TempBytes)); + Move(TempBytes[0], Result[0], length(TempBytes)); +end; +{$ELSE} +// TO-DO: Calculate SHA256 hash in older Delphi versions +function TCEFOAuth2Helper.CalculateSHA256Hash(const aString : ustring) : TCefCustomByteArray; +begin + Result := nil; +end; +{$ENDIF} +{$ENDIF} + +procedure TCEFOAuth2Helper.GenerateRandomState; +begin + // The "state" should be a string of 30 or so characters constructed + // using a high-quality random-number generator. + + Randomize; + + FState := IntToHex(Random(high(integer)), 8) + + IntToHex(Random(high(integer)), 8) + + IntToHex(Random(high(integer)), 8) + + IntToHex(Random(high(integer)), 8); +end; + +function TCEFOAuth2Helper.ReadJSONString(const aDictionary : ICefDictionaryValue; const aKey : ustring) : ustring; +var + TempValue : ICefValue; +begin + Result := ''; + + if (aDictionary <> nil) then + begin + TempValue := aDictionary.GetValue(aKey); + if (TempValue <> nil) and (TempValue.GetType = VTYPE_STRING) then Result := TempValue.GetString; + end; +end; + +function TCEFOAuth2Helper.ReadJSONInteger(const aDictionary : ICefDictionaryValue; const aKey : ustring) : integer; +var + TempValue : ICefValue; +begin + Result := 0; + + if (aDictionary <> nil) then + begin + TempValue := aDictionary.GetValue(aKey); + if (TempValue <> nil) and (TempValue.GetType = VTYPE_INT) then Result := TempValue.GetInt; + end; +end; + +function TCEFOAuth2Helper.ParseTokenExchangeResponse(const aResponse : ustring) : boolean; +var + TempRoot : ICefValue; + TempDictionary : ICefDictionaryValue; +begin + Result := False; + + try + if (length(aResponse) > 0) then + begin + TempRoot := CefParseJson(aResponse, JSON_PARSER_RFC); + + if (TempRoot <> nil) and (TempRoot.GetType = VTYPE_DICTIONARY) then + begin + TempDictionary := TempRoot.GetDictionary; + FError := ReadJSONString(TempDictionary, 'error'); + + if (length(FError) > 0) then + FErrorDescription := ReadJSONString(TempDictionary, 'error_description') + else + begin + FAccessToken := ReadJSONString(TempDictionary, 'access_token'); + + if (length(FAccessToken) > 0) then + begin + FIDToken := ReadJSONString(TempDictionary, 'id_token'); + FScope := ReadJSONString(TempDictionary, 'scope'); + FTokenType := ReadJSONString(TempDictionary, 'token_type'); + FRefreshToken := ReadJSONString(TempDictionary, 'refresh_token'); + FTokenExpiry := ReadJSONInteger(TempDictionary, 'expires_in'); + Result := True; + end; + end; + end; + end; + except + on e : exception do + if CustomExceptionHandler('TCEFOAuth2Helper.ParseTokenExchangeResponse', e) then raise; + end; +end; + +function TCEFOAuth2Helper.ParseRefreshTokenResponse(const aResponse : ustring) : boolean; +var + TempRoot : ICefValue; + TempDictionary : ICefDictionaryValue; +begin + Result := False; + + try + if (length(aResponse) > 0) then + begin + TempRoot := CefParseJson(aResponse, JSON_PARSER_RFC); + + if (TempRoot <> nil) and (TempRoot.GetType = VTYPE_DICTIONARY) then + begin + TempDictionary := TempRoot.GetDictionary; + FError := ReadJSONString(TempDictionary, 'error'); + + if (length(FError) > 0) then + FErrorDescription := ReadJSONString(TempDictionary, 'error_description') + else + begin + FAccessToken := ReadJSONString(TempDictionary, 'access_token'); + + if (length(FAccessToken) > 0) then + begin + FTokenType := ReadJSONString(TempDictionary, 'token_type'); + FTokenExpiry := ReadJSONInteger(TempDictionary, 'expires_in'); + Result := True; + end; + end; + end; + end; + except + on e : exception do + if CustomExceptionHandler('TCEFOAuth2Helper.ParseRefreshTokenResponse', e) then raise; + end; +end; + +procedure TCEFOAuth2Helper.ParseQueryPair(const aPair : ustring); +var + TempKey : ustring; + TempValue : ustring; + i : integer; +begin + i := pos('=', aPair); + + if (i > 0) then + begin + TempKey := copy(aPair, 1, pred(i)); + TempValue := copy(aPair, succ(i), length(aPair)); + + if (CompareStr(TempKey, 'code') = 0) then FAuthCode := TempValue + else if (CompareStr(TempKey, 'state') = 0) then FIncState := TempValue + else if (CompareStr(TempKey, 'error') = 0) then FError := TempValue + else if (CompareStr(TempKey, 'error_description') = 0) then FErrorDescription := TempValue; + end; +end; + +function TCEFOAuth2Helper.ParseCodeRequestResponse(const aURL : ustring) : boolean; +var + TempParts : TUrlParts; + TempQuery : ustring; + i : integer; +begin + Result := False; + + if (length(aURL) > 0) then + begin + CefParseUrl(aURL, TempParts); + + TempQuery := TempParts.query; + + if (length(TempQuery) > 0) then + begin + i := pos('&', TempQuery); + + while (i > 0) do + begin + ParseQueryPair(copy(TempQuery, 1, pred(i))); + TempQuery := copy(TempQuery, succ(i), length(TempQuery)); + i := pos('&', TempQuery); + end; + + ParseQueryPair(TempQuery); + + Result := ValidState and (length(FAuthCode) > 0); + end; + end; +end; + +end. diff --git a/source/uCEFTypes.pas b/source/uCEFTypes.pas index 80738a8b..29e51c74 100644 --- a/source/uCEFTypes.pas +++ b/source/uCEFTypes.pas @@ -308,6 +308,8 @@ type {$ENDIF} {$ENDIF} + TCefCustomByteArray = array of byte; // Needed only for backwards compatibility with old Delphi versions + {$IFDEF MSWINDOWS} TMyMemoryStatusEx = record dwLength : DWORD; diff --git a/update_CEF4Delphi.json b/update_CEF4Delphi.json index 8f07c6fb..2eee6c63 100644 --- a/update_CEF4Delphi.json +++ b/update_CEF4Delphi.json @@ -2,9 +2,9 @@ "UpdateLazPackages" : [ { "ForceNotify" : true, - "InternalVersion" : 80, + "InternalVersion" : 81, "Name" : "cef4delphi_lazarus.lpk", - "Version" : "79.1.3.0" + "Version" : "79.1.10.0" } ], "UpdatePackageData" : {