浏览代码

Merge remote-tracking branch 'chbwien/main' into chbwien
Did some cleanup during merge.

Martijn Laan 2 年之前
父节点
当前提交
3386bbd2a5

+ 1 - 0
ISHelp/isxclasses.pas

@@ -739,6 +739,7 @@ TDownloadWizardPage = class(TOutputProgressWizardPage)
   property AbortButton: TNewButton; read;
   property AbortedByUser: Boolean; read;
   procedure Add(const Url, BaseName, RequiredSHA256OfFile: String);
+  procedure AddEx(const Url, BaseName, RequiredSHA256OfFile, UserName, Password: String);
   procedure Clear;
   function Download: Int64;
 end;

+ 18 - 3
ISHelp/isxfunc.xml

@@ -1769,12 +1769,14 @@ end;</pre></example>
 <p>If RequiredSHA256OfFile is set it will compare this to the SHA-256 of the downloaded file and raise an exception if the hashes don't match.</p>
 <p>An exception will be raised if there was an error. Otherwise, returns the number of bytes downloaded. Returns 0 if RequiredSHA256OfFile is set and the file was already downloaded.</p>
 <p>Supports HTTPS (but not expired or self-signed certificates) and HTTP. Redirects are automatically followed and proxy settings are automatically used. Safe to use from services.</p>
-<p>For basic authentication use a special URL format like this: http://username:[email protected]/</p>
+<p>For basic authentication use <link topic="isxfunc_SetDownloadCredentials">SetDownloadCredentials</link>.</p>
 <p>Set OnDownloadProgress to a function to be informed of progress, or <tt>nil</tt> otherwise.</p></description>
         <remarks><p>TOnDownloadProgress is defined as:</p>
 <p><tt>TOnDownloadProgress = function(const Url, FileName: string; const Progress, ProgressMax: Int64): Boolean;</tt></p>
 <p>ProgressMax will be 0 if the file size is still unknown. Return True to allow the download to continue, False otherwise.</p></remarks>
-        <seealso><p><link topic="isxfunc_DownloadTemporaryFileSize">DownloadTemporaryFileSize</link><br />
+        <seealso><p><link topic="isxfunc_SetDownloadCredentials">SetDownloadCredentials</link><br />
+<link topic="isxfunc_DownloadTemporaryFileSize">DownloadTemporaryFileSize</link><br />
+<link topic="isxfunc_DownloadTemporaryFileDate">DownloadTemporaryFileDate</link><br />
 <link topic="isxfunc_CreateDownloadPage">CreateDownloadPage</link><br />
 <link topic="isxfunc_ExtractTemporaryFile">ExtractTemporaryFile</link></p></seealso>
         <example><pre>
@@ -1800,11 +1802,24 @@ begin
   end;
 end;</pre>
 <p>See <i>CodeDownloadFiles.iss</i> for another example which uses <link topic="isxfunc_CreateDownloadPage">CreateDownloadPage</link> instead.</p></example>
+      </function>
+      <function>
+        <name>SetDownloadCredentials</name>
+        <prototype>procedure SetDownloadCredentials(const User, Pass: String);</prototype>
+        <description><p>Sets username and password for all following downloads. Set an empty string to delete the previous setting.</p>
+<seealso><p><link topic="isxfunc_DownloadTemporaryFile">DownloadTemporaryFile</link><br/><link topic="isxfunc_DownloadTemporaryFileSize">DownloadTemporaryFileSize</link><br/><link topic="isxfunc_DownloadTemporaryFileDate">DownloadTemporaryFileDate</link></p></seealso></description>
       </function>
       <function>
         <name>DownloadTemporaryFileSize</name>
         <prototype>function DownloadTemporaryFileSize(const Url): Int64;</prototype>
