1

I'm writing an install script that's supposed to download a private repository from GitHub:

if Pat <> '' then
begin
  Pat := Pat + '@'
end;

Url := Format('https://%sgithub.com/<MY_REPO>/%s/archive/main.zip', [Pat, RepoName]);

try
  DownloadTemporaryFile(Url, 'main.zip', '', @OnDownloadProgress);
except
  MsgBox('Failed to download the files from the GitHub repository.', mbError, MB_OK);
  Abort();
end;

For a public repository, I can set Pat to an empty string and this works without issue. However, for private repositories, I get a 404 response code. I've tried using a personal access token, and I've tried doing username:token as well. Furthermore, I have verified that the organization name and repository name match and, when trying the URL from a browser, I can download the file. I also have MFA enabled on my account. How can I make this work?

This script is part of an installer where the user enters their PAT, which allows them to download and install the code in the repository. Only people with a valid PAT can access the code.

For PAT, see Clone A Private Repository (Github).

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Woody1193
  • 7,252
  • 5
  • 40
  • 90

1 Answers1

1

After searching through other Stack Overflow questions, I found Get www/web content using HTTP request in Inno Setup, which showed me the hint I needed. This code relies on the WinHttpRequest object, to make the GET request with the required authentication, which is my GitHub Personal Access Token (PAT). This code works.

const
  WinHttpRequestLib = 'WinHttp.WinHttpRequest.5.1';

function ByteArrayToString(const ByteArray: array of Byte): AnsiString;
var
  I: Integer;
begin
  SetLength(Result, GetArrayLength(ByteArray));
  for I := 1 to GetArrayLength(ByteArray) do
    Result[I] := Chr(ByteArray[I - 1]);
end;

procedure GetGitHubArchive(Url, AccessToken: string);
var
  Request:      Variant;
  ResponseBody: string;
begin
  // First, load the OLE object associated with the WinHTTP library
  Request := CreateOleObject(WinHttpRequestLib);

  // Next, open a new GET request to the URL;
  // if we have a non-empty access token then add the
  // associated authorization header here
  Request.Open('GET', Url, false);
  if AccessToken <> '' then
  begin  
    Request.SetRequestHeader('Authorization', 'Bearer ' + AccessToken);
  end;

  // Finally, send the request; if we received a non-200 response code
  // then show the error.
  // Otherwise, extract the response body and write it to a file
  Request.Send;
  if Request.Status <> 200 then 
  begin
    MsgBox('Failed to download file: ' + Request.StatusText, mbError, MB_OK);
    Abort();
  end
  else
  begin
    ResponseBody := ByteArrayToString(Request.ResponseBody);
    SaveStringToFile(ExpandConstant('{tmp}\main.zip'), ResponseBody, False);
  end;
end;
Woody1193
  • 7,252
  • 5
  • 40
  • 90