209 lines
7.4 KiB
C#
209 lines
7.4 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using AxCopilot.SDK;
|
|
using AxCopilot.Themes;
|
|
|
|
namespace AxCopilot.Handlers;
|
|
|
|
/// <summary>
|
|
/// 인코딩/해싱 변환 핸들러. "encode " 프리픽스로 사용합니다.
|
|
/// 예: encode base64 hello → aGVsbG8=
|
|
/// encode decode base64 aGVsbG8= → hello
|
|
/// encode url https://example.com → URL 인코딩
|
|
/// encode hex hello → 68656c6c6f
|
|
/// encode md5 hello → 5d41402abc4b2a76b9719d911017c592
|
|
/// encode sha256 hello → 2cf24dba...
|
|
/// encode sha1 hello → aaf4c61d...
|
|
/// encode (빈 쿼리) → 지원 목록
|
|
/// </summary>
|
|
public class EncodeHandler : IActionHandler
|
|
{
|
|
public string? Prefix => "encode "; // 뒤에 공백 포함
|
|
|
|
public PluginMetadata Metadata => new(
|
|
"Encoder",
|
|
"인코딩/해싱 — encode base64/url/hex/md5/sha256 텍스트",
|
|
"1.0",
|
|
"AX");
|
|
|
|
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
|
{
|
|
var q = query.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(q))
|
|
return Task.FromResult(HelpItems());
|
|
|
|
// "decode <타입> <값>" 파턴
|
|
if (q.StartsWith("decode ", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var rest = q[7..].Trim();
|
|
return Task.FromResult(HandleDecode(rest));
|
|
}
|
|
|
|
// "<타입> <값>" 패턴
|
|
var spaceIdx = q.IndexOf(' ');
|
|
if (spaceIdx < 0)
|
|
return Task.FromResult(HelpItems());
|
|
|
|
var type = q[..spaceIdx].Trim().ToLowerInvariant();
|
|
var input = q[(spaceIdx + 1)..];
|
|
|
|
return Task.FromResult(HandleEncode(type, input));
|
|
}
|
|
|
|
private static IEnumerable<LauncherItem> HandleEncode(string type, string input)
|
|
{
|
|
try
|
|
{
|
|
return type switch
|
|
{
|
|
"base64" or "b64" => SingleResult("Base64 인코딩",
|
|
Convert.ToBase64String(Encoding.UTF8.GetBytes(input))),
|
|
|
|
"url" => SingleResult("URL 인코딩",
|
|
Uri.EscapeDataString(input)),
|
|
|
|
"hex" => SingleResult("HEX 인코딩",
|
|
Convert.ToHexString(Encoding.UTF8.GetBytes(input)).ToLowerInvariant()),
|
|
|
|
"md5" => SingleResult("MD5 해시",
|
|
MD5Hash(input)),
|
|
|
|
"sha1" => SingleResult("SHA-1 해시",
|
|
SHA1Hash(input)),
|
|
|
|
"sha256" => SingleResult("SHA-256 해시",
|
|
SHA256Hash(input)),
|
|
|
|
"sha512" => SingleResult("SHA-512 해시",
|
|
SHA512Hash(input)),
|
|
|
|
"html" => SingleResult("HTML 엔티티 인코딩",
|
|
System.Net.WebUtility.HtmlEncode(input)),
|
|
|
|
_ =>
|
|
[
|
|
new LauncherItem(
|
|
$"알 수 없는 타입: {type}",
|
|
"base64, url, hex, md5, sha1, sha256, sha512, html 중 선택",
|
|
null, null, Symbol: Symbols.Warning)
|
|
]
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return
|
|
[
|
|
new LauncherItem("변환 오류", ex.Message, null, null, Symbol: Symbols.Error)
|
|
];
|
|
}
|
|
}
|
|
|
|
private static IEnumerable<LauncherItem> HandleDecode(string rest)
|
|
{
|
|
var spaceIdx = rest.IndexOf(' ');
|
|
if (spaceIdx < 0)
|
|
return [new LauncherItem("사용법: encode decode <타입> <값>", "타입: base64, url, hex, html", null, null, Symbol: Symbols.Info)];
|
|
|
|
var type = rest[..spaceIdx].Trim().ToLowerInvariant();
|
|
var input = rest[(spaceIdx + 1)..];
|
|
|
|
try
|
|
{
|
|
return type switch
|
|
{
|
|
"base64" or "b64" => SingleResult("Base64 디코딩",
|
|
Encoding.UTF8.GetString(Convert.FromBase64String(input))),
|
|
|
|
"url" => SingleResult("URL 디코딩",
|
|
Uri.UnescapeDataString(input)),
|
|
|
|
"hex" => SingleResult("HEX 디코딩",
|
|
Encoding.UTF8.GetString(Convert.FromHexString(input))),
|
|
|
|
"html" => SingleResult("HTML 엔티티 디코딩",
|
|
System.Net.WebUtility.HtmlDecode(input)),
|
|
|
|
_ =>
|
|
[
|
|
new LauncherItem(
|
|
$"디코딩 불가 타입: {type}",
|
|
"디코딩 지원: base64, url, hex, html",
|
|
null, null, Symbol: Symbols.Warning)
|
|
]
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return
|
|
[
|
|
new LauncherItem("디코딩 오류", ex.Message, null, null, Symbol: Symbols.Error)
|
|
];
|
|
}
|
|
}
|
|
|
|
private static IEnumerable<LauncherItem> SingleResult(string title, string result)
|
|
{
|
|
var preview = result.Length > 80 ? result[..77] + "…" : result;
|
|
return
|
|
[
|
|
new LauncherItem(
|
|
title,
|
|
$"{preview} · Enter로 복사",
|
|
null,
|
|
result,
|
|
Symbol: Symbols.EncodeIcon)
|
|
];
|
|
}
|
|
|
|
private static IEnumerable<LauncherItem> HelpItems()
|
|
{
|
|
return
|
|
[
|
|
new LauncherItem("encode base64 <텍스트>", "Base64 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode url <텍스트>", "URL 퍼센트 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode hex <텍스트>", "16진수 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode md5 <텍스트>", "MD5 해시 (단방향)", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode sha256 <텍스트>", "SHA-256 해시 (단방향)", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode html <텍스트>", "HTML 엔티티 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
|
|
new LauncherItem("encode decode base64 <값>", "Base64 디코딩 예시", null, null, Symbol: Symbols.EncodeIcon),
|
|
];
|
|
}
|
|
|
|
// ─── 해시 헬퍼 ─────────────────────────────────────────────────────────────
|
|
|
|
private static string MD5Hash(string input)
|
|
{
|
|
var bytes = MD5.HashData(Encoding.UTF8.GetBytes(input));
|
|
return Convert.ToHexString(bytes).ToLowerInvariant();
|
|
}
|
|
|
|
private static string SHA1Hash(string input)
|
|
{
|
|
var bytes = SHA1.HashData(Encoding.UTF8.GetBytes(input));
|
|
return Convert.ToHexString(bytes).ToLowerInvariant();
|
|
}
|
|
|
|
private static string SHA256Hash(string input)
|
|
{
|
|
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input));
|
|
return Convert.ToHexString(bytes).ToLowerInvariant();
|
|
}
|
|
|
|
private static string SHA512Hash(string input)
|
|
{
|
|
var bytes = SHA512.HashData(Encoding.UTF8.GetBytes(input));
|
|
return Convert.ToHexString(bytes).ToLowerInvariant();
|
|
}
|
|
|
|
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
|
{
|
|
if (item.Data is string text)
|
|
{
|
|
try { Clipboard.SetText(text); } catch (Exception) { }
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|