Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle bad credential exception and block update submissions with no changes #100

Merged
merged 11 commits into from
Jul 3, 2021
8 changes: 7 additions & 1 deletion src/WingetCreateCLI/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public async Task<bool> SetAndCheckGitHubToken(bool cacheToken = false)

return true;
}
catch
catch (Exception e)
{
if (token == cachedToken)
{
Expand All @@ -158,6 +158,12 @@ public async Task<bool> SetAndCheckGitHubToken(bool cacheToken = false)
GitHubOAuth.DeleteTokenCache();
return await this.SetAndCheckGitHubToken();
}
else if (e is AuthorizationException)
{
Logger.ErrorLocalized(nameof(Resources.Error_Prefix), e.Message);
Logger.ErrorLocalized(nameof(Resources.InvalidTokenError_Message));
return false;
}
else
{
throw;
Expand Down
37 changes: 25 additions & 12 deletions src/WingetCreateCLI/Commands/NewCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,23 @@ public override async Task<bool> Execute()

string manifestDirectoryPath = SaveManifestDirToLocalPath(manifests, this.OutputDir);

if (!ValidateManifest(manifestDirectoryPath) ||
!Prompt.Confirm(Resources.ConfirmGitHubSubmitManifest_Message) ||
!await this.SetAndCheckGitHubToken())
{
bool isManifestValid = ValidateManifest(manifestDirectoryPath);

if (isManifestValid && Prompt.Confirm(Resources.ConfirmGitHubSubmitManifest_Message))
{
if (await this.SetAndCheckGitHubToken())
{
return commandEvent.IsSuccessful = await this.GitHubSubmitManifests(manifests, this.GitHubToken);
}

return false;
}
else
{
Console.WriteLine();
Logger.WarnLocalized(nameof(Resources.SkippingPullRequest_Message));
return false;
Logger.WarnLocalized(nameof(Resources.SkippingPullRequest_Message));
return commandEvent.IsSuccessful = isManifestValid;
}

return commandEvent.IsSuccessful = await this.GitHubSubmitManifests(
manifests,
this.GitHubToken);
}
finally
{
Expand Down Expand Up @@ -304,11 +309,19 @@ private static T PromptProperty<T>(object model, T property, string memberName,
/// <returns>Boolean value indicating whether the package identifier is valid.</returns>
private async Task<bool> PromptPackageIdentifierAndCheckDuplicates(Manifests manifests)
{
GitHub client = new GitHub(this.GitHubToken, this.WingetRepoOwner, this.WingetRepo);

if (!string.IsNullOrEmpty(this.GitHubToken))
{
if (!await this.SetAndCheckGitHubToken())
{
return false;
}
}

VersionManifest versionManifest = manifests.VersionManifest;
versionManifest.PackageIdentifier = PromptProperty(versionManifest, versionManifest.PackageIdentifier, nameof(versionManifest.PackageIdentifier));

GitHub client = new GitHub(this.GitHubToken, this.WingetRepoOwner, this.WingetRepo);

string exactMatch = await client.FindPackageId(versionManifest.PackageIdentifier);
if (!string.IsNullOrEmpty(exactMatch))
{
Expand Down
6 changes: 2 additions & 4 deletions src/WingetCreateCLI/Commands/SubmitCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,16 @@ public override async Task<bool> Execute()

private async Task<bool> SubmitManifest()
{
Manifests manifests = new Manifests();

if (File.Exists(this.Path) && ValidateManifest(this.Path))
{
Manifests manifests = new Manifests();
manifests.SingletonManifest = Serialization.DeserializeFromPath<SingletonManifest>(this.Path);
return await this.GitHubSubmitManifests(manifests, this.GitHubToken);
}
else if (Directory.Exists(this.Path) && ValidateManifest(this.Path))
{
List<string> manifestContents = Directory.GetFiles(this.Path).Select(f => File.ReadAllText(f)).ToList();

Serialization.DeserializeManifestContents(manifestContents, manifests);
Manifests manifests = Serialization.DeserializeManifestContents(manifestContents);
return await this.GitHubSubmitManifests(manifests, this.GitHubToken);
}
else
Expand Down
52 changes: 43 additions & 9 deletions src/WingetCreateCLI/Commands/UpdateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,18 @@ public override async Task<bool> Execute()

try
{
GitHub client = new GitHub(this.GitHubToken, this.WingetRepoOwner, this.WingetRepo);
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved

if (!string.IsNullOrEmpty(this.GitHubToken))
{
if (!await this.SetAndCheckGitHubToken())
{
return false;
}
}

Logger.DebugLocalized(nameof(Resources.RetrievingManifest_Message), this.Id);

GitHub client = new GitHub(this.GitHubToken, this.WingetRepoOwner, this.WingetRepo);
string exactId = await client.FindPackageId(this.Id);

if (!string.IsNullOrEmpty(exactId))
Expand Down Expand Up @@ -133,9 +142,7 @@ public override async Task<bool> Execute()
/// <returns>Manifests object representing the updates manifest content, or null if the update failed.</returns>
public async Task<Manifests> DeserializeExistingManifestsAndUpdate(List<string> latestManifestContent)
{
Manifests manifests = new Manifests();

Serialization.DeserializeManifestContents(latestManifestContent, manifests);
Manifests manifests = Serialization.DeserializeManifestContents(latestManifestContent);

if (manifests.SingletonManifest != null)
{
Expand Down Expand Up @@ -192,27 +199,36 @@ public async Task<Manifests> DeserializeExistingManifestsAndUpdate(List<string>
/// <returns>Boolean representing whether the manifest was updated successfully or not.</returns>
public async Task<bool> ExecuteManifestUpdate(List<string> latestManifestContent, CommandExecutedEvent commandEvent)
{
Manifests manifests = await this.DeserializeExistingManifestsAndUpdate(latestManifestContent);
if (manifests == null)
Manifests originalManifests = Serialization.DeserializeManifestContents(latestManifestContent);
Manifests updatedManifests = await this.DeserializeExistingManifestsAndUpdate(latestManifestContent);

if (updatedManifests == null)
{
return false;
}

DisplayManifestPreview(manifests);
DisplayManifestPreview(updatedManifests);

if (string.IsNullOrEmpty(this.OutputDir))
{
this.OutputDir = Directory.GetCurrentDirectory();
}

string manifestDirectoryPath = SaveManifestDirToLocalPath(manifests, this.OutputDir);
string manifestDirectoryPath = SaveManifestDirToLocalPath(updatedManifests, this.OutputDir);

if (ValidateManifest(manifestDirectoryPath))
{
if (this.SubmitToGitHub)
{
if (!this.VerifyUpdatedInstallerHash(originalManifests, updatedManifests.InstallerManifest))
{
Logger.ErrorLocalized(nameof(Resources.NoChangeDetectedInUpdatedManifest_Message));
Logger.ErrorLocalized(nameof(Resources.CompareUpdatedManifestWithExisting_Message));
return false;
}

return await this.SetAndCheckGitHubToken()
? (commandEvent.IsSuccessful = await this.GitHubSubmitManifests(manifests, this.GitHubToken))
? (commandEvent.IsSuccessful = await this.GitHubSubmitManifests(updatedManifests, this.GitHubToken))
: false;
}

Expand Down Expand Up @@ -260,5 +276,23 @@ private static void UpdatePropertyForLocaleManifests(string propertyName, string
manifest.GetType().GetProperty(propertyName).SetValue(manifest, value);
}
}

/// <summary>
/// Compares the hashes of the original and updated manifests and returns true if the new manifest has an updated SHA256 hash.
/// </summary>
/// <param name="oldManifest">The original manifest object model.</param>
/// <param name="newManifest">The updated installer manifest object model.</param>
/// <returns>A boolean value indicating whether the updated manifest has new changes compared to the original manifest.</returns>
private bool VerifyUpdatedInstallerHash(Manifests oldManifest, InstallerManifest newManifest)
{
IEnumerable<string> oldHashes;
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved

oldHashes = oldManifest.InstallerManifest == null
? oldManifest.SingletonManifest.Installers.Select(i => i.InstallerSha256).Distinct()
: oldManifest.InstallerManifest.Installers.Select(i => i.InstallerSha256).Distinct();

var newHashes = newManifest.Installers.Select(i => i.InstallerSha256).Distinct();
return newHashes.Except(oldHashes).Any();
}
}
}
20 changes: 15 additions & 5 deletions src/WingetCreateCLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Microsoft.WingetCreateCLI
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using CommandLine;
using CommandLine.Text;
Expand Down Expand Up @@ -35,13 +37,15 @@ private static async Task<int> Main(string[] args)
Logger.Trace($"Command line args: {arguments}");

Parser myParser = new Parser(config => config.HelpWriter = null);

var parserResult = myParser.ParseArguments<NewCommand, UpdateCommand, SubmitCommand, TokenCommand, SettingsCommand>(args);
BaseCommand command = parserResult.MapResult(c => c as BaseCommand, err => null);

var types = GetVerbs();
var parserResult = myParser.ParseArguments(args, types);
BaseCommand command = parserResult.MapResult(c => c as BaseCommand, err => null);

if (command == null)
{
DisplayHelp(parserResult as NotParsed<object>);
return 1;
return args.Any() ? 1 : 0;
}

try
Expand All @@ -61,7 +65,13 @@ private static async Task<int> Main(string[] args)
Logger.Error(ex.ToString());
return 1;
}
}
}

private static Type[] GetVerbs()
{
return Assembly.GetExecutingAssembly().GetTypes()
.Where(types => types.GetCustomAttribute<VerbAttribute>() != null).ToArray();
}

private static void DisplayHelp(NotParsed<object> result)
{
Expand Down
27 changes: 27 additions & 0 deletions src/WingetCreateCLI/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/WingetCreateCLI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -587,4 +587,13 @@
<data name="UnexpectedErrorLoadSettings_Message" xml:space="preserve">
<value>Unexpected error while loading settings. Please verify your settings by running the settings command.</value>
</data>
<data name="CompareUpdatedManifestWithExisting_Message" xml:space="preserve">
<value>Please ensure that the updated manifest you are submitting is different from the existing package.</value>
</data>
<data name="InvalidTokenError_Message" xml:space="preserve">
<value>Invalid token provided, please generate a new GitHub token and try again.</value>
</data>
<data name="NoChangeDetectedInUpdatedManifest_Message" xml:space="preserve">
<value>Submitting a manifest without any updated changes is not allowed. </value>
</data>
</root>
8 changes: 6 additions & 2 deletions src/WingetCreateCore/Common/Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,11 @@ public static string ConvertYamlToJson(string yaml)
/// Deserializes a list of manifest strings into their appropriate object models.
/// </summary>
/// <param name="manifestContents">List of manifest string contents.</param>
/// <param name="manifests">Wrapper object for manifest object models.</param>
public static void DeserializeManifestContents(IEnumerable<string> manifestContents, Manifests manifests)
/// <returns>Manifest object model.</returns>
public static Manifests DeserializeManifestContents(IEnumerable<string> manifestContents)
{
Manifests manifests = new Manifests();

foreach (string content in manifestContents)
{
string trimmedContent = RemoveBom(content);
Expand Down Expand Up @@ -171,6 +173,8 @@ public static void DeserializeManifestContents(IEnumerable<string> manifestConte
manifests.InstallerManifest = Serialization.DeserializeFromString<InstallerManifest>(trimmedContent);
}
}

return manifests;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ InstallerSwitches:
Installers:
- Architecture: x64
InstallerUrl: https://fakedomain.com/ManifestCreatorTestExeInstaller.exe
InstallerSha256: A7803233EEDB6A4B59B3024CCF9292A6FFFB94507DC998AA67C5B745D197A5DC
InstallerSha256: 71A2BF371B23C9432F4E0E08AE6F2A754067F0FE09C0141556DE4AF628F6B371
ManifestType: singleton
ManifestVersion: 1.0.0
15 changes: 15 additions & 0 deletions src/WingetCreateTests/WingetCreateTests/TestConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,20 @@ public static class TestConstants
/// File name of the test msix manifest.
/// </summary>
public const string TestMsixManifest = "WingetCreateE2E.MsixTest.yaml";

/// <summary>
/// File name of the test multifile msi version manifest.
/// </summary>
public const string TestMultifileMsiVersionManifest = "Multifile.MsiTest.yaml";

/// <summary>
/// File name of the test multifile msi installer manifest.
/// </summary>
public const string TestMultifileMsiInstallerManifest = "Multifile.MsiTest.installer.yaml";

/// <summary>
/// File name of the test multifile msi default locale manifest.
/// </summary>
public const string TestMultifileMsiDefaultLocaleManifest = "Multifile.MsiTest.locale.en-US.yaml";
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading