Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,13 @@ Running unit and E2E tests are a great way to ensure that functionality is prese
* Fill out the test parameters in the `WingetCreateTests/Test.runsettings` file
* `WingetPkgsTestRepoOwner`: The repository owner of the winget-pkgs-submission-test repo. (Repo owner must be forked from main "winget-pkgs-submission-test" repo)
* `WingetPkgsTestRepo`: The winget-pkgs test repository. (winget-pkgs-submission-test)
* `GitHubApiKey`: GitHub personal access token for testing.
* Instructions on [how to generate your own GitHubApiKey](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
* Direct link to GitHub [Personal Access Tokens page](https://github.com/settings/tokens).
* `GitHubAppPrivateKey`: Leave blank, this is only used by the build server.

* Set the solution wide runsettings file for the tests
* Go to `Test` menu > `Configure Run Settings` -> `Select Solution Wide runsettings File` -> Choose your configured runsettings file

> [!CAUTION]
> You should treat your access token like a password. To avoid exposing your PAT, be sure to reset changes to the `WingetCreateTests/Test.runsettings` file before committing your changes. You can also use the command `git update-index --skip-worktree src/WingetCreateTests/WingetCreateTests/Test.runsettings` command to untrack changes to the file and prevent it from being committed.
* Set up your github token:
* __[Recommended]__ Run 'wingetcreate token -s` to go through the Github authentication flow
* Or create a personal access token with the `repo` permission and set it as an environment variable `WINGET_CREATE_GITHUB_TOKEN`. _(This option is more convenient for CI/CD pipelines.)_

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion doc/new-locale.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The following arguments are available:
| **-r, --reference-locale** | Existing locale manifest to be used as reference for default values. If not provided, the default locale manifest will be used.
| **-o, --out** | The output directory where the newly created manifests will be saved locally.
| **-f,--format** | Output format of the manifest. Default is "yaml". |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command |

Instructions on setting up GitHub Token for Winget-Create can be found [here](../README.md#github-personal-access-token-classic-permissions).
2 changes: 1 addition & 1 deletion doc/new.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The following arguments are available:
|--------------|-------------|
| **-o,--out** | The output directory where the newly created manifests will be saved locally |
| **-f,--format** | Output format of the manifest. Default is "yaml". |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command |

## Winget-Create New Command flow
Expand Down
2 changes: 1 addition & 1 deletion doc/show.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The following arguments are available:
| **-l, --locale-manifests** | Switch to display all locale manifests.
| **--version-manifest** | Switch to display the version manifest.
| **-f,--format** | Output format of the manifest. Default is "yaml". |
| **-t, --token** | GitHub personal access token used for authenticated access to the GitHub API. It is recommended to provide a token to get a higher [API rate limit](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting).
| **-t, --token** | GitHub personal access token used for authenticated access to the GitHub API. It is recommended to provide a token to get a higher [API rate limit](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command. |

Instructions on setting up GitHub Token for Winget-Create can be found [here](../README.md#github-personal-access-token-classic-permissions).
2 changes: 1 addition & 1 deletion doc/submit.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The following arguments are available:
|--------------|-------------|
| **-p, --prtitle** | The title of the pull request submitted to GitHub.
| **-r, --replace** | Boolean value for replacing an existing manifest from the Windows Package Manager repo. Optionally provide a version or else the latest version will be replaced. Default is false.
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials.
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command. |

If you have provided your [GitHub token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) on the command line with the **submit** command and the device is registered with GitHub, **Winget-Create** will submit your PR to [Windows Package Manager repo](https://docs.microsoft.com/windows/package-manager/).
Expand Down
9 changes: 8 additions & 1 deletion doc/token.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ Instructions on setting up GitHub Token for Winget-Create can be found [here](..

## Usage

> [!WARNING]
> Using the `--token` argument may result in the token being logged.
>
> For local development, it is recommended to go through the OAuth flow by omitting the `--token` argument.
>
> For CI/CD scenarios, it is recommended to use the 'WINGET_CREATE_GITHUB_TOKEN' environment variable to store the token.

`wingetcreate.exe token [\<options>]`

### Store a new GitHub token in your local cache
Expand All @@ -25,5 +32,5 @@ The following arguments are available:
|---------------- |-------------|
| **-c, --clear** | Required. Clear the cached GitHub token
| **-s, --store** | Required. Set the cached GitHub token. Can specify token to cache with --token parameter, otherwise will initiate OAuth flow.
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials.
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._
| **-?, --help** | Gets additional help on this command. |
2 changes: 1 addition & 1 deletion doc/update-locale.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The following arguments are available:
| **-l, --locale** | The package locale to update the manifest for. If not provided, the tool will prompt you a list of existing locales to choose from.
| **-o, --out** | The output directory where the newly created manifests will be saved locally.
| **-f,--format** | Output format of the manifest. Default is "yaml". |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo |
| **-t,--token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command |

Instructions on setting up GitHub Token for Winget-Create can be found [here](../README.md#github-personal-access-token-classic-permissions).
2 changes: 1 addition & 1 deletion doc/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ The following arguments are available:
| **-r, --replace** | Boolean value for replacing an existing manifest from the Windows Package Manager repo. Optionally provide a version or else the latest version will be replaced. Default is false. |
| **-i, --interactive** | Boolean value for making the update command interactive. If true, the tool will prompt the user for input. Default is false. |
| **-f,--format** | Output format of the manifest. Default is "yaml". |
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials. |
| **-t, --token** | GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials. <br/>⚠️ _Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token._ |
| **-?, --help** | Gets additional help on this command. |

## Submit
Expand Down
4 changes: 3 additions & 1 deletion pipelines/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ extends:
testSelector: "testAssemblies"
testAssemblyVer2: 'src\WingetCreateTests\WingetCreateTests\bin\$(buildPlatform)\$(buildConfiguration)\$(targetFramework)\WingetCreateTests.dll'
runSettingsFile: 'src\WingetCreateTests\WingetCreateTests\Test.runsettings'
overrideTestrunParameters: '-WingetPkgsTestRepoOwner microsoft -WingetPkgsTestRepo winget-pkgs-submission-test -GitHubAppPrivateKey "$(GitHubApp_PrivateKey)"'
overrideTestrunParameters: '-WingetPkgsTestRepoOwner microsoft -WingetPkgsTestRepo winget-pkgs-submission-test'
env:
WINGET_CREATE_APP_KEY: $(GitHubApp_PrivateKey)

- task: 1ES.PublishPipelineArtifact@1
inputs:
Expand Down
23 changes: 10 additions & 13 deletions src/WingetCreateCLI/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,19 @@ public async Task<bool> LoadGitHubClient(bool requireToken = false)
if (string.IsNullOrEmpty(this.GitHubToken))
{
Logger.Trace("No token parameter, reading cached token");
this.GitHubToken = GitHubOAuth.ReadTokenCache();
if (string.IsNullOrEmpty(this.GitHubToken))
if (GitHubOAuth.TryReadTokenCache(out var token))
{
if (requireToken)
{
Logger.Trace("No token found in cache, launching OAuth flow");
if (!await this.GetTokenFromOAuth())
{
Logger.Trace("Failed to obtain token from OAuth flow.");
return false;
}
}
this.GitHubToken = token;
isCacheToken = true;
}
else
else if (requireToken)
{
isCacheToken = true;
Logger.Trace("No token found in cache, launching OAuth flow");
if (!await this.GetTokenFromOAuth())
{
Logger.Trace("Failed to obtain token from OAuth flow.");
return false;
}
}
}

Expand Down
73 changes: 24 additions & 49 deletions src/WingetCreateCLI/GitHubOAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ namespace Microsoft.WingetCreateCLI
{
using System;
using System.ComponentModel;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Microsoft.WingetCreateCLI.Logging;
using Microsoft.WingetCreateCLI.Properties;
using Microsoft.WingetCreateCLI.Telemetry;
Expand All @@ -25,49 +22,27 @@ public static class GitHubOAuth
{
private const string GitHubDeviceEndpoint = "https://github.com/login/device/code";
private const string GitHubTokenEndpoint = "https://github.com/login/oauth/access_token";
private const string GrantType = "urn:ietf:params:oauth:grant-type:device_code";
private static readonly string TokenFile = Path.Combine(Common.LocalAppStatePath, "tokenCache.bin");

/// <summary>
/// Create byte array for additional entropy when using Protect method.
/// </summary>
private static readonly byte[] EntropyBytes = Encoding.UTF8.GetBytes(TokenFile);

/// <summary>
/// Deletes the cached token.
/// </summary>
public static void DeleteTokenCache()
{
File.Delete(TokenFile);
}

/// <summary>
/// Reads and decrypts the cached token, if one exists.
/// </summary>
/// <returns>Decrypted cached token.</returns>
public static string ReadTokenCache()
{
if (File.Exists(TokenFile))
{
var protectedBytes = File.ReadAllBytes(TokenFile);
var bytes = ProtectedData.Unprotect(protectedBytes, EntropyBytes, DataProtectionScope.CurrentUser);
return Encoding.UTF8.GetString(bytes);
}
else
{
return null;
}
}

/// <summary>
/// Encrypts and writes the token to the file cache.
/// </summary>
/// <param name="token">Token to be cached.</param>
public static void WriteTokenCache(string token)
{
var bytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(token), EntropyBytes, DataProtectionScope.CurrentUser);
File.WriteAllBytes(TokenFile, bytes);
}
private const string GrantType = "urn:ietf:params:oauth:grant-type:device_code";

/// <summary>
/// Deletes the token.
/// </summary>
/// <returns>True if the token was deleted, false otherwise.</returns>
public static bool DeleteTokenCache() => TokenHelper.Delete();

/// <summary>
/// Writes the token.
/// </summary>
/// <param name="token">Token to be cached.</param>
/// <returns>True if the token was written, false otherwise.</returns>
public static bool WriteTokenCache(string token) => TokenHelper.Write(token);

/// <summary>
/// Reads the token.
/// </summary>
/// <param name="token">Output token.</param>
/// <returns>True if the token was read, false otherwise.</returns>
public static bool TryReadTokenCache(out string token) => TokenHelper.TryRead(out token);

/// <summary>
/// Sends a POST request to GitHub's authorization server to obtain a device code.
Expand Down Expand Up @@ -236,5 +211,5 @@ public class TokenErrorResponse
[JsonPropertyName("error_uri")]
public string ErrorUri { get; set; }
}
}
}
}
}
4 changes: 4 additions & 0 deletions src/WingetCreateCLI/NativeMethods.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CredDelete
CredFree
CredRead
CredWrite
6 changes: 6 additions & 0 deletions src/WingetCreateCLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ private static async Task<int> Main(string[] args)
return args.Any() ? 1 : 0;
}

// If the user has provided a token via the command line, warn them that it may be logged
if (!string.IsNullOrEmpty(command.GitHubToken))
{
Logger.WarnLocalized(nameof(Resources.GitHubTokenWarning_Message));
}

bool commandHandlesToken = command is not CacheCommand and not InfoCommand and not SettingsCommand;

// Do not load github client for commands that do not deal with a GitHub token.
Expand Down
13 changes: 12 additions & 1 deletion src/WingetCreateCLI/Properties/Resources.Designer.cs

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

7 changes: 6 additions & 1 deletion src/WingetCreateCLI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@
<value>GitHub login failed.</value>
</data>
<data name="GitHubToken_HelpText" xml:space="preserve">
<value>GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials.</value>
<value>GitHub personal access token used for direct submission to the Windows Package Manager repo. If no token is provided, tool will prompt for GitHub login credentials.

Warning: Using this argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token.</value>
</data>
<data name="Heading" xml:space="preserve">
<value>Windows Package Manager Manifest Creator v{0}</value>
Expand Down Expand Up @@ -653,6 +655,9 @@
<data name="InvalidGitHubToken_Message" xml:space="preserve">
<value>Token was invalid. Please generate a new GitHub token and try again.</value>
</data>
<data name="GitHubTokenWarning_Message" xml:space="preserve">
<value>Warning: Using the --token argument may result in the token being logged. Consider an alternative approach https://aka.ms/winget-create-token.</value>
</data>
<data name="RateLimitExceeded_Message" xml:space="preserve">
<value>GitHub api rate limit exceeded. To extend your rate limit, provide your GitHub token with the '-t' flag or store one using the 'token --store' command.</value>
<comment>'-t' refers to a command line switch argument
Expand Down
Loading