mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Fix bug in GithubSource when an access token is not provided
This commit is contained in:
@@ -37,7 +37,7 @@ namespace Velopack.Sources
|
||||
/// <summary>
|
||||
/// The Bearer or other type of Authorization header used to authenticate against the Api.
|
||||
/// </summary>
|
||||
protected abstract (string Name, string Value) Authorization { get; }
|
||||
protected abstract (string Name, string Value)? Authorization { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Base constructor.
|
||||
@@ -51,17 +51,18 @@ namespace Velopack.Sources
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
|
||||
public virtual Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress,
|
||||
CancellationToken cancelToken)
|
||||
{
|
||||
if (releaseEntry is GitBaseAsset githubEntry) {
|
||||
// this might be a browser url or an api url (depending on whether we have a AccessToken or not)
|
||||
// https://docs.github.com/en/rest/reference/releases#get-a-release-asset
|
||||
var assetUrl = GetAssetUrlFromName(githubEntry.Release, releaseEntry.FileName);
|
||||
return Downloader.DownloadFile(assetUrl, localFile, progress,
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/octet-stream"
|
||||
},
|
||||
return Downloader.DownloadFile(
|
||||
assetUrl,
|
||||
localFile,
|
||||
progress,
|
||||
GetRequestHeaders("application/octet-stream"),
|
||||
cancelToken: cancelToken);
|
||||
}
|
||||
|
||||
@@ -91,11 +92,10 @@ namespace Velopack.Sources
|
||||
logger.Trace(ex.ToString());
|
||||
continue;
|
||||
}
|
||||
var releaseBytes = await Downloader.DownloadBytes(assetUrl,
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/octet-stream"
|
||||
}
|
||||
|
||||
var releaseBytes = await Downloader.DownloadBytes(
|
||||
assetUrl,
|
||||
GetRequestHeaders("application/octet-stream")
|
||||
).ConfigureAwait(false);
|
||||
var txt = CoreUtil.RemoveByteOrderMarkerIfPresent(releaseBytes);
|
||||
var feed = VelopackAssetFeed.FromJson(txt);
|
||||
@@ -122,6 +122,24 @@ namespace Velopack.Sources
|
||||
/// </summary>
|
||||
protected abstract string GetAssetUrlFromName(T release, string assetName);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a dictionary containing HTTP request headers.
|
||||
/// </summary>
|
||||
/// <param name="accept">The value for the "Accept" header; defaults to "application/json".</param>
|
||||
/// <returns>A dictionary of headers including "Accept" and, if available, authorization headers.</returns>
|
||||
protected virtual Dictionary<string, string> GetRequestHeaders(string accept = "application/json")
|
||||
{
|
||||
var headers = new Dictionary<string, string> {
|
||||
["Accept"] = accept,
|
||||
};
|
||||
if (Authorization.HasValue) {
|
||||
headers.Add(Authorization.Value.Name, Authorization.Value.Value);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a wrapper around <see cref="VelopackAsset"/> which also contains a Git Release.
|
||||
/// </summary>
|
||||
|
||||
@@ -83,7 +83,8 @@ namespace Velopack.Sources
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("Authorization", $"token {AccessToken}");
|
||||
protected override (string Name, string Value)? Authorization =>
|
||||
string.IsNullOrEmpty(AccessToken) ? null : ("Authorization", $"token {AccessToken}");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<GiteaRelease[]> GetReleases(bool includePrereleases)
|
||||
@@ -96,14 +97,9 @@ namespace Velopack.Sources
|
||||
var releasesPath = $"repos{RepoUri.AbsolutePath}/releases?limit={perPage}&page={page}&draft=false";
|
||||
var baseUri = GetApiBaseUrl(RepoUri);
|
||||
var getReleasesUri = new Uri(baseUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/json"
|
||||
}
|
||||
).ConfigureAwait(false);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(), GetRequestHeaders()).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGiteaReleaseList(response);
|
||||
if (releases == null) return new GiteaRelease[0];
|
||||
if (releases == null) return Array.Empty<GiteaRelease>();
|
||||
return releases.OrderByDescending(d => d.PublishedAt).Where(x => includePrereleases || !x.Prerelease).ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ namespace Velopack.Sources
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("Authorization", $"Bearer {AccessToken}");
|
||||
protected override (string Name, string Value)? Authorization =>
|
||||
string.IsNullOrEmpty(AccessToken) ? null : ("Authorization", $"Bearer {AccessToken}");
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<GithubRelease[]> GetReleases(bool includePrereleases)
|
||||
@@ -99,11 +100,9 @@ namespace Velopack.Sources
|
||||
var releasesPath = $"repos{RepoUri.AbsolutePath}/releases?per_page={perPage}&page={page}";
|
||||
var baseUri = GetApiBaseUrl(RepoUri);
|
||||
var getReleasesUri = new Uri(baseUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/vnd.github.v3+json"
|
||||
}
|
||||
var response = await Downloader.DownloadString(
|
||||
getReleasesUri.ToString(),
|
||||
GetRequestHeaders("application/vnd.github.v3+json")
|
||||
).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGithubReleaseList(response);
|
||||
if (releases == null) return Array.Empty<GithubRelease>();
|
||||
@@ -117,7 +116,8 @@ namespace Velopack.Sources
|
||||
throw new ArgumentException($"No assets found in GitHub Release '{release.Name}'.");
|
||||
}
|
||||
|
||||
IEnumerable<GithubReleaseAsset> allReleasesFiles = release.Assets.Where(a => a.Name?.Equals(assetName, StringComparison.InvariantCultureIgnoreCase) == true);
|
||||
IEnumerable<GithubReleaseAsset> allReleasesFiles =
|
||||
release.Assets.Where(a => a.Name?.Equals(assetName, StringComparison.InvariantCultureIgnoreCase) == true);
|
||||
if (!allReleasesFiles.Any()) {
|
||||
throw new ArgumentException($"Could not find asset called '{assetName}' in GitHub Release '{release.Name}'.");
|
||||
}
|
||||
@@ -157,6 +157,7 @@ namespace Velopack.Sources
|
||||
// API location is http://internal.github.server.local/api/v3
|
||||
baseAddress = new Uri(string.Format("{0}{1}{2}/api/v3/", repoUrl.Scheme, Uri.SchemeDelimiter, repoUrl.Host));
|
||||
}
|
||||
|
||||
// above ^^ notice the end slashes for the baseAddress, explained here: http://stackoverflow.com/a/23438417/162694
|
||||
return baseAddress;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,8 @@ namespace Velopack.Sources
|
||||
public class GitlabSource : GitBase<GitlabRelease>
|
||||
{
|
||||
/// <inheritdoc cref="Authorization"/>
|
||||
protected override (string Name, string Value) Authorization => ("PRIVATE-TOKEN", AccessToken ?? string.Empty);
|
||||
protected override (string Name, string Value)? Authorization =>
|
||||
string.IsNullOrEmpty(AccessToken) ? null : ("PRIVATE-TOKEN", AccessToken ?? string.Empty);
|
||||
|
||||
/// <inheritdoc cref="GitlabSource" />
|
||||
/// <param name="repoUrl">
|
||||
@@ -159,11 +160,7 @@ namespace Velopack.Sources
|
||||
// https://docs.gitlab.com/ee/api/releases/
|
||||
var releasesPath = $"releases?per_page={perPage}&page={page}";
|
||||
var getReleasesUri = CombineUri(RepoUri, releasesPath);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(),
|
||||
new Dictionary<string, string> {
|
||||
[Authorization.Name] = Authorization.Value,
|
||||
["Accept"] = "application/json"
|
||||
}).ConfigureAwait(false);
|
||||
var response = await Downloader.DownloadString(getReleasesUri.ToString(), GetRequestHeaders()).ConfigureAwait(false);
|
||||
var releases = CompiledJson.DeserializeGitlabReleaseList(response);
|
||||
if (releases == null) return Array.Empty<GitlabRelease>();
|
||||
return releases.OrderByDescending(d => d.ReleasedAt).Where(x => includePrereleases || !x.UpcomingRelease).ToArray();
|
||||
|
||||
@@ -20,6 +20,26 @@ public class GithubDeploymentTests
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact(Skip = "Need to create a repo to test with")]
|
||||
public async Task TestUnauthenticatedDownload()
|
||||
{
|
||||
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
|
||||
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
|
||||
|
||||
var repo = new GitHubRepository(logger);
|
||||
var options = new GitHubDownloadOptions {
|
||||
TargetOs = RuntimeOs.Linux,
|
||||
Channel = "linux-x64",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
Timeout = 60,
|
||||
Prerelease = false,
|
||||
RepoUrl = "TODO",
|
||||
Token = null,
|
||||
};
|
||||
|
||||
await repo.DownloadLatestFullPackageAsync(options);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void WillRefuseToUploadMultipleWithoutMergeArg()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user