diff --git a/InfosysPublisher.sln b/InfosysPublisher.sln new file mode 100644 index 0000000..53edfa0 --- /dev/null +++ b/InfosysPublisher.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfosysPublisher", "InfosysPublisher\InfosysPublisher.csproj", "{96AECF20-EE37-45E8-BEA1-4C221E1E0BC7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96AECF20-EE37-45E8-BEA1-4C221E1E0BC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96AECF20-EE37-45E8-BEA1-4C221E1E0BC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96AECF20-EE37-45E8-BEA1-4C221E1E0BC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96AECF20-EE37-45E8-BEA1-4C221E1E0BC7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EA731043-FAF1-479E-8787-1E45190E5DC9} + EndGlobalSection +EndGlobal diff --git a/InfosysPublisher/App.xaml b/InfosysPublisher/App.xaml new file mode 100644 index 0000000..c3c539e --- /dev/null +++ b/InfosysPublisher/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/InfosysPublisher/App.xaml.cs b/InfosysPublisher/App.xaml.cs new file mode 100644 index 0000000..c958877 --- /dev/null +++ b/InfosysPublisher/App.xaml.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows; + +namespace InfosysPublisher +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/InfosysPublisher/AssemblyInfo.cs b/InfosysPublisher/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/InfosysPublisher/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/InfosysPublisher/Classes/Encryption.cs b/InfosysPublisher/Classes/Encryption.cs new file mode 100644 index 0000000..133b0b6 --- /dev/null +++ b/InfosysPublisher/Classes/Encryption.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace ResevalnaScanner.Classes +{ + internal static class Encryption + { + public enum Type + { + General, + Licence, + } + + public static string AesEncrypt(this string iPlain, Type iType = Type.General, string iKey = "", string iSalt = "") + { + if (iPlain.Length > 16 && iPlain.Length % 16 != 0) + { + var size = ((iPlain.Length / 16) + 1) * 16; + iPlain += new string(' ', size - iPlain.Length); + } + + switch (iType) + { + case Type.General: + iKey = "DEWSCYUSBP2AQ6JnMc_InfosysPublisher_S9Gj3GU4hchg7J38zZ"; + iSalt = "P4TqMkZ3FZd6Y5K5uNykmngCATDpP7PrxnACj2sFkfc6"; + break; + case Type.Licence: + iKey = "2D849KZ6RjpQCG_ResevalnaLicense_crKwBTjnskwycCvy7N"; + iSalt = "kUt7E6ngrYqA7watQ8YMPYNdzYFgLcCpuuchS96SZwC6"; + break; + } + + if (string.IsNullOrEmpty(iPlain)) + { + return ""; + } + + var saltByes = Encoding.ASCII.GetBytes(iSalt); + var key = new Rfc2898DeriveBytes(iKey, saltByes); + + var aesAlgorithm = Aes.Create(); + aesAlgorithm.KeySize = 256; + aesAlgorithm.Key = key.GetBytes(aesAlgorithm.KeySize / 8); + aesAlgorithm.IV = key.GetBytes(aesAlgorithm.BlockSize / 8); + + var msEncrypt = new MemoryStream(); + using (var encrypt = aesAlgorithm.CreateEncryptor(aesAlgorithm.Key, aesAlgorithm.IV)) + using (var csEncrypt = new CryptoStream(msEncrypt, encrypt, CryptoStreamMode.Write)) + { + using (var swEncrypt = new StreamWriter(csEncrypt)) + { + swEncrypt.Write(iPlain); + } + } + + return Convert.ToBase64String(msEncrypt.ToArray()); + } + + public static string AesDecrypt(this string iCipherText, Type iType = Type.General, string iKey = "", string iSalt = "") + { + switch (iType) + { + case Type.General: + iKey = "DEWSCYUSBP2AQ6JnMc_InfosysPublisher_S9Gj3GU4hchg7J38zZ"; + iSalt = "P4TqMkZ3FZd6Y5K5uNykmngCATDpP7PrxnACj2sFkfc6"; + break; + case Type.Licence: + iKey = "2D849KZ6RjpQCG_ResevalnaLicense_crKwBTjnskwycCvy7N"; + iSalt = "kUt7E6ngrYqA7watQ8YMPYNdzYFgLcCpuuchS96SZwC6"; + break; + } + + if (string.IsNullOrEmpty(iCipherText)) + { + return ""; + } + + var saltByes = Encoding.ASCII.GetBytes(iSalt); + var key = new Rfc2898DeriveBytes(iKey, saltByes); + + var aesAlgorithm = Aes.Create(); + aesAlgorithm.KeySize = 256; + aesAlgorithm.Key = key.GetBytes(aesAlgorithm.KeySize / 8); + aesAlgorithm.IV = key.GetBytes(aesAlgorithm.BlockSize / 8); + + var cipherTextBytes = Convert.FromBase64String(iCipherText); + var plainTextBytes = new byte[iCipherText.Length]; + var byteCount = 0; + + using (var decrypt = aesAlgorithm.CreateDecryptor(aesAlgorithm.Key, aesAlgorithm.IV)) + using (var msDecrypt = new MemoryStream(cipherTextBytes)) + using (var csDecrypt = new CryptoStream(msDecrypt, decrypt, CryptoStreamMode.Read)) + { + byteCount = csDecrypt.Read(plainTextBytes, 0, plainTextBytes.Length); + } + + return Encoding.UTF8.GetString(plainTextBytes, 0, byteCount).Trim(); + } + } +} diff --git a/InfosysPublisher/Classes/Settings.cs b/InfosysPublisher/Classes/Settings.cs new file mode 100644 index 0000000..2207ca6 --- /dev/null +++ b/InfosysPublisher/Classes/Settings.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; +using ResevalnaScanner.Classes; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace InfosysPublisher.Classes +{ + internal class Settings + { + public class Application + { + //SQL strežniki + //Privatna polja + [JsonProperty] private string _sftpUsername; + [JsonProperty] private string _sftpPassword; + + //Javna polja + public string SftpServerAddress { get; set; } + public int SftpPort { get; set; } + public int BuildSeconds { get; set; } + public string LastFolder { get; set; } + + [JsonIgnore] + public string SftpUsername + { + get => _sftpUsername.AesDecrypt(); + set => _sftpUsername = value.AesEncrypt(); + } + + [JsonIgnore] + public string SftpPassword + { + get => _sftpPassword.AesDecrypt(); + set => _sftpPassword = value.AesEncrypt(); + } + + public void Save(string iPath) + { + var json = JsonConvert.SerializeObject(this); + + if (!Directory.Exists(Path.GetDirectoryName(iPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(iPath)); + } + + File.WriteAllText(iPath, json); + } + } + } +} diff --git a/InfosysPublisher/InfosysPublisher.csproj b/InfosysPublisher/InfosysPublisher.csproj new file mode 100644 index 0000000..3521c28 --- /dev/null +++ b/InfosysPublisher/InfosysPublisher.csproj @@ -0,0 +1,27 @@ + + + + WinExe + net6.0-windows + enable + true + 1.0.1.0 + infosysPublisher.ico + + + + + + + + + + + + + + Always + + + + diff --git a/InfosysPublisher/WinMain.xaml b/InfosysPublisher/WinMain.xaml new file mode 100644 index 0000000..f493fb8 --- /dev/null +++ b/InfosysPublisher/WinMain.xaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pripravi samo zip + + + + diff --git a/InfosysPublisher/WinMain.xaml.cs b/InfosysPublisher/WinMain.xaml.cs new file mode 100644 index 0000000..ce8d710 --- /dev/null +++ b/InfosysPublisher/WinMain.xaml.cs @@ -0,0 +1,388 @@ +using InfosysPublisher.Classes; +using Newtonsoft.Json; +using Renci.SshNet; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Xml; +using Path = System.IO.Path; + +namespace InfosysPublisher +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + #region Classes + + public class Project + { + public string Name { get; set; } + public string Path { get; set; } + } + + #endregion + private Settings.Application? _application; + + + private string _projectPath; + private List _projects; + private Project? _selectedProject = null; + private string _selectedProjectSubPath = ""; + private string _selectedProjectPublishLocation = ""; + private string _selectedProjectVersion = ""; + + private const string SftpArchivePath = "Archive"; + public MainWindow() + { + InitializeComponent(); + + var version = typeof(App).Assembly.GetName().Version; + this.Title += " " + version; + + _application = WinSettings.GetSettings(); + + TbProjectsPath.LostFocus += TbProjectsPath_LostFocus; + CbProjects.SelectionChanged += CbProjects_SelectionChanged; + + BtnPublish.Click += BtnPublish_Click; + BtnSettings.Click += BtnSettings_Click; + + Closing += MainWindow_Closing; + + if (_application == null) + { + OpenSettings(); + return; + } + + TbProjectsPath.Text = _application.LastFolder; + LoadProjects(); + } + + private void BtnSettings_Click(object sender, RoutedEventArgs e) + { + OpenSettings(); + } + + private void MainWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e) + { + var settings = WinSettings.GetSettings(); + if (settings == null) + return; + settings.LastFolder = TbProjectsPath.Text; + WinSettings.SaveSettings(settings); + } + + private void OpenSettings() + { + var win = new WinSettings(); + win.ShowDialog(); + if (win.DialogResult != null && (bool)win.DialogResult) + { + _application = WinSettings.GetSettings(); + } + } + + private void CbProjects_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + _selectedProject = (Project)CbProjects.SelectedItem; + LoadProject(); + } + + private void TbProjectsPath_LostFocus(object sender, RoutedEventArgs e) + { + LoadProjects(); + } + + private void LoadProjects() + { + _projectPath = TbProjectsPath.Text; + + if (!Directory.Exists(_projectPath)) + { + MessageBox.Show($"Pot {_projectPath} ne obstaja!"); + return; + } + + _projects = new List(); + var dirInfo = new DirectoryInfo(_projectPath); + + dirInfo.GetDirectories() + .ToList() + .ForEach(directoryInfo => directoryInfo.GetFiles("*.sln") + .ToList() + .ForEach(x => _projects.Add(new Project + { + Name = $"{directoryInfo.Name}/{x.Name}", + Path = x.FullName + }))); + + CbProjects.ItemsSource = _projects; + } + + private void LoadProject() + { + TbOutput.Text = ""; + LblProjectInfo.Content = ""; + BtnPublish.IsEnabled = false; + if (_selectedProject == null) + return; + + _selectedProjectVersion = ""; + _selectedProjectSubPath = ""; + _selectedProjectPublishLocation = ""; + + var lines = File.ReadLines(_selectedProject.Path); + lines.Where(line => line.StartsWith("Project")) + .ToList() + .ForEach(line => + { + var projectTitle = line.Split(",")[1].Replace(" ", "").Replace("\"", "").Split(@"\")[0]; + var projectSubPath = Path.Combine(new FileInfo(_selectedProject.Path)?.DirectoryName ?? "", projectTitle); + var projectFileInfos = new DirectoryInfo(projectSubPath) + .GetFiles("*.cs") + .Where(x => x.Name is "App.xaml.cs" or "Program.cs") + .ToList(); + + if (projectFileInfos.Count <= 0) return; + + var csLines = File.ReadLines(projectFileInfos[0].FullName).ToList(); + + csLines.Where(csLine => csLine.StartsWith("[assembly: AssemblyVersion(")) + .ToList() + .ForEach(csLine => + { + _selectedProjectVersion = csLine.Replace("[assembly: AssemblyVersion(\"", "").Replace("\")]", ""); + _selectedProjectSubPath = projectSubPath; + + System.Diagnostics.Debug.WriteLine(_selectedProjectVersion); + }); + if (_selectedProjectSubPath != "") + { + csLines.Where(csLine => csLine.StartsWith("//Publish location:")) + .ToList() + .ForEach(csLine => + { + _selectedProjectPublishLocation = csLine.Replace("//Publish location:", ""); + + System.Diagnostics.Debug.WriteLine(_selectedProjectPublishLocation); + }); + } + }); + + if (_selectedProjectVersion == "" || _selectedProjectSubPath == "" || _selectedProjectPublishLocation == "") + return; + + LblProjectInfo.Content = $"Verzija: {_selectedProjectVersion} Pot: {_selectedProjectPublishLocation}"; + + BtnPublish.IsEnabled = true; + } + + private async void BtnPublish_Click(object sender, RoutedEventArgs e) + { + if (_selectedProject == null || _application == null) + return; + + var releaseFolder = Path.Combine(_selectedProjectSubPath, @"bin\Release"); + if (!Directory.Exists(releaseFolder)) + { + MessageBox.Show($"Mapa {releaseFolder} ne obstaja!"); + return; + } + + GridProgress.Visibility = Visibility.Visible; + LblLoading.Content = $"Čiščenje mape {releaseFolder}"; + await Task.Run(() => + { + var diReleaseFolder = new DirectoryInfo(releaseFolder); + + foreach (var file in diReleaseFolder.GetFiles()) + { + file.Delete(); + } + foreach (var dir in diReleaseFolder.GetDirectories()) + { + dir.Delete(true); + } + }); + + LblLoading.Content = $"Rebuild {_selectedProject.Path}"; + var output = ""; + await Task.Run(() => + { + var command = $"devenv {_selectedProject.Path} /Rebuild \"Release\""; + var cmd = new Process(); + cmd.StartInfo.FileName = "cmd.exe"; + cmd.StartInfo.RedirectStandardInput = true; + cmd.StartInfo.RedirectStandardOutput = true; + cmd.StartInfo.CreateNoWindow = true; + cmd.StartInfo.UseShellExecute = false; + cmd.Start(); + + cmd.StandardInput.WriteLine(command); + //cmd.StandardInput.WriteLine("echo Oscar"); + cmd.StandardInput.Flush(); + cmd.StandardInput.Close(); + cmd.WaitForExit(_application.BuildSeconds * 1000); + output = cmd.StandardOutput.ReadToEnd(); + Debug.WriteLine("\n\n\n\n"); + Debug.WriteLine(output); + //System.Diagnostics.Process.Start("CMD.exe", ""); + }); + TbOutput.Text = output; + + var zipDirectory = new DirectoryInfo(releaseFolder).Parent?.FullName ?? ""; + var zipPath = Path.Combine(zipDirectory, "Package.zip"); + LblLoading.Content = $"Zip {zipPath}"; + if (File.Exists(zipPath)) + File.Delete(zipPath); + + await Task.Run(() => + { + ZipFile.CreateFromDirectory(releaseFolder, zipPath, CompressionLevel.Optimal, false); + }); + + if (ChbPripraviSamoZip.IsChecked != null && (bool) ChbPripraviSamoZip.IsChecked) + { + Process.Start("explorer.exe", zipDirectory); + } + else + { + //InfosysUpdate + //v&H6c$wTbTkgSgdWvL*8k$st3#z5X + LblLoading.Content = $"Upload to SFTP"; + var error = ""; + await Task.Run(() => + { + try + { + using var sftpClient = new SftpClient(_application.SftpServerAddress, _application.SftpPort, + _application.SftpUsername, _application.SftpPassword); + sftpClient.Connect(); + + if (!sftpClient.Exists(_selectedProjectPublishLocation)) + sftpClient.CreateDirectory(_selectedProjectPublishLocation); + + if (!sftpClient.Exists(SftpArchivePath)) + sftpClient.CreateDirectory(SftpArchivePath); + + var files = sftpClient.ListDirectory(_selectedProjectPublishLocation).ToList(); + var xmlVersion = ""; + //arhiv + foreach (var file in files) + { + if (!file.Name.ToLower().EndsWith(".xml")) + continue; + + var tmpXmlFile = Path.GetTempFileName(); + + using (var tmpFile = File.OpenWrite(tmpXmlFile)) + { + sftpClient.DownloadFile(file.FullName, tmpFile); + } + + try + { + var xmlContent = File.ReadAllText(tmpXmlFile); + if (!string.IsNullOrEmpty(xmlContent)) + { + //Oddaljena verzije + var xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(xmlContent); + var xmlNode = xmlDocument.SelectSingleNode("/Update"); + xmlVersion = xmlNode["Version"].InnerText; + } + } + catch (Exception exception) + { + error += "\n\n"; + error += exception.ToString(); + } + + File.Delete(tmpXmlFile); + } + + if (xmlVersion != "") + { + var projectArchive = SftpArchivePath + "/" + _selectedProjectPublishLocation; + if (!sftpClient.Exists(projectArchive)) + sftpClient.CreateDirectory(projectArchive); + + var archiveFolderWithoutIndex = projectArchive + "/" + xmlVersion.Replace(".", "_"); + var archiveFolder = archiveFolderWithoutIndex; + var index = 1; + while (sftpClient.Exists(archiveFolder)) + { + archiveFolder = archiveFolderWithoutIndex + "_" + index; + index++; + } + + sftpClient.CreateDirectory(archiveFolder); + + foreach (var file in files) + { + if (!file.IsRegularFile) + continue; + + sftpClient.Get(file.FullName).MoveTo(archiveFolder + "/" + file.Name); + + } + } + + //Upload + var tmpXmlFileUpload = Path.GetTempFileName(); + string xml = $@" + + {_selectedProjectVersion} +"; + File.WriteAllText(tmpXmlFileUpload, xml); + using (var fileStream = new FileStream(tmpXmlFileUpload, FileMode.Open)) + { + sftpClient.UploadFile(fileStream, _selectedProjectPublishLocation + "/" + "Update.xml", + true); + } + + using (var fileStream = new FileStream(zipPath, FileMode.Open)) + { + sftpClient.UploadFile(fileStream, _selectedProjectPublishLocation + "/" + "Package.zip", + true); + } + + File.Delete(tmpXmlFileUpload); + sftpClient.Disconnect(); + } + catch (Exception ex) + { + error += "\n\n"; + error += ex.ToString(); + } + }); + if (error != "") + { + MessageBox.Show(error); + } + } + + GridProgress.Visibility = Visibility.Hidden; + LblLoading.Content = ""; + } + } +} diff --git a/InfosysPublisher/WinSettings.xaml b/InfosysPublisher/WinSettings.xaml new file mode 100644 index 0000000..2293fe2 --- /dev/null +++ b/InfosysPublisher/WinSettings.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/InfosysPublisher/WinSettings.xaml.cs b/InfosysPublisher/WinSettings.xaml.cs new file mode 100644 index 0000000..ca811ec --- /dev/null +++ b/InfosysPublisher/WinSettings.xaml.cs @@ -0,0 +1,93 @@ +using InfosysPublisher.Classes; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace InfosysPublisher +{ + /// + /// Interaction logic for WinSettings.xaml + /// + public partial class WinSettings : Window + { + private static string _settingsPath; + private static string _applicationPath; + + public WinSettings() + { + InitializeComponent(); + + BtnSave.Click += BtnSave_Click; + + LoadSettings(); + } + + private void BtnSave_Click(object sender, RoutedEventArgs e) + { + SaveSettings(); + } + + private void SaveSettings() + { + var settings = new Settings.Application + { + SftpServerAddress = TbSftpServer.Text, + SftpPort = Convert.ToInt32(TbSftpPort.Text), + SftpUsername = TbSftpUsername.Text, + SftpPassword = TbSftpPassword.Text, + BuildSeconds = Convert.ToInt32(TbBuildDuration.Text) + }; + + SaveSettings(settings); + + this.DialogResult = true; + } + + private void LoadSettings() + { + var settings = GetSettings() ?? new Settings.Application(); + + TbSftpServer.Text = settings.SftpServerAddress; + TbSftpPort.Text = settings.SftpPort.ToString(); + TbSftpUsername.Text = settings.SftpUsername; + TbSftpPassword.Text = settings.SftpPassword; + TbBuildDuration.Text = settings.BuildSeconds.ToString(); + } + + private static void SetPaths() + { + _applicationPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + _settingsPath = _applicationPath + @"\InfosysPublisher.json"; + } + + internal static Settings.Application? GetSettings() + { + SetPaths(); + + if (File.Exists(_settingsPath)) + { + return JsonConvert.DeserializeObject(File.ReadAllText(_settingsPath)) ?? new Settings.Application(); + } + + return null; + } + + internal static void SaveSettings(Settings.Application iSettings) + { + SetPaths(); + iSettings.Save(_settingsPath); + } + } +} diff --git a/InfosysPublisher/infosysPublisher.ico b/InfosysPublisher/infosysPublisher.ico new file mode 100644 index 0000000..695d097 Binary files /dev/null and b/InfosysPublisher/infosysPublisher.ico differ