1
0
mirror of https://github.com/salvadordf/CEF4Delphi.git synced 2025-06-02 21:57:37 +02:00

Update to CEF 79.1.10

- Added TCEFOAuth2Helper
- Added OAuth2Tester demo
- Added GetDefaultCEFUserAgent function to the uCEFMiscFunctions unit.
This commit is contained in:
Salvador Díaz Fau 2020-01-13 15:39:44 +01:00
parent c14be37648
commit e93fd29623
28 changed files with 5866 additions and 23 deletions

View File

@ -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 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 : 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) * [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.3%2Bga5342ed%2Bchromium-79.0.3945.88_windows64.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. 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.

View File

@ -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

View File

@ -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 <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;
{$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.

View File

@ -0,0 +1,977 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{FF0090FB-12B4-40DE-86E7-6E71DD3624CA}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>OAuth2Tester.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<SanitizedProjectName>OAuth2Tester</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>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)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>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)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<DCC_ExeOutput>..\..\..\bin</DCC_ExeOutput>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uOAuth2TesterFrm.pas">
<Form>OAuth2TesterFrm</Form>
</DCCReference>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">OAuth2Tester.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclIPIndyImpl260.bpl">IP Abstraction Indy Implementation Design Time</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="..\..\..\bin\OAuth2Tester.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>OAuth2Tester.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements">
<Platform Name="OSX32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList">
<Platform Name="OSX32">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@ -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}

View File

@ -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

View File

@ -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 <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;
{$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 := '<html><head><title>User authentication successfull</title></head>' +
'<body><p>User authentication successfull.</p><p>You can close this window now.</p></body></html>';
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.

View File

@ -47,8 +47,7 @@ uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, ComCtrls, StdCtrls, Controls, Forms, Dialogs, ComCtrls, StdCtrls,
{$ENDIF} {$ENDIF}
uCEFInterfaces, uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest, uCEFInterfaces, uCEFUrlRequestClientComponent, uCEFRequest, uCEFUrlRequest;
uCEFSentinel;
const const
URLREQUEST_SUCCESS = WM_APP + $101; 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. // 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 // 2- The next time TCEFUrlRequestClientComponent.OnDownloadProgress is executed we call request.Cancel, which triggers the
// TCEFUrlRequestClientComponent.OnRequestComplete event. // TCEFUrlRequestClientComponent.OnRequestComplete event.
// 3- in the TCEFUrlRequestClientComponent.OnRequestComplete event we call TCEFSentinel.Start, which will trigger TCEFSentinel.OnClose when the renderer processes are closed. // 3- The TCEFUrlRequestClientComponent.OnRequestComplete event sets FCanClose := True and sends WM_CLOSE to the form.
// 4- TCEFSentinel.OnClose sets FCanClose := True and sends WM_CLOSE to the form.
uses uses
ShellApi, ShellApi,

View File

@ -0,0 +1,2 @@
rmdir /S /Q lib
rmdir /S /Q backup

View File

@ -0,0 +1,977 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{FF0090FB-12B4-40DE-86E7-6E71DD3624CA}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>OAuth2Tester.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<SanitizedProjectName>OAuth2Tester</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>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)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>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)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<DCC_ExeOutput>..\..\..\bin</DCC_ExeOutput>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uOAuth2TesterFrm.pas">
<Form>OAuth2TesterFrm</Form>
</DCCReference>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">OAuth2Tester.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclIPIndyImpl260.bpl">IP Abstraction Indy Implementation Design Time</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="..\..\..\bin\OAuth2Tester.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>OAuth2Tester.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements">
<Platform Name="OSX32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList">
<Platform Name="OSX32">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasUsesSectionForAllUnits Value="False"/>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="OAuth2Tester"/>
<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>

View File

@ -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.

View File

@ -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>

View File

@ -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}

View File

@ -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

View File

@ -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</title></head>' +
'<body><p>User authentication successfull.</p><p>You can close this window now.</p></body></html>';
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.

View File

@ -174,7 +174,8 @@ contains
uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas',
uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas',
uCEFSentinel in '..\source\uCEFSentinel.pas', uCEFSentinel in '..\source\uCEFSentinel.pas',
uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; uCEFApplicationCore in '..\source\uCEFApplicationCore.pas',
uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas';
end. end.

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<ProjectGuid>{2F51F1BD-0529-4B4A-BFD2-86FE96910A62}</ProjectGuid> <ProjectGuid>{2F51F1BD-0529-4B4A-BFD2-86FE96910A62}</ProjectGuid>
<MainSource>CEF4Delphi.dpk</MainSource> <MainSource>CEF4Delphi.dpk</MainSource>
<ProjectVersion>18.5</ProjectVersion> <ProjectVersion>18.8</ProjectVersion>
<FrameworkType>VCL</FrameworkType> <FrameworkType>VCL</FrameworkType>
<Base>True</Base> <Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config> <Config Condition="'$(Config)'==''">Debug</Config>
@ -269,6 +269,7 @@
<DCCReference Include="..\source\uCEFResourceReadCallback.pas"/> <DCCReference Include="..\source\uCEFResourceReadCallback.pas"/>
<DCCReference Include="..\source\uCEFSentinel.pas"/> <DCCReference Include="..\source\uCEFSentinel.pas"/>
<DCCReference Include="..\source\uCEFApplicationCore.pas"/> <DCCReference Include="..\source\uCEFApplicationCore.pas"/>
<DCCReference Include="..\source\uCEFOAuth2Helper.pas"/>
<BuildConfiguration Include="Base"> <BuildConfiguration Include="Base">
<Key>Base</Key> <Key>Base</Key>
</BuildConfiguration> </BuildConfiguration>
@ -324,12 +325,20 @@
<RemoteDir>classes</RemoteDir> <RemoteDir>classes</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidFileProvider"> <DeployClass Name="AndroidFileProvider">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\xml</RemoteDir> <RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidGDBServer"> <DeployClass Name="AndroidGDBServer">
<Platform Name="Android"> <Platform Name="Android">
@ -342,96 +351,242 @@
<RemoteDir>library\lib\armeabi</RemoteDir> <RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile"> <DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir> <RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidServiceOutput"> <DeployClass Name="AndroidServiceOutput">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir> <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidSplashImageDef"> <DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir> <RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidSplashStyles"> <DeployClass Name="AndroidSplashStyles">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\values</RemoteDir> <RemoteDir>res\values</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="AndroidSplashStylesV21"> <DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir> <RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_DefaultAppIcon"> <DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir> <RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_LauncherIcon144"> <DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir> <RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_LauncherIcon36"> <DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir> <RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_LauncherIcon48"> <DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir> <RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_LauncherIcon72"> <DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir> <RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_LauncherIcon96"> <DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir> <RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_SplashImage426"> <DeployClass Name="Android_SplashImage426">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir> <RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_SplashImage470"> <DeployClass Name="Android_SplashImage470">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir> <RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_SplashImage640"> <DeployClass Name="Android_SplashImage640">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir> <RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="Android_SplashImage960"> <DeployClass Name="Android_SplashImage960">
<Platform Name="Android"> <Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir> <RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="DebugSymbols"> <DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator"> <Platform Name="iOSSimulator">
@ -501,6 +656,9 @@
<Platform Name="Android"> <Platform Name="Android">
<Operation>0</Operation> <Operation>0</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>0</Operation> <Operation>0</Operation>
</Platform> </Platform>
@ -531,6 +689,17 @@
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536"> <DeployClass Name="iPad_Launch1536">
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>1</Operation> <Operation>1</Operation>
@ -542,6 +711,39 @@
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048"> <DeployClass Name="iPad_Launch2048">
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>1</Operation> <Operation>1</Operation>
@ -553,6 +755,61 @@
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768"> <DeployClass Name="iPad_Launch768">
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>1</Operation> <Operation>1</Operation>
@ -564,6 +821,116 @@
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320"> <DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>1</Operation> <Operation>1</Operation>
@ -597,10 +964,35 @@
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest"> <DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android"> <Platform Name="Android">
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass> </DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug"> <DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
@ -644,6 +1036,10 @@
<RemoteDir>library\lib\armeabi-v7a</RemoteDir> <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32"> <Platform Name="iOSDevice32">
<Operation>1</Operation> <Operation>1</Operation>
</Platform> </Platform>
@ -666,6 +1062,12 @@
<Operation>0</Operation> <Operation>0</Operation>
</Platform> </Platform>
</DeployClass> </DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest"> <DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32"> <Platform Name="Win32">
<Operation>1</Operation> <Operation>1</Operation>
@ -703,6 +1105,7 @@
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/> <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment> </Deployment>
<Platforms> <Platforms>
<Platform value="Win32">True</Platform> <Platform value="Win32">True</Platform>

View File

@ -171,6 +171,7 @@ contains
uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas',
uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas',
uCEFSentinel in '..\source\uCEFSentinel.pas', uCEFSentinel in '..\source\uCEFSentinel.pas',
uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; uCEFApplicationCore in '..\source\uCEFApplicationCore.pas',
uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas';
end. end.

View File

