From 7c0f24df65afd8446da9a1e4c479ecb2d41796d8 Mon Sep 17 00:00:00 2001 From: Heiko <61519853+htcfreek@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:30:11 +0100 Subject: [PATCH] [PTRun][ValueGenerator]Add URI/URL features (#30648) * move existing generator classes * add new generators * implement new generators * fixes * improvements * shorten query tags * make spellcheck happy * add tests * dev docs * fix typos * fix tests --- .github/actions/spell-check/expect.txt | 3 + .../plugins/community.valuegenerator.md | 40 ++++++++++-- .../InputParserTests.cs | 30 +++++++-- .../Base64/Base64DecodeRequest.cs | 0 .../{ => Generators}/Base64/Base64Request.cs | 0 .../{ => Generators}/GUID/GUIDGenerator.cs | 0 .../{ => Generators}/GUID/GUIDRequest.cs | 0 .../{ => Generators}/Hashing/HashRequest.cs | 0 .../Generators/Uri/DataEscapeRequest.cs | 50 +++++++++++++++ .../Generators/Uri/DataUnescapeRequest.cs | 58 +++++++++++++++++ .../Generators/Uri/HexEscapeRequest.cs | 58 +++++++++++++++++ .../Generators/Uri/HexUnescapeRequest.cs | 62 ++++++++++++++++++ .../Generators/Uri/UrlDecodeRequest.cs | 60 +++++++++++++++++ .../Generators/Uri/UrlEncodeRequest.cs | 52 +++++++++++++++ .../InputParser.cs | 64 +++++++++++++++++++ .../Main.cs | 11 +++- 16 files changed, 475 insertions(+), 13 deletions(-) rename src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/{ => Generators}/Base64/Base64DecodeRequest.cs (100%) rename src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/{ => Generators}/Base64/Base64Request.cs (100%) rename src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/{ => Generators}/GUID/GUIDGenerator.cs (100%) rename src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/{ => Generators}/GUID/GUIDRequest.cs (100%) rename src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/{ => Generators}/Hashing/HashRequest.cs (100%) create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 2091f78ed3..f00870c928 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1600,6 +1600,7 @@ UAL uap udit uefi +uesc UHash UIA UIEx @@ -1608,6 +1609,7 @@ ums uncompilable UNCPRIORITY UNDNAME +unescape UNICODETEXT uninstantiated uniquifier @@ -1626,6 +1628,7 @@ UOI Updatelayout UPGRADINGPRODUCTCODE Uptool +urld Usb USEDEFAULT USEFILEATTRIBUTES diff --git a/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md b/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md index 379e7d4894..4a580f090d 100644 --- a/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md +++ b/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md @@ -1,6 +1,6 @@ # Value Generator Plugin -The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings and to generate GUIDs versions 1, 3, 4 and 5. +The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs versions 1, 3, 4 and 5. ![Image of Value Generator plugin](/doc/images/launcher/plugin/community.valuegenerator.png) @@ -10,7 +10,7 @@ The Value Generator plugin is used to generate hashes for strings, to calculate - The result of `string ResultToString()` will be used for the Result's title - The `Description` field will be used for the Result's subtitle -### [`HashRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Hashing/HashRequest.cs) +### [`HashRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Hashing/HashRequest.cs) - Implements IComputeRequest - Supports the hashing algorithms from System.Security.Cryptography: - MD5 @@ -20,19 +20,19 @@ The Value Generator plugin is used to generate hashes for strings, to calculate - SHA512 - If other algorithms are added to System.Security.Cryptography, they can be added to the `_algorithms` dictionary. [`InputParser.ParseInput()`](#inputparser) will need to return a `HashRequest` for the algorithm in the query -### [`Base64Request`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64Request.cs) +### [`Base64Request`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64Request.cs) - Implements IComputeRequest - `Compute()` will populate `Result` with the base64 encoding of the byte array passed in the constructor -### [`Base64DecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64DecodeRequest.cs) +### [`Base64DecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64DecodeRequest.cs) - Implements IComputeRequest - `Compute()` will populate `Result` with the decoded byte array of the base64 string passed in the constructor -### [`GUIDRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDRequest.cs) +### [`GUIDRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDRequest.cs) - Implements IComputeRequest - Uses the [`GUIDGenerator`](#guidgenerator) class to generate or compute the requested GUID -### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDGenerator.cs) +### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs) - Utility class for generating or calculating GUIDs - Generating GUID versions 1 and 4 is done using builtin APIs. [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 and `System.Guid.NewGuid()` for version 4 - Versions 3 and 5 take two parameters, a namespace and a name @@ -40,6 +40,32 @@ The Value Generator plugin is used to generate hashes for strings, to calculate - The `PredefinedNamespaces` dictionary contains aliases for the predefined namespaces - The name can be any string +### [`UrlEncodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the encoded url converted using `HttpUtility.UrlEncode()`. + +### [`UrlDecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the decoded url converted using `HttpUtility.UrlDecode()`. + +### [`DataEscapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the escaped data string converted using `System.Uri.EscapeDataString()`. + +### [`DataUnescapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the unescaped data string converted using `System.Uri.UnescapeDataString()`. + +### [`HexEscapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the escaped data string converted using `System.Uri.HexEscape()`. +- Only single characters are supported as input. + +### [`HexUnescapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs) +- Implements IComputeRequest +- `Compute()` will populate `Result` with the unescaped data string converted using `System.Uri.HexUnescape()`. +- Only the first hexadecimal character in the string gets unescaped. The rest of the user input is ignored. + ### [`InputParser`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs) - It is responsible only for parsing the query from the user - Based on the user query, the `ParseInput()` method must return an object that implements the `IComputeRequest` interface or it must throw one of `FormatException` or `ArgumentException` @@ -51,6 +77,6 @@ The Value Generator plugin is used to generate hashes for strings, to calculate > The error message will not be shown to the user but a log message will be created ### Adding a new value generator -1. To add a new value generator, create a folder under `/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/` and inside it add a class that implements `IComputeRequest`. +1. To add a new value generator, create a folder under `/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/` and inside it add a class that implements `IComputeRequest`. 2. Add any utility classes that are specific to the new generator inside the same folder to keep them separated from the other generators. 3. Modify the `InputParser.ParseInput()` to handle a request for the new generator and return an instance of the class you created in step 1 \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests/InputParserTests.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests/InputParserTests.cs index afc2d0232d..b6794611ee 100644 --- a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests/InputParserTests.cs +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests/InputParserTests.cs @@ -30,12 +30,23 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests [DataRow("base99 abc", null)] [DataRow("base64s abc", null)] [DataRow("base64d abc=", typeof(Base64.Base64DecodeRequest))] - public void ParserTest(string input, Type? expectedRequestType) + [DataRow("url http://googl.de/u oii d", typeof(Uri.UrlEncodeRequest))] + [DataRow("urld http://googl.de/u oii d=oo", typeof(Uri.UrlDecodeRequest))] + [DataRow("esc:data jjdje332j 3 3l2jl32", typeof(Uri.DataEscapeRequest))] + [DataRow("esc:hex d", typeof(Uri.HexEscapeRequest))] + [DataRow("esc:hex 4", typeof(Uri.HexEscapeRequest))] + [DataRow("esc:hex ", typeof(Uri.HexEscapeRequest), true)] + [DataRow("esc:hex z44", typeof(Uri.HexEscapeRequest), true)] + [DataRow("uesc:data jjdje332j 3 3l2jl32", typeof(Uri.DataUnescapeRequest))] + [DataRow("uesc:hex %21", typeof(Uri.HexUnescapeRequest))] + [DataRow("uesc:hex 4", typeof(Uri.HexUnescapeRequest))] + [DataRow("uesc:hex ", typeof(Uri.HexUnescapeRequest))] + [DataRow("uesc:hex z44", typeof(Uri.HexUnescapeRequest))] + public void ParserTest(string input, Type? expectedRequestType, bool expectException = false) { var parser = new InputParser(); var query = new Query(input); - var expectException = false; string? command = null; if (query.Terms.Count == 0) { @@ -79,15 +90,24 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests private static bool CommandIsKnown(string command) { string[] hashes = new string[] { "md5", "sha1", "sha256", "sha384", "sha512", "base64", "base64d" }; - if (hashes.Contains(command.ToLowerInvariant())) { return true; } - Regex regex = new Regex("^(guid|uuid)([1345]{0,1}|v[1345]{1})$", RegexOptions.IgnoreCase | RegexOptions.Compiled); + Regex regexGuiUUID = new Regex("^(guid|uuid)([1345]{0,1}|v[1345]{1})$", RegexOptions.IgnoreCase | RegexOptions.Compiled); + if (regexGuiUUID.IsMatch(command)) + { + return true; + } - return regex.IsMatch(command); + string[] uriCommands = new string[] { "url", "urld", "esc:hex", "uesc:hex", "esc:data", "uesc:data" }; + if (uriCommands.Contains(command.ToLowerInvariant())) + { + return true; + } + + return false; } } } diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64DecodeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64DecodeRequest.cs similarity index 100% rename from src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64DecodeRequest.cs rename to src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64DecodeRequest.cs diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64Request.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64Request.cs similarity index 100% rename from src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64Request.cs rename to src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64Request.cs diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDGenerator.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs similarity index 100% rename from src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDGenerator.cs rename to src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDRequest.cs similarity index 100% rename from src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDRequest.cs rename to src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDRequest.cs diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Hashing/HashRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Hashing/HashRequest.cs similarity index 100% rename from src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Hashing/HashRequest.cs rename to src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Hashing/HashRequest.cs diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs new file mode 100644 index 0000000000..cfe581a294 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class DataEscapeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Data string escaped"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToEscape { get; set; } + + public DataEscapeRequest(string dataToEscape) + { + DataToEscape = dataToEscape ?? throw new ArgumentNullException(nameof(dataToEscape)); + } + + public bool Compute() + { + IsSuccessful = true; + try + { + Result = Encoding.UTF8.GetBytes(System.Uri.EscapeDataString(DataToEscape)); + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + return Encoding.UTF8.GetString(Result); + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs new file mode 100644 index 0000000000..2de144d81e --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Text; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class DataUnescapeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Data string unescaped"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToUnescape { get; set; } + + public DataUnescapeRequest(string dataToUnescape) + { + DataToUnescape = dataToUnescape ?? throw new ArgumentNullException(nameof(dataToUnescape)); + } + + public bool Compute() + { + IsSuccessful = true; + try + { + Result = Encoding.UTF8.GetBytes(System.Uri.UnescapeDataString(DataToUnescape)); + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + if (Result != null) + { + return Encoding.UTF8.GetString(Result); + } + else + { + return string.Empty; + } + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs new file mode 100644 index 0000000000..7c47af69bc --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Text; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class HexEscapeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Hex escaped char"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToEscape { get; set; } + + public HexEscapeRequest(string dataToEscape) + { + DataToEscape = dataToEscape ?? throw new ArgumentNullException(nameof(dataToEscape)); + + // Validate that we have only one character + if (dataToEscape.Length != 1) + { + throw new ArgumentOutOfRangeException(nameof(dataToEscape)); + } + } + + public bool Compute() + { + IsSuccessful = true; + try + { + char charToEscape = DataToEscape[0]; + Result = Encoding.UTF8.GetBytes(System.Uri.HexEscape(charToEscape)); + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + return Encoding.UTF8.GetString(Result); + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs new file mode 100644 index 0000000000..8bd5e80ed0 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Text; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class HexUnescapeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Hex char unescaped"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToUnescape { get; set; } + + public HexUnescapeRequest(string dataToUnescape) + { + DataToUnescape = dataToUnescape ?? throw new ArgumentNullException(nameof(dataToUnescape)); + } + + public bool Compute() + { + IsSuccessful = true; + try + { + int index = 0; + if (System.Uri.IsHexEncoding(DataToUnescape, index)) + { + Result = Encoding.UTF8.GetBytes(System.Uri.HexUnescape(DataToUnescape, ref index).ToString()); + } + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + if (Result != null) + { + return Encoding.UTF8.GetString(Result); + } + else + { + return string.Empty; + } + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs new file mode 100644 index 0000000000..db26f7009a --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Security.Policy; +using System.Text; +using System.Web; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class UrlDecodeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Decoded URL"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToDecode { get; set; } + + public UrlDecodeRequest(string dataToDecode) + { + DataToDecode = dataToDecode ?? throw new ArgumentNullException(nameof(dataToDecode)); + } + + public bool Compute() + { + IsSuccessful = true; + try + { + Result = Encoding.UTF8.GetBytes(HttpUtility.UrlDecode(DataToDecode)); + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + if (Result != null) + { + return Encoding.UTF8.GetString(Result); + } + else + { + return string.Empty; + } + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs new file mode 100644 index 0000000000..1022cd702a --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Security.Policy; +using System.Text; +using System.Web; +using Wox.Plugin.Logger; + +namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri +{ + public class UrlEncodeRequest : IComputeRequest + { + public byte[] Result { get; set; } + + public string Description => "Encoded URL"; + + public bool IsSuccessful { get; set; } + + public string ErrorMessage { get; set; } + + private string DataToEncode { get; set; } + + public UrlEncodeRequest(string dataToEncode) + { + DataToEncode = dataToEncode ?? throw new ArgumentNullException(nameof(dataToEncode)); + } + + public bool Compute() + { + IsSuccessful = true; + try + { + Result = Encoding.UTF8.GetBytes(HttpUtility.UrlEncode(DataToEncode)); + } + catch (Exception e) + { + Log.Exception(e.Message, e, GetType()); + ErrorMessage = e.Message; + IsSuccessful = false; + } + + return IsSuccessful; + } + + public string ResultToString() + { + return Encoding.UTF8.GetString(Result); + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs index 59143fe203..929366f597 100644 --- a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs @@ -8,6 +8,7 @@ using System.Text; using Community.PowerToys.Run.Plugin.ValueGenerator.Base64; using Community.PowerToys.Run.Plugin.ValueGenerator.GUID; using Community.PowerToys.Run.Plugin.ValueGenerator.Hashing; +using Community.PowerToys.Run.Plugin.ValueGenerator.Uri; using Wox.Plugin; using Wox.Plugin.Logger; @@ -127,6 +128,69 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); request = new Base64DecodeRequest(content); } + else if (command.StartsWith("esc:", StringComparison.OrdinalIgnoreCase)) + { + // Escape things + if (command.Equals("esc:data", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + request = new DataEscapeRequest(content); + } + else if (command.Equals("esc:hex", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + + // This is only for single chars + if (content.Length > 1) + { + throw new ArgumentException($"Invalid Query: {query.RawUserQuery} (To many characters.)"); + } + else if (content.Length == 0) + { + throw new FormatException($"Invalid Query: {query.RawUserQuery}"); + } + + request = new HexEscapeRequest(content); + } + else + { + throw new FormatException($"Invalid Query: {query.RawUserQuery}"); + } + } + else if (command.StartsWith("uesc:", StringComparison.OrdinalIgnoreCase)) + { + // Unescape things + if (command.Equals("uesc:data", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + request = new DataUnescapeRequest(content); + } + else if (command.Equals("uesc:hex", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + request = new HexUnescapeRequest(content); + } + else + { + throw new FormatException($"Invalid Query: {query.RawUserQuery}"); + } + } + else if (command.Equals("url", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + request = new UrlEncodeRequest(content); + } + else if (command.Equals("urld", StringComparison.OrdinalIgnoreCase)) + { + int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase); + string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); + request = new UrlDecodeRequest(content); + } else { throw new FormatException($"Invalid Query: {query.RawUserQuery}"); diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Main.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Main.cs index 36536da303..1ed2186063 100644 --- a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Main.cs +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Main.cs @@ -93,7 +93,16 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator try { IComputeRequest computeRequest = _inputParser.ParseInput(query); - results.Add(GetResult(computeRequest)); + var result = GetResult(computeRequest); + + if (!string.IsNullOrEmpty(result.Title)) + { + results.Add(result); + } + else + { + return results; + } } catch (ArgumentException e) {