-        <description><p>Returns the size of the file from the specified URL, without downloading the file. If the server does not provide the file size, -1 will be returned.</p>
+        <description><p>Returns the size of the file from the specified URL, without downloading the file. If the server does not provide the size, -1 will be returned.</p>
+<p>An exception will be raised if there was an error.</p>
+<p>See <link topic="isxfunc_DownloadTemporaryFile">DownloadTemporaryFile</link> for other considerations.</p></description>
+      </function>
+      <function>
+        <name>DownloadTemporaryFileDate</name>
+        <prototype>function DownloadTemporaryFileDate(const Url): String;</prototype>
+        <description><p>Returns the last modified date of the file from the specified URL, without downloading the file. If the server does not provide the last modified file date, '' will be returned.</p>
 <p>An exception will be raised if there was an error.</p>
 <p>See <link topic="isxfunc_DownloadTemporaryFile">DownloadTemporaryFile</link> for other considerations.</p></description>
       </function>

+ 102 - 14
Projects/Install.pas

@@ -24,6 +24,8 @@ procedure ExtractTemporaryFile(const BaseName: String);
 function ExtractTemporaryFiles(const Pattern: String): Integer;
 function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String; const OnDownloadProgress: TOnDownloadProgress): Int64;
 function DownloadTemporaryFileSize(const Url: String): Int64;
+function DownloadTemporaryFileDate(const Url: String): String;
+procedure SetDownloadCredentials(const User, Pass: String);
 
 implementation
 
@@ -32,7 +34,8 @@ uses
   InstFunc, InstFnc2, SecurityFunc, Msgs, Main, Logging, Extract, FileClass,
   Compress, SHA1, PathFunc, CmnFunc, CmnFunc2, RedirFunc, Int64Em, MsgIDs,
   Wizard, DebugStruct, DebugClient, VerInfo, ScriptRunner, RegDLL, Helper,
-  ResUpdate, DotNet, TaskbarProgressFunc, NewProgressBar, RestartManager, Net.HTTPClient;
+  ResUpdate, DotNet, TaskbarProgressFunc, NewProgressBar, RestartManager,
+  Net.HTTPClient, Net.URLClient, NetEncoding;
 
 type
   TSetupUninstallLog = class(TUninstallLog)
@@ -43,6 +46,7 @@ type
 var
   CurProgress: Integer64;
   ProgressShiftCount: Cardinal;
+  DownloadUser, DownloadPass: String;
 
 { TSetupUninstallLog }
 
@@ -3501,6 +3505,47 @@ begin
   AHTTPClient.SecureProtocols := [THTTPSecureProtocol.TLS1, THTTPSecureProtocol.TLS11, THTTPSecureProtocol.TLS12];
 end;
 
+function MaskPasswordInUrl(const Url: String): String;
+var
+  Uri: TUri;
+begin
+  Uri := TUri.Create(Url);
+  if Uri.Password <> '' then begin
+    Uri.Password := '***';
+    Result := Uri.ToString;
+  end else
+    Result := URL;
+end;
+
+procedure SetDownloadCredentials(const User, Pass: String);
+begin
+  DownloadUser := User;
+  DownloadPass := Pass;
+end;
+
+function GetCredentialsAndCleanUrl(const Url: String; var User, Pass, CleanUrl: String) : Boolean;
+var
+  Uri: TUri;
+begin
+  Uri := TUri.Create(Url);
+  if DownloadUser = '' then
+    User := TUri.URLDecode(Uri.Username)
+  else
+    User := DownloadUser;
+  if DownloadPass = '' then
+    Pass := TUri.URLDecode(Uri.Password,true)
+  else
+    Pass := DownloadPass;
+  Uri.Username := '';
+  Uri.Password := '';
+  CleanUrl := Uri.ToString;
+  Result := (User <> '') or (Pass <> '');
+  if Result then
+    LogFmt('Download is using basic authentication: %s, ***', [User])
+  else
+    Log('Download is not using basic authentication');
+end;
+
 function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String; const OnDownloadProgress: TOnDownloadProgress): Int64;
 var
   DisableFsRedir: Boolean;