@ -22,7 +22,7 @@ package CEF4Delphi_FMX;
{$VARSTRINGCHECKS ON} {$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF} {$WRITEABLECONST OFF}
{$MINENUMSIZE 1} {$MINENUMSIZE 1}
{$IMAGEBASE $54C00000} {$IMAGEBASE $400000}
{$DEFINE $(FrameworkType)} {$DEFINE $(FrameworkType)}
{$ENDIF IMPLICITBUILDING} {$ENDIF IMPLICITBUILDING}
{$DESCRIPTION 'CEF4Delphi'} {$DESCRIPTION 'CEF4Delphi'}
@ -179,7 +179,8 @@ contains
uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas', uCEFResourceSkipCallback in '..\source\uCEFResourceSkipCallback.pas',
uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas', uCEFResourceReadCallback in '..\source\uCEFResourceReadCallback.pas',
uCEFSentinel in '..\source\uCEFSentinel.pas', uCEFSentinel in '..\source\uCEFSentinel.pas',
uCEFApplicationCore in '..\source\uCEFApplicationCore.pas'; uCEFApplicationCore in '..\source\uCEFApplicationCore.pas',
uCEFOAuth2Helper in '..\source\uCEFOAuth2Helper.pas';
end. end.

View File

@ -295,6 +295,7 @@
<DCCReference Include="..\source\uCEFResourceReadCallback.pas"/> <DCCReference Include="..\source\uCEFResourceReadCallback.pas"/>
<DCCReference Include="..\source\uCEFSentinel.pas"/> <DCCReference Include="..\source\uCEFSentinel.pas"/>
<DCCReference Include="..\source\uCEFApplicationCore.pas"/> <DCCReference Include="..\source\uCEFApplicationCore.pas"/>
<DCCReference Include="..\source\uCEFOAuth2Helper.pas"/>
<BuildConfiguration Include="Base"> <BuildConfiguration Include="Base">
<Key>Base</Key> <Key>Base</Key>
</BuildConfiguration> </BuildConfiguration>

View File

@ -21,8 +21,8 @@
</CompilerOptions> </CompilerOptions>
<Description Value="CEF4Delphi is an open source project created by Salvador Díaz Fau to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC."/> <Description Value="CEF4Delphi is an open source project created by Salvador Díaz Fau to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC."/>
<License Value="MPL 1.1"/> <License Value="MPL 1.1"/>
<Version Major="79" Minor="1" Release="3"/> <Version Major="79" Minor="1" Release="10"/>
<Files Count="146"> <Files Count="147">
<Item1> <Item1>
<Filename Value="..\source\uCEFAccessibilityHandler.pas"/> <Filename Value="..\source\uCEFAccessibilityHandler.pas"/>
<UnitName Value="uCEFAccessibilityHandler"/> <UnitName Value="uCEFAccessibilityHandler"/>
@ -616,17 +616,24 @@
<Filename Value="..\source\uCEFApplicationCore.pas"/> <Filename Value="..\source\uCEFApplicationCore.pas"/>
<UnitName Value="uCEFApplicationCore"/> <UnitName Value="uCEFApplicationCore"/>
</Item146> </Item146>
<Item147>
<Filename Value="..\source\uCEFOAuth2Helper.pas"/>
<UnitName Value="uCEFOAuth2Helper"/>
</Item147>
</Files> </Files>
<RequiredPkgs Count="3"> <RequiredPkgs Count="4">
<Item1> <Item1>
<PackageName Value="LCL"/> <PackageName Value="dcpcrypt"/>
</Item1> </Item1>
<Item2> <Item2>
<PackageName Value="LCLBase"/> <PackageName Value="LCL"/>
</Item2> </Item2>
<Item3> <Item3>
<PackageName Value="FCL"/> <PackageName Value="LCLBase"/>
</Item3> </Item3>
<Item4>
<PackageName Value="FCL"/>
</Item4>
</RequiredPkgs> </RequiredPkgs>
<UsageOptions> <UsageOptions>
<UnitPath Value="$(PkgOutDir)"/> <UnitPath Value="$(PkgOutDir)"/>

View File

@ -50,7 +50,7 @@ uses
uCEFUrlRequestClientComponent, uCEFOSRIMEHandler, uCEFCookieAccessFilter, uCEFUrlRequestClientComponent, uCEFOSRIMEHandler, uCEFCookieAccessFilter,
uCEFResourceReadCallback, uCEFResourceRequestHandler, uCEFResourceReadCallback, uCEFResourceRequestHandler,
uCEFResourceSkipCallback, uCEFSentinel, uCEFApplicationCore, uCEFResourceSkipCallback, uCEFSentinel, uCEFApplicationCore,
LazarusPackageIntf; uCEFOAuth2Helper, LazarusPackageIntf;
implementation implementation

View File

