From cbf0683653858e8aca3bd6df33b5877a786498e6 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Tue, 7 Jun 2022 14:30:11 -0700 Subject: [PATCH] Localize strings in user-jwts tool (#42061) * Localize strings in user-jwts tool * Update localziations --- .../src/Commands/ClearCommand.cs | 13 +- .../src/Commands/CreateCommand.cs | 36 ++- .../src/Commands/KeyCommand.cs | 17 +- .../src/Commands/ListCommand.cs | 10 +- .../src/Commands/PrintCommand.cs | 13 +- .../Commands/ProjectCommandLineApplication.cs | 2 +- .../{DeleteCommand.cs => RemoveCommand.cs} | 12 +- .../src/Helpers/DevJwtCliHelpers.cs | 2 +- src/Tools/dotnet-user-jwts/src/Program.cs | 4 +- src/Tools/dotnet-user-jwts/src/Resources.resx | 255 ++++++++++++++++++ .../dotnet-user-jwts/test/UserJwtsTests.cs | 4 +- 11 files changed, 311 insertions(+), 57 deletions(-) rename src/Tools/dotnet-user-jwts/src/Commands/{DeleteCommand.cs => RemoveCommand.cs} (79%) create mode 100644 src/Tools/dotnet-user-jwts/src/Resources.resx diff --git a/src/Tools/dotnet-user-jwts/src/Commands/ClearCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/ClearCommand.cs index e0880812fc8e..abc01f770e3d 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/ClearCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/ClearCommand.cs @@ -12,11 +12,11 @@ public static void Register(ProjectCommandLineApplication app) { app.Command("clear", cmd => { - cmd.Description = "Delete all issued JWTs for a project"; + cmd.Description = Resources.ClearCommand_Description; var forceOption = cmd.Option( "--force", - "Don't prompt for confirmation before deleting JWTs", + Resources.ClearCommand_ForceOption_Description, CommandOptionType.NoValue); cmd.HelpOption("-h|--help"); @@ -39,16 +39,17 @@ private static int Execute(IReporter reporter, string projectPath, bool force) if (count == 0) { - reporter.Output($"There are no JWTs to delete from {project}."); + reporter.Output(Resources.FormatClearCommand_NoJwtsRemoved(project)); return 0; } if (!force) { - reporter.Output($"Are you sure you want to delete {count} JWT(s) for {project}?{Environment.NewLine} [Y]es / [N]o"); + reporter.Output(Resources.ClearCommand_Permission); + reporter.Output("[Y]es / [N]o"); if (Console.ReadLine().Trim().ToUpperInvariant() != "Y") { - reporter.Output("Canceled, no JWTs were deleted."); + reporter.Output(Resources.ClearCommand_Canceled); return 0; } } @@ -62,7 +63,7 @@ private static int Execute(IReporter reporter, string projectPath, bool force) jwtStore.Jwts.Clear(); jwtStore.Save(); - reporter.Output($"Deleted {count} token(s) from {project} successfully."); + reporter.Output(Resources.FormatClearCommand_Confirmed(count, project)); return 0; } diff --git a/src/Tools/dotnet-user-jwts/src/Commands/CreateCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/CreateCommand.cs index 17ac345c5945..a9eb9253852f 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/CreateCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/CreateCommand.cs @@ -23,59 +23,57 @@ public static void Register(ProjectCommandLineApplication app) { app.Command("create", cmd => { - cmd.Description = "Issue a new JSON Web Token"; + cmd.Description = Resources.CreateCommand_Description; var schemeNameOption = cmd.Option( "--scheme", - "The scheme name to use for the generated token. Defaults to 'Bearer'", + Resources.CreateCommand_SchemeOption_Description, CommandOptionType.SingleValue ); var nameOption = cmd.Option( "--name", - "The name of the user to create the JWT for. Defaults to the current environment user.", + Resources.CreateCommand_NameOption_Description, CommandOptionType.SingleValue); var audienceOption = cmd.Option( "--audience", - "The audiences to create the JWT for. Defaults to the URLs configured in the project's launchSettings.json", + Resources.CreateCommand_AudienceOption_Description, CommandOptionType.MultipleValue); var issuerOption = cmd.Option( "--issuer", - "The issuer of the JWT. Defaults to the dotnet-user-jwts", + Resources.CreateCommand_IssuerOption_Description, CommandOptionType.SingleValue); var scopesOption = cmd.Option( "--scope", - "A scope claim to add to the JWT. Specify once for each scope.", + Resources.CreateCommand_ScopeOption_Description, CommandOptionType.MultipleValue); var rolesOption = cmd.Option( "--role", - "A role claim to add to the JWT. Specify once for each role", + Resources.CreateCommand_RoleOption_Description, CommandOptionType.MultipleValue); var claimsOption = cmd.Option( "--claim", - "Claims to add to the JWT. Specify once for each claim in the format \"name=value\"", + Resources.CreateCommand_ClaimOption_Description, CommandOptionType.MultipleValue); var notBeforeOption = cmd.Option( "--not-before", - @"The UTC date & time the JWT should not be valid before in the format 'yyyy-MM-dd [[HH:mm[[:ss]]]]'. Defaults to the date & time the JWT is created", + Resources.CreateCommand_NotBeforeOption_Description, CommandOptionType.SingleValue); var expiresOnOption = cmd.Option( "--expires-on", - @"The UTC date & time the JWT should expire in the format 'yyyy-MM-dd [[[[HH:mm]]:ss]]'. Defaults to 6 months after the --not-before date. " + - "Do not use this option in conjunction with the --valid-for option.", + Resources.CreateCommand_ExpiresOnOption_Description, CommandOptionType.SingleValue); var validForOption = cmd.Option( "--valid-for", - "The period the JWT should expire after. Specify using a number followed by a period type like 'd' for days, 'h' for hours, " + - "'m' for minutes, and 's' for seconds, e.g. '365d'. Do not use this option in conjunction with the --expires-on option.", + Resources.CreateCommand_ValidForOption_Description, CommandOptionType.SingleValue); cmd.HelpOption("-h|--help"); @@ -117,7 +115,7 @@ private static (JwtCreatorOptions, bool) ValidateArguments( var audience = audienceOption.HasValue() ? audienceOption.Values : DevJwtCliHelpers.GetAudienceCandidatesFromLaunchSettings(project).ToList(); if (audience is null) { - reporter.Error("Could not determine the project's HTTPS URL. Please specify an audience for the JWT using the --audience option."); + reporter.Error(Resources.CreateCommand_NoAudience_Error); isValid = false; } var issuer = issuerOption.HasValue() ? issuerOption.Value() : DevJwtsDefaults.Issuer; @@ -127,7 +125,7 @@ private static (JwtCreatorOptions, bool) ValidateArguments( { if (!ParseDate(notBeforeOption.Value(), out notBefore)) { - reporter.Error(@"The date provided for --not-before could not be parsed. Dates must consist of a date and can include an optional timestamp."); + reporter.Error(Resources.FormatCreateCommand_InvalidDate_Error("--not-before")); isValid = false; } } @@ -137,7 +135,7 @@ private static (JwtCreatorOptions, bool) ValidateArguments( { if (!ParseDate(expiresOnOption.Value(), out expiresOn)) { - reporter.Error(@"The date provided for --expires-on could not be parsed. Dates must consist of a date and can include an optional timestamp."); + reporter.Error(Resources.FormatCreateCommand_InvalidDate_Error("--expires-on")); isValid = false; } } @@ -146,7 +144,7 @@ private static (JwtCreatorOptions, bool) ValidateArguments( { if (!TimeSpan.TryParseExact(validForOption.Value(), _timeSpanFormats, CultureInfo.InvariantCulture, out var validForValue)) { - reporter.Error("The period provided for --valid-for could not be parsed. Ensure you use a format like '10d', '22h', '45s' etc."); + reporter.Error(Resources.FormatCreateCommand_InvalidPeriod_Error("--valid-for")); } expiresOn = notBefore.Add(validForValue); } @@ -159,7 +157,7 @@ private static (JwtCreatorOptions, bool) ValidateArguments( { if (!DevJwtCliHelpers.TryParseClaims(claimsOption.Values, out claims)) { - reporter.Error("Malformed claims supplied. Ensure each claim is in the format \"name=value\"."); + reporter.Error(Resources.CreateCommand_InvalidClaims_Error); isValid = false; } } @@ -197,7 +195,7 @@ private static int Execute( var settingsToWrite = new JwtAuthenticationSchemeSettings(options.Scheme, options.Audiences, options.Issuer); settingsToWrite.Save(appsettingsFilePath); - reporter.Output($"New JWT saved with ID '{jwtToken.Id}'."); + reporter.Output(Resources.FormatCreateCommand_Confirmed(jwtToken.Id)); return 0; } diff --git a/src/Tools/dotnet-user-jwts/src/Commands/KeyCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/KeyCommand.cs index 1637d7d7f6ed..a90eb4df14c8 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/KeyCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/KeyCommand.cs @@ -13,16 +13,16 @@ public static void Register(ProjectCommandLineApplication app) { app.Command("key", cmd => { - cmd.Description = "Display or reset the signing key used to issue JWTs"; + cmd.Description = Resources.KeyCommand_Description; var resetOption = cmd.Option( "--reset", - "Reset the signing key. This will invalidate all previously issued JWTs for this project.", + Resources.KeyCommand_ResetOption_Description, CommandOptionType.NoValue); var forceOption = cmd.Option( "--force", - "Don't prompt for confirmation before resetting the signing key.", + Resources.KeyCommand_ForceOption_Description, CommandOptionType.NoValue); cmd.HelpOption("-h|--help"); @@ -45,16 +45,17 @@ private static int Execute(IReporter reporter, string projectPath, bool reset, b { if (!force) { - reporter.Output("Are you sure you want to reset the JWT signing key? This will invalidate all JWTs previously issued for this project.\n [Y]es / [N]o"); + reporter.Output(Resources.KeyCommand_Permission); + reporter.Error("[Y]es / [N]o"); if (Console.ReadLine().Trim().ToUpperInvariant() != "Y") { - reporter.Output("Key reset canceled."); + reporter.Output(Resources.KeyCommand_Canceled); return 0; } } var key = DevJwtCliHelpers.CreateSigningKeyMaterial(userSecretsId, reset: true); - reporter.Output($"New signing key created: {Convert.ToBase64String(key)}"); + reporter.Output(Resources.FormatKeyCommand_KeyCreated(Convert.ToBase64String(key))); return 0; } @@ -65,11 +66,11 @@ private static int Execute(IReporter reporter, string projectPath, bool reset, b if (signingKeyMaterial is null) { - reporter.Output("Signing key for JWTs was not found. One will be created automatically when the first JWT is created, or you can force creation of a key with the --reset option."); + reporter.Output(Resources.KeyCommand_KeyNotFound); return 0; } - reporter.Output($"Signing Key: {signingKeyMaterial}"); + reporter.Output(Resources.FormatKeyCommand_Confirmed(signingKeyMaterial)); return 0; } } diff --git a/src/Tools/dotnet-user-jwts/src/Commands/ListCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/ListCommand.cs index 8013e298997f..f74c67a3f4b4 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/ListCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/ListCommand.cs @@ -12,11 +12,11 @@ public static void Register(ProjectCommandLineApplication app) { app.Command("list", cmd => { - cmd.Description = "Lists the JWTs issued for the project"; + cmd.Description = Resources.ListCommand_Description; var showTokensOption = cmd.Option( "--show-tokens", - "Indicates whether JWT base64 strings should be shown", + Resources.ListCommand_ShowTokenOption_Description, CommandOptionType.NoValue); cmd.HelpOption("-h|--help"); @@ -36,8 +36,8 @@ private static int Execute(IReporter reporter, string projectPath, bool showToke } var jwtStore = new JwtStore(userSecretsId); - reporter.Output($"Project: {project}"); - reporter.Output($"User Secrets ID: {userSecretsId}"); + reporter.Output(Resources.FormatListCommand_Project(project)); + reporter.Output(Resources.FormatListCommand_UserSecretsId(userSecretsId)); if (jwtStore.Jwts is { Count: > 0 } jwts) { @@ -66,7 +66,7 @@ private static int Execute(IReporter reporter, string projectPath, bool showToke } else { - reporter.Output("No JWTs created yet!"); + reporter.Output(Resources.ListCommand_NoJwts); } return 0; diff --git a/src/Tools/dotnet-user-jwts/src/Commands/PrintCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/PrintCommand.cs index 3d144b9c5001..2842c13ef832 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/PrintCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/PrintCommand.cs @@ -12,13 +12,13 @@ public static void Register(ProjectCommandLineApplication app) { app.Command("print", cmd => { - cmd.Description = "Print the details of a given JWT"; + cmd.Description = Resources.PrintCommand_Description; - var idArgument = cmd.Argument("[id]", "The ID of the JWT to print"); + var idArgument = cmd.Argument("[id]", Resources.PrintCommand_IdArgument_Description); var showFullOption = cmd.Option( "--show-full", - "Whether to show the full JWT contents in addition to the compact serialized format", + Resources.PrintCommand_ShowFullOption_Description, CommandOptionType.NoValue); cmd.HelpOption("-h|--help"); @@ -43,14 +43,13 @@ private static int Execute(IReporter reporter, string projectPath, string id, bo } var jwtStore = new JwtStore(userSecretsId); - if (!jwtStore.Jwts.ContainsKey(id)) + if (!jwtStore.Jwts.TryGetValue(id, out var jwt)) { - reporter.Output($"No token with ID '{id}' found"); + reporter.Output(Resources.FormatPrintCommand_NoJwtFound(id)); return 1; } - reporter.Output($"Found JWT with ID '{id}'"); - var jwt = jwtStore.Jwts[id]; + reporter.Output(Resources.FormatPrintCommand_Confirmed(id)); JwtSecurityToken fullToken; if (showFull) diff --git a/src/Tools/dotnet-user-jwts/src/Commands/ProjectCommandLineApplication.cs b/src/Tools/dotnet-user-jwts/src/Commands/ProjectCommandLineApplication.cs index a15391cc99b6..497543297a76 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/ProjectCommandLineApplication.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/ProjectCommandLineApplication.cs @@ -17,7 +17,7 @@ public ProjectCommandLineApplication(IReporter reporter, bool throwOnUnexpectedA { ProjectOption = Option( "-p|--project", - "The path of the project to operate on. Defaults to the project in the current directory", + Resources.ProjectOption_Description, CommandOptionType.SingleValue); Reporter = reporter; } diff --git a/src/Tools/dotnet-user-jwts/src/Commands/DeleteCommand.cs b/src/Tools/dotnet-user-jwts/src/Commands/RemoveCommand.cs similarity index 79% rename from src/Tools/dotnet-user-jwts/src/Commands/DeleteCommand.cs rename to src/Tools/dotnet-user-jwts/src/Commands/RemoveCommand.cs index 83b287b81a2f..1efa3beed86a 100644 --- a/src/Tools/dotnet-user-jwts/src/Commands/DeleteCommand.cs +++ b/src/Tools/dotnet-user-jwts/src/Commands/RemoveCommand.cs @@ -6,15 +6,15 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer.Tools; -internal sealed class DeleteCommand +internal sealed class RemoveCommand { public static void Register(ProjectCommandLineApplication app) { - app.Command("delete", cmd => + app.Command("remove", cmd => { - cmd.Description = "Delete a given JWT"; + cmd.Description = Resources.RemoveCommand_Description; - var idArgument = cmd.Argument("[id]", "The ID of the JWT to delete"); + var idArgument = cmd.Argument("[id]", Resources.RemoveCommand_IdArgument_Description); cmd.HelpOption("-h|--help"); cmd.OnExecute(() => @@ -39,7 +39,7 @@ private static int Execute(IReporter reporter, string projectPath, string id) if (!jwtStore.Jwts.ContainsKey(id)) { - reporter.Error($"[ERROR] No JWT with ID '{id}' found"); + reporter.Error(Resources.FormatRemoveCommand_NoJwtFound(id)); return 1; } @@ -49,7 +49,7 @@ private static int Execute(IReporter reporter, string projectPath, string id) jwtStore.Jwts.Remove(id); jwtStore.Save(); - reporter.Output($"Deleted JWT with ID '{id}'"); + reporter.Output(Resources.FormatRemoveCommand_Confirmed(id)); return 0; } diff --git a/src/Tools/dotnet-user-jwts/src/Helpers/DevJwtCliHelpers.cs b/src/Tools/dotnet-user-jwts/src/Helpers/DevJwtCliHelpers.cs index 40e35506b27c..e34a017553c3 100644 --- a/src/Tools/dotnet-user-jwts/src/Helpers/DevJwtCliHelpers.cs +++ b/src/Tools/dotnet-user-jwts/src/Helpers/DevJwtCliHelpers.cs @@ -135,7 +135,7 @@ public static string[] GetAudienceCandidatesFromLaunchSettings(string project) var value = applicationUrl.GetString(); if (value is { } applicationUrls) { - return applicationUrls.Split(";"); + return applicationUrls.Split(';'); } } } diff --git a/src/Tools/dotnet-user-jwts/src/Program.cs b/src/Tools/dotnet-user-jwts/src/Program.cs index 24d2ea9dafbe..5d64717ccdb6 100644 --- a/src/Tools/dotnet-user-jwts/src/Program.cs +++ b/src/Tools/dotnet-user-jwts/src/Program.cs @@ -37,8 +37,8 @@ public void Run(string[] args) CreateCommand.Register(userJwts); // dotnet user-jwts print ecd045 PrintCommand.Register(userJwts); - // dotnet user-jwts delete ecd045 - DeleteCommand.Register(userJwts); + // dotnet user-jwts remove ecd045 + RemoveCommand.Register(userJwts); // dotnet user-jwts clear ClearCommand.Register(userJwts); // dotnet user-jwts key diff --git a/src/Tools/dotnet-user-jwts/src/Resources.resx b/src/Tools/dotnet-user-jwts/src/Resources.resx new file mode 100644 index 000000000000..b8b95ba88d07 --- /dev/null +++ b/src/Tools/dotnet-user-jwts/src/Resources.resx @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Canceled! No JWTs were deleted. + + + Deleted {0} token(s) from '{1}' successfully. + + + Remove all issued JWTs for a project + + + Don't prompt for confirmation before deleting JWTs. + + + There are no JWTs to delete from '{0}'. + + + Are you sure you want to delete {0} JWT(s) for '{1}'? + + + The audiences to create the JWT for. Defaults to the URLs configured in the project's launchSettings.json. + + + Claims to add to the JWT. Specify once for each claim in the format "name=value". + + + New JWT saved with ID '{id}'. + + + Issue a new JSON Web Token + + + The UTC date & time the JWT should expire in the format 'yyyy-MM-dd [[[[HH:mm]]:ss]]'. Defaults to 6 months after the --not-before date. Do not use this option in conjunction with the --valid-for option. + + + Malformed claims supplied. Ensure each claim is in the format "name=value". + + + The date provided for '{type}' could not be parsed. Dates must consist of a date and can include an optional timestamp. + + + The period provided for '{0}' could not be parsed. Ensure you use a format like '10d', '22h', '45s' etc. + + + The issuer of the JWT. Defaults to 'dotnet-user-jwts'. + + + The name of the user to create the JWT for. Defaults to the current environment user. + + + Could not determine the project's HTTPS URL. Please specify an audience for the JWT using the --audience option. + + + The UTC date & time the JWT should not be valid before in the format 'yyyy-MM-dd [[HH:mm[[:ss]]]]'. Defaults to the date & time the JWT is created. + + + A role claim to add to the JWT. Specify once for each role. + + + The scheme name to use for the generated token. Defaults to 'Bearer'. + + + A scope claim to add to the JWT. Specify once for each scope. + + + The period the JWT should expire after. Specify using a number followed by a duration type like 'd' for days, 'h' for hours, 'm' for minutes, and 's' for seconds, e.g. '365d'. Do not use this option in conjunction with the --expires-on option. + + + Key reset canceled. + + + Signing Key: '{0}' + + + Display or reset the signing key used to issue JWTs + + + Don't prompt for confirmation before resetting the signing key. + + + New signing key created: '{0}' + + + Signing key for JWTs was not found. One will be created automatically when the first JWT is created, or you can force creation of a key with the --reset option. + + + Are you sure you want to reset the JWT signing key? This will invalidate all JWTs previously issued for this project. + + + Reset the signing key. This will invalidate all previously issued JWTs for this project. + + + Lists the JWTs issued for the project + + + No JWTs created yet! + + + Project: '{0}' + + + Indicates whether JWT base64 strings should be shown. + + + User Secrets ID: '{0}' + + + Found JWT with ID '{0}'. + + + Print the details of a given JWT + + + The ID of the JWT to print. + + + No token with ID '{0}' found. + + + Whether to show the full JWT contents in addition to the compact serialized format. + + + The path of the project to operate on. Defaults to the project in the current directory. + + + Deleted JWT with ID '{0}'. + + + Remove a given JWT + + + The ID of the JWT to delete. + + + No JWT with ID '{0}' found. + + \ No newline at end of file diff --git a/src/Tools/dotnet-user-jwts/test/UserJwtsTests.cs b/src/Tools/dotnet-user-jwts/test/UserJwtsTests.cs index ac0cf3d95723..413b8503987e 100644 --- a/src/Tools/dotnet-user-jwts/test/UserJwtsTests.cs +++ b/src/Tools/dotnet-user-jwts/test/UserJwtsTests.cs @@ -95,7 +95,7 @@ public void List_ReturnsIdForGeneratedToken() } [Fact] - public void Delete_RemovesGeneratedToken() + public void Remove_RemovesGeneratedToken() { var project = Path.Combine(_fixture.CreateProject(), "TestProject.csproj"); var appsettings = Path.Combine(Path.GetDirectoryName(project), "appsettings.Development.json"); @@ -106,7 +106,7 @@ public void Delete_RemovesGeneratedToken() var id = matches.SingleOrDefault().Groups[1].Value; app.Run(new[] { "create", "--project", project, "--scheme", "Scheme2" }); - app.Run(new[] { "delete", id, "--project", project }); + app.Run(new[] { "remove", id, "--project", project }); var appsettingsContent = File.ReadAllText(appsettings); Assert.DoesNotContain("Bearer", appsettingsContent); Assert.Contains("Scheme2", appsettingsContent);