From d6d6f096d7838b059ac9e57b213f9692281f5f20 Mon Sep 17 00:00:00 2001 From: GZTime Date: Fri, 11 Aug 2023 03:08:10 +0800 Subject: [PATCH] fix(k8s): add ToValidRFC1123String --- src/GZCTF/Models/Data/Challenge.cs | 2 +- src/GZCTF/Models/Data/Game.cs | 2 +- src/GZCTF/Models/Data/Post.cs | 2 +- src/GZCTF/Services/DockerService.cs | 2 +- src/GZCTF/Services/K8sService.cs | 13 +--- src/GZCTF/Utils/Codec.cs | 108 +++++++++++++++++----------- 6 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/GZCTF/Models/Data/Challenge.cs b/src/GZCTF/Models/Data/Challenge.cs index e8a5eb9fe..0464fa541 100644 --- a/src/GZCTF/Models/Data/Challenge.cs +++ b/src/GZCTF/Models/Data/Challenge.cs @@ -214,7 +214,7 @@ internal string GenerateFlag(Participation part) // for third-party flag calculation and external distribution. // To address this issue, one possible solution is to use a salted hash of // the private key as the salt for the team's hash. - var hash = Codec.StrSHA256($"{part.Token}::{part.Game.TeamHashSalt}::{Id}"); + var hash = $"{part.Token}::{part.Game.TeamHashSalt}::{Id}".StrSHA256(); return flag.Replace("[TEAM_HASH]", hash[12..24]); } diff --git a/src/GZCTF/Models/Data/Game.cs b/src/GZCTF/Models/Data/Game.cs index 0ca3f5340..d27f86f9f 100644 --- a/src/GZCTF/Models/Data/Game.cs +++ b/src/GZCTF/Models/Data/Game.cs @@ -169,7 +169,7 @@ public class Game public string? PosterUrl => PosterHash is null ? null : $"/assets/{PosterHash}/poster"; [NotMapped] - public string TeamHashSalt => Codec.StrSHA256($"GZCTF@{PrivateKey}@PK"); + public string TeamHashSalt => $"GZCTF@{PrivateKey}@PK".StrSHA256(); internal void GenerateKeyPair(byte[]? xorkey) { diff --git a/src/GZCTF/Models/Data/Post.cs b/src/GZCTF/Models/Data/Post.cs index 3472772aa..e4d98204e 100644 --- a/src/GZCTF/Models/Data/Post.cs +++ b/src/GZCTF/Models/Data/Post.cs @@ -71,5 +71,5 @@ internal Post Update(PostEditModel model, UserInfo user) return this; } - internal void UpdateKeyWithHash() => Id = Codec.StrSHA256($"{Title}:{UpdateTimeUTC:s}:{Guid.NewGuid()}")[4..12]; + internal void UpdateKeyWithHash() => Id = $"{Title}:{UpdateTimeUTC:s}:{Guid.NewGuid()}".StrSHA256()[4..12]; } diff --git a/src/GZCTF/Services/DockerService.cs b/src/GZCTF/Services/DockerService.cs index 52b78172a..5ed8c6eeb 100644 --- a/src/GZCTF/Services/DockerService.cs +++ b/src/GZCTF/Services/DockerService.cs @@ -78,7 +78,7 @@ public async Task DestroyContainerAsync(Container container, CancellationToken t } private static string GetName(ContainerConfig config) - => $"{config.Image.Split("/").LastOrDefault()?.Split(":").FirstOrDefault()}_{Codec.StrMD5(config.Flag ?? Guid.NewGuid().ToString())[..16]}"; + => $"{config.Image.Split("/").LastOrDefault()?.Split(":").FirstOrDefault()}_{(config.Flag ?? Guid.NewGuid().ToString()).StrMD5()[..16]}"; private static CreateContainerParameters GetCreateContainerParameters(ContainerConfig config) => new() diff --git a/src/GZCTF/Services/K8sService.cs b/src/GZCTF/Services/K8sService.cs index 302b3e25f..9abc55f39 100644 --- a/src/GZCTF/Services/K8sService.cs +++ b/src/GZCTF/Services/K8sService.cs @@ -47,8 +47,8 @@ public K8sService(IOptions _registry, IOptions _registry, IOptions + /// 转换为对应进制 + /// + /// 源数据 + /// 进制支持2,8,10,16 + /// + public static List ToBase(List source, int tobase) + => new(source.ConvertAll((a) => Convert.ToString(a, tobase))); + /// /// 字节数组转换为16进制字符串 /// @@ -218,12 +227,62 @@ public static byte[] Xor(byte[] data, byte[] xor) return res; } + /// + /// 将文件打包为 zip 文件 + /// + /// 文件列表 + /// 根目录 + /// 压缩包根目录 + /// + /// + public async static Task ZipFilesAsync(IEnumerable files, string basepath, string zipName, CancellationToken token = default) + { + var size = files.Select(f => f.FileSize).Sum(); + + Stream tmp = size <= 64 * 1024 * 1024 ? new MemoryStream() : + File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); + + using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); + + foreach (var file in files) + { + var entry = zip.CreateEntry(Path.Combine(zipName, file.Name), CompressionLevel.Optimal); + await using var entryStream = entry.Open(); + await using var fileStream = File.OpenRead(Path.Combine(basepath, file.Location, file.Hash)); + await fileStream.CopyToAsync(entryStream, token); + } + + await tmp.FlushAsync(token); + return tmp; + } +} + +public static partial class CodecExtensions +{ + + [GeneratedRegex("[^a-zA-Z0-9]+")] + private static partial Regex RFC1123ReplacePattern(); + + /// + /// 将字符串转换为符合 RFC1123 要求的字符串 + /// + /// + /// 若开头为数字则添加的字符串 + /// + public static string ToValidRFC1123String(this string str, string leading = "name") + { + var ret = RFC1123ReplacePattern().Replace(str, "-").Trim('-').ToLowerInvariant(); + if (ret.Length > 0 && char.IsDigit(ret[0])) + return $"{leading}-{ret}"; + return ret; + } + /// /// 获取字符串ASCII数组 /// /// 原字符串 /// - public static List ASCII(string str) + public static List ASCII(this string str) { var buff = Encoding.ASCII.GetBytes(str); List res = new(); @@ -232,21 +291,12 @@ public static List ASCII(string str) return res; } - /// - /// 转换为对应进制 - /// - /// 源数据 - /// 进制支持2,8,10,16 - /// - public static List ToBase(List source, int tobase) - => new(source.ConvertAll((a) => Convert.ToString(a, tobase))); - /// /// 反转字符串 /// /// 原字符串 /// - public static string Reverse(string s) + public static string Reverse(this string s) { var charArray = s.ToCharArray(); Array.Reverse(charArray); @@ -259,7 +309,7 @@ public static string Reverse(string s) /// 原始字符串 /// 是否使用Base64编码 /// - public static string StrMD5(string str, bool useBase64 = false) + public static string StrMD5(this string str, bool useBase64 = false) { var output = MD5.HashData(Encoding.Default.GetBytes(str)); if (useBase64) @@ -273,7 +323,7 @@ public static string StrMD5(string str, bool useBase64 = false) /// 原始字符串 /// 是否使用Base64编码 /// - public static string StrSHA256(string str, bool useBase64 = false) + public static string StrSHA256(this string str, bool useBase64 = false) { var output = SHA256.HashData(Encoding.Default.GetBytes(str)); if (useBase64) @@ -286,7 +336,7 @@ public static string StrSHA256(string str, bool useBase64 = false) /// /// 原始字符串 /// - public static byte[] BytesMD5(string str) + public static byte[] BytesMD5(this string str) => MD5.HashData(Encoding.Default.GetBytes(str)); /// @@ -294,35 +344,7 @@ public static byte[] BytesMD5(string str) /// /// 原始字符串 /// - public static byte[] BytesSHA256(string str) + public static byte[] BytesSHA256(this string str) => SHA256.HashData(Encoding.Default.GetBytes(str)); - /// - /// 将文件打包为 zip 文件 - /// - /// 文件列表 - /// 根目录 - /// 压缩包根目录 - /// - /// - public async static Task ZipFilesAsync(IEnumerable files, string basepath, string zipName, CancellationToken token = default) - { - var size = files.Select(f => f.FileSize).Sum(); - - Stream tmp = size <= 64 * 1024 * 1024 ? new MemoryStream() : - File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose); - - using var zip = new ZipArchive(tmp, ZipArchiveMode.Create, true); - - foreach (var file in files) - { - var entry = zip.CreateEntry(Path.Combine(zipName, file.Name), CompressionLevel.Optimal); - await using var entryStream = entry.Open(); - await using var fileStream = File.OpenRead(Path.Combine(basepath, file.Location, file.Hash)); - await fileStream.CopyToAsync(entryStream, token); - } - - await tmp.FlushAsync(token); - return tmp; - } }