@ -62,13 +62,13 @@ uses
const const
CEF_SUPPORTED_VERSION_MAJOR = 79; CEF_SUPPORTED_VERSION_MAJOR = 79;
CEF_SUPPORTED_VERSION_MINOR = 1; CEF_SUPPORTED_VERSION_MINOR = 1;
CEF_SUPPORTED_VERSION_RELEASE = 3; CEF_SUPPORTED_VERSION_RELEASE = 10;
CEF_SUPPORTED_VERSION_BUILD = 0; CEF_SUPPORTED_VERSION_BUILD = 0;
CEF_CHROMEELF_VERSION_MAJOR = 79; CEF_CHROMEELF_VERSION_MAJOR = 79;
CEF_CHROMEELF_VERSION_MINOR = 0; CEF_CHROMEELF_VERSION_MINOR = 0;
CEF_CHROMEELF_VERSION_RELEASE = 3945; CEF_CHROMEELF_VERSION_RELEASE = 3945;
CEF_CHROMEELF_VERSION_BUILD = 88; CEF_CHROMEELF_VERSION_BUILD = 117;
{$IFDEF MSWINDOWS} {$IFDEF MSWINDOWS}
LIBCEF_DLL = 'libcef.dll'; LIBCEF_DLL = 'libcef.dll';

View File

@ -61,6 +61,22 @@ uses
const const
Kernel32DLL = 'kernel32.dll'; Kernel32DLL = 'kernel32.dll';
SHLWAPIDLL = 'shlwapi.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 CefColorGetA(color: TCefColor): Byte;
function CefColorGetR(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 PathIsUNCUnicode(pszPath: LPCWSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsUNCW';
function PathIsURLAnsi(pszPath: LPCSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLA'; function PathIsURLAnsi(pszPath: LPCSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLA';
function PathIsURLUnicode(pszPath: LPCWSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLW'; function PathIsURLUnicode(pszPath: LPCWSTR): BOOL; stdcall; external SHLWAPIDLL name 'PathIsURLW';
function RtlGetVersion(var lpVersionInformation : TOSVersionInfoEx): LongInt; stdcall; external NTDLL;
{$IFNDEF DELPHI12_UP} {$IFNDEF DELPHI12_UP}
const const
@ -232,6 +249,9 @@ function GetCefKeyboardModifiers(aWparam : WPARAM; aLparam : LPARAM) : TCefEvent
procedure DropEffectToDragOperation(aEffect : Longint; var aAllowedOps : TCefDragOperations); procedure DropEffectToDragOperation(aEffect : Longint; var aAllowedOps : TCefDragOperations);
procedure DragOperationToDropEffect(const aDragOperations : TCefDragOperations; var aEffect: Longint); procedure DragOperationToDropEffect(const aDragOperations : TCefDragOperations; var aEffect: Longint);
function GetWindowsMajorMinorVersion(var wMajorVersion, wMinorVersion : DWORD) : boolean;
function GetDefaultCEFUserAgent : string;
{$ENDIF} {$ENDIF}
function DeviceToLogical(aValue : integer; const aDeviceScaleFactor : double) : integer; overload; 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_LINK) <> 0) then aEffect := aEffect or DROPEFFECT_LINK;
if ((aDragOperations and DRAG_OPERATION_MOVE) <> 0) then aEffect := aEffect or DROPEFFECT_MOVE; if ((aDragOperations and DRAG_OPERATION_MOVE) <> 0) then aEffect := aEffect or DROPEFFECT_MOVE;
end; 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} {$ENDIF}
function DeviceToLogical(aValue : integer; const aDeviceScaleFactor : double) : integer; function DeviceToLogical(aValue : integer; const aDeviceScaleFactor : double) : integer;

515
source/uCEFOAuth2Helper.pas Normal file
View File

@ -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 <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 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.

View File

@ -308,6 +308,8 @@ type
{$ENDIF} {$ENDIF}
{$ENDIF} {$ENDIF}
TCefCustomByteArray = array of byte; // Needed only for backwards compatibility with old Delphi versions
{$IFDEF MSWINDOWS} {$IFDEF MSWINDOWS}
TMyMemoryStatusEx = record TMyMemoryStatusEx = record
dwLength : DWORD; dwLength : DWORD;

View File

@ -2,9 +2,9 @@
"UpdateLazPackages" : [ "UpdateLazPackages" : [
{ {
"ForceNotify" : true, "ForceNotify" : true,
"InternalVersion" : 80, "InternalVersion" : 81,
"Name" : "cef4delphi_lazarus.lpk", "Name" : "cef4delphi_lazarus.lpk",
"Version" : "79.1.3.0" "Version" : "79.1.10.0"
} }
], ],
"UpdatePackageData" : { "UpdatePackageData" : {