@@ -3514,6 +3559,9 @@ var
   SHA256OfFile: String;
   RetriesLeft: Integer;
   LastError: DWORD;
+  User, Pass, CleanUrl: String;
+  HasCredentials : Boolean;
+  Base64: TBase64Encoding;
 begin
   if Url = '' then
     InternalError('DownloadTemporaryFile: Invalid Url value');
@@ -3522,7 +3570,7 @@ begin
 
   DestFile := AddBackslash(TempInstallDir) + BaseName;
 
-  LogFmt('Downloading temporary file from %s: %s', [Url, DestFile]);
+  LogFmt('Downloading temporary file from %s: %s', [MaskPasswordInURL(Url), DestFile]);
 
   DisableFsRedir := InstallDefaultDisableFsRedir;
 
@@ -3532,7 +3580,7 @@ begin
       Log('  File already downloaded.');
       Result := 0;
       Exit;
-    end;    
+    end;
     SetFileAttributesRedir(DisableFsRedir, DestFile, GetFileAttributesRedir(DisableFsRedir, DestFile) and not FILE_ATTRIBUTE_READONLY);
     DelayDeleteFile(DisableFsRedir, DestFile, 13, 50, 250);
   end else
@@ -3543,11 +3591,15 @@ begin
   TempF := nil;
   TempFileLeftOver := False;
   HandleStream := nil;
+  Base64 := nil;
+
   try
+    HasCredentials := GetCredentialsAndCleanUrl(URL, User, Pass, CleanUrl);
+
     { Setup downloader }
     HTTPDataReceiver := THTTPDataReceiver.Create;
     HTTPDataReceiver.BaseName := BaseName;
-    HTTPDataReceiver.Url := Url;
+    HTTPDataReceiver.Url := CleanUrl;
     HTTPDataReceiver.OnDownloadProgress := OnDownloadProgress;
 
     HTTPClient := THTTPClient.Create; { http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_an_HTTP_Client }
@@ -3569,7 +3621,11 @@ begin
 
     { Download to temporary file}
     HandleStream := THandleStream.Create(TempF.Handle);
-    HTTPResponse := HTTPClient.Get(Url, HandleStream);
+    if HasCredentials then begin
+      Base64 := TBase64Encoding.Create(0);
+      HTTPClient.CustomHeaders['Authorization'] := 'Basic ' + Base64.Encode(User + ':' + Pass);
+    end;
+    HTTPResponse := HTTPClient.Get(CleanUrl, HandleStream);
     if HTTPDataReceiver.Aborted then
       raise Exception.Create(SetupMessages[msgErrorDownloadAborted])
     else if (HTTPResponse.StatusCode < 200) or (HTTPResponse.StatusCode > 299) then
@@ -3617,6 +3673,7 @@ begin
       TempFileLeftOver := False;
     end;
   finally
+    Base64.Free;
     HandleStream.Free;
     TempF.Free;
     HTTPClient.Free;
@@ -3626,27 +3683,58 @@ begin
   end;
 end;
 
-function DownloadTemporaryFileSize(const Url: String): Int64;
+procedure DownloadTemporaryFileSizeAndDate(const Url: String; var FileSize: Int64; var FileDate: String);
 var
   HTTPClient: THTTPClient;
   HTTPResponse: IHTTPResponse;
+  User, Pass, CleanUrl: string;
+  HasCredentials : Boolean;
+  Base64: TBase64Encoding;
 begin
-  if Url = '' then
-    InternalError('DownloadTemporaryFileSize: Invalid Url value');
-
-  LogFmt('Getting size of %s.', [Url]);
-
   HTTPClient := THTTPClient.Create;
+  Base64 := nil;
+  HasCredentials := GetCredentialsAndCleanUrl(Url, User, Pass, CleanUrl);
   try
