using System; using System.Text.RegularExpressions; namespace BulkArchiveMailer.Core { /// Result of successfully parsing an archive file name. public sealed class ParsedFilename { public ParsedFilename(string login, string suffix) { Login = login; Suffix = suffix; } /// Lower-cased login exactly as it appears in the file name (hyphens intact). public string Login { get; } /// /// Lower-cased suffix exactly as it appears in the file name (the /// part between the login and ".7z"), e.g. "ssh_access" or /// "config_update" for the two built-in templates, or whatever /// FileSuffix a custom template in AppSettingsData.Templates uses. /// Whether this suffix corresponds to any *configured* template is /// NOT checked here - that is ArchiveScanner's job, since it is the /// one holding the list of templates. /// public string Suffix { get; } } /// /// Parses the generic "{login}_{suffix}.7z" file name shape /// ssh-access-tui produces (see internal/keymgr/pack.go and /// internal/keymgr/configonly.go in the main repo for the producing /// side, and config.default.json/SettingsForm for how an operator adds /// further suffixes via custom templates). Anything else (wrong /// extension, no underscore-separated suffix, stray file dropped in the /// export folder by a human) simply fails to parse - the caller /// (ArchiveScanner) is responsible for routing that into the /// "unrecognized" bucket instead of blocking the batch. Whether a /// syntactically valid suffix actually matches a configured template is /// also ArchiveScanner's job, not this parser's. /// public static class FilenameParser { // Matches the login part ssh-access-tui itself accepts for a Linux // username: lowercase alnum segments joined by single hyphens (no // leading/trailing/double hyphens), followed by an underscore and // any lowercase alnum/underscore suffix. Case-insensitive purely as // a defensive measure in case a file was renamed by hand on a // case-insensitive filesystem; the captured login/suffix are // normalized to lower case before use. private static readonly Regex Pattern = new Regex( @"^(?[a-z0-9]+(?:-[a-z0-9]+)*)_(?[a-z0-9_]+)\.7z$", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static bool TryParse(string fileName, out ParsedFilename parsed) { parsed = null; if (string.IsNullOrEmpty(fileName)) { return false; } var match = Pattern.Match(fileName); if (!match.Success) { return false; } var login = match.Groups["login"].Value.ToLowerInvariant(); var suffix = match.Groups["suffix"].Value.ToLowerInvariant(); parsed = new ParsedFilename(login, suffix); return true; } } }