+    if HasCredentials then begin
+      Base64 := TBase64Encoding.Create(0);
+      HTTPClient.CustomHeaders['Authorization'] := 'Basic ' + Base64.Encode(User + ':' + Pass);
+    end;
     SetUserAgentAndSecureProtocols(HTTPClient);
-    HTTPResponse := HTTPClient.Head(Url);
+    HTTPResponse := HTTPClient.Head(CleanUrl);
     if (HTTPResponse.StatusCode < 200) or (HTTPResponse.StatusCode > 299) then
       raise Exception.Create(FmtSetupMessage(msgErrorDownloadSizeFailed, [IntToStr(HTTPResponse.StatusCode), HTTPResponse.StatusText]))
-    else
-      Result := HTTPResponse.ContentLength; { Could be -1 }
+    else begin
+      FileSize := HTTPResponse.ContentLength;
+      FileDate := HTTPResponse.LastModified;
+    end;
   finally
+    Base64.Free;
     HTTPClient.Free;
   end;
 end;
 
+function DownloadTemporaryFileSize(const Url: String): Int64;
+var
+  FileSize: Int64;
+  FileDate: String;
+begin
+  if Url = '' then
+    InternalError('DownloadTemporaryFileSize: Invalid Url value');
+  LogFmt('Getting size of %s.', [MaskPasswordInUrl(Url)]);
+  DownloadTemporaryFileSizeAndDate(Url, FileSize, FileDate);
+  Result := FileSize;
+end;
+
+function DownloadTemporaryFileDate(const Url: String): String;
+var
+  FileSize: Int64;
+  FileDate: String;
+begin
+  if Url = '' then
+    InternalError('DownloadTemporaryFileDate: Invalid Url value');
+  LogFmt('Getting last modified date of %s.', [MaskPasswordInUrl(Url)]);
+  DownloadTemporaryFileSizeAndDate(Url, FileSize, FileDate);
+  Result := FileDate;
+end;
+
 end.

+ 1 - 0
Projects/ScriptClasses_C.pas

@@ -556,6 +556,7 @@ begin
     RegisterProperty('AbortButton', 'TNewButton', iptr);
     RegisterProperty('AbortedByUser', 'Boolean', iptr);
     RegisterMethod('procedure Add(const Url, BaseName, RequiredSHA256OfFile: String)');
+    RegisterMethod('procedure AddEx(const Url, BaseName, RequiredSHA256OfFile, UserName, Password: String)');
     RegisterMethod('procedure Clear');
     RegisterMethod('function Download: Int64');
     RegisterMethod('procedure Show'); { Without this TOutputProgressWizardPage's Show will be called }

+ 1 - 0
Projects/ScriptClasses_R.pas

@@ -338,6 +338,7 @@ begin
   begin
     RegisterPropertyHelper(@TDownloadPageAbortedByUser_R,nil,'AbortedByUser');
     RegisterMethod(@TDownloadWizardPage.Add, 'Add');
+    RegisterMethod(@TDownloadWizardPage.AddEx, 'AddEx');
     RegisterMethod(@TDownloadWizardPage.Clear, 'Clear');
     RegisterMethod(@TDownloadWizardPage.Download, 'Download');
     RegisterMethod(@TDownloadWizardPage.Show, 'Show');

+ 11 - 1
Projects/ScriptDlg.pas

@@ -189,6 +189,7 @@ type
       procedure Initialize; override;
       property AbortedByUser: Boolean read FAbortedByUser;
       procedure Add(const Url, BaseName, RequiredSHA256OfFile: String);
+      procedure AddEx(const Url, BaseName, RequiredSHA256OfFile, UserName, Password: String);
       procedure Clear;
       function Download: Int64;
       property OnDownloadProgress: TOnDownloadProgress write FOnDownloadProgress;
@@ -922,7 +923,7 @@ end;
 
 type
   TDownloadFile = class
-    Url, BaseName, RequiredSHA256OfFile: String;
+    Url, BaseName, RequiredSHA256OfFile, UserName, Password: String;
   end;
 
 procedure TDownloadWizardPage.AbortButtonClick(Sender: TObject);
@@ -1014,6 +1015,11 @@ begin
 end;
 
 procedure TDownloadWizardPage.Add(const Url, BaseName, RequiredSHA256OfFile: String);
+begin
+  AddEx(Url, BaseName, RequiredSHA256OfFile, '', '');
+end;
+
+procedure TDownloadWizardPage.AddEx(const Url, BaseName, RequiredSHA256OfFile, UserName, Password: String);
 var
   F: TDownloadFile;
 begin
@@ -1021,6 +1027,8 @@ begin
   F.Url := Url;
   F.BaseName := BaseName;
   F.RequiredSHA256OfFile := RequiredSHA256OfFile;
+  F.UserName := UserName;
+  F.Password := Password;
   FFiles.Add(F);
 end;
 
@@ -1040,8 +1048,10 @@ begin
   for I := 0 to FFiles.Count-1 do begin
     F := TDownloadFile(FFiles[I]);
     { Don't need to set DownloadTemporaryFileProcessMessages before downloading since we already process messages ourselves. }
+    SetDownloadCredentials(F.UserName, F.Password);
     Result := Result + DownloadTemporaryFile(F.Url, F.BaseName, F.RequiredSHA256OfFile, InternalOnDownloadProgress);
   end;
+  SetDownloadCredentials('', '');
 end;
 
 {$ENDIF}

+ 4 - 2
Projects/ScriptFunc.pas

@@ -129,7 +129,7 @@ const
 
   { Install }
 {$IFNDEF PS_NOINT64}
-  InstallTable: array [0..3] of AnsiString =
+  InstallTable: array [0..5] of AnsiString =
 {$ELSE}
   InstallTable: array [0..2] of AnsiString =
 {$ENDIF}
@@ -138,7 +138,9 @@ const
     'function ExtractTemporaryFiles(const Pattern: String): Integer;',
 {$IFNDEF PS_NOINT64}
     'function DownloadTemporaryFile(const Url, FileName, RequiredSHA256OfFile: String; const OnDownloadProgress: TOnDownloadProgress): Int64;',
-    'function DownloadTemporaryFileSize(const Url: String): Int64;'
+    'function DownloadTemporaryFileSize(const Url: String): Int64;',
+    'function DownloadTemporaryFileDate(const Url: String): String;',
+    'procedure SetDownloadCredentials(const User, Pass: String);'
 {$ENDIF}
   );
 

+ 4 - 1
Projects/ScriptFunc_R.pas

@@ -811,9 +811,12 @@ begin
     else
       OnDownloadProgress := nil;
     Stack.SetInt64(PStart, DownloadTemporaryFile(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), OnDownloadProgress));
+  end else if Proc.Name = 'SETDOWNLOADCREDENTIALS' then begin
+    SetDownloadCredentials(Stack.GetString(PStart),Stack.GetString(PStart-1));
   end else if Proc.Name = 'DOWNLOADTEMPORARYFILESIZE' then begin
     Stack.SetInt64(PStart, DownloadTemporaryFileSize(Stack.GetString(PStart-1)));
-{$ENDIF}
+  end else if Proc.Name = 'DOWNLOADTEMPORARYFILEDATE' then begin
+    Stack.SetString(PStart, DownloadTemporaryFileDate(Stack.GetString(PStart-1)));{$ENDIF}
   end else
     Result := False;
 end;

+ 2 - 2
Projects/Struct.pas

@@ -17,8 +17,8 @@ uses
 
 const
   SetupTitle = 'Inno Setup';
-  SetupVersion = '6.2.1';
-  SetupBinVersion = (6 shl 24) + (2 shl 16) + (1 shl 8) + 0;
+  SetupVersion = '6.2.2';
+  SetupBinVersion = (6 shl 24) + (2 shl 16) + (2 shl 8) + 0;
 
 type
   TSetupID = array[0..63] of AnsiChar;