525 lines
20 KiB
C#
525 lines
20 KiB
C#
using Newtonsoft.Json;
|
|
using Org.BouncyCastle.Crypto;
|
|
using Org.BouncyCastle.Crypto.IO;
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Security;
|
|
using Publisher.Models;
|
|
using Publisher.Models.Confluence;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Publisher
|
|
{
|
|
public partial class Main : Form
|
|
{
|
|
private delegate void UpdateOutputStatusDelegate(string message);
|
|
private static string MemoryMasterKey = "!ZEqy2Zsb#VK6<8`H6;W~VxJ$r:w.{ffzwDt=<yKC6m6N3;T<9nyeF&+.4&D@rhK";
|
|
private static string AppDirectory = null;
|
|
private static string ConfigPath = null;
|
|
private Config config = null;
|
|
private string LogsText = "";
|
|
|
|
public Main()
|
|
{
|
|
InitializeComponent();
|
|
|
|
AppDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PBA_Publisher");
|
|
|
|
if(!Directory.Exists(AppDirectory))
|
|
{
|
|
Directory.CreateDirectory(AppDirectory);
|
|
}
|
|
|
|
ConfigPath = Path.Combine(AppDirectory, "config.json");
|
|
|
|
if(File.Exists(ConfigPath))
|
|
{
|
|
try
|
|
{
|
|
string json = File.ReadAllText(ConfigPath);
|
|
|
|
if(!string.IsNullOrEmpty(json))
|
|
{
|
|
config = JsonConvert.DeserializeObject<Config>(json);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(ex.Message);
|
|
}
|
|
}
|
|
|
|
if(config != null)
|
|
{
|
|
if(config.Inside != null)
|
|
{
|
|
txtServiceInsideProjectFile.Text = config.Inside.Path;
|
|
cbxServiceInsideAutoIncrement.CheckState = (config.Inside.VersionAutoIncrement ? CheckState.Checked : CheckState.Unchecked);
|
|
config.Inside.OnUpdateStatus += Service_OnUpdateStatus;
|
|
}
|
|
|
|
if (config.Outside != null)
|
|
{
|
|
txtServiceOutsideProjectFile.Text = config.Outside.Path;
|
|
cbxServiceOutsideAutoIncrement.CheckState = (config.Outside.VersionAutoIncrement ? CheckState.Checked : CheckState.Unchecked);
|
|
config.Outside.OnUpdateStatus += Service_OnUpdateStatus;
|
|
}
|
|
|
|
txtConfluenceURL.Text = config.ConfluenceUrl;
|
|
txtConfluenceParentPageId.Text = config.ConfluenceParentPageId.ToString();
|
|
txtConfluenceUsername.Text = config.ConfluenceUsername;
|
|
txtConfluencePassword.Text = Decrypt(config.ConfluencePassword);
|
|
|
|
txtOutputDirectory.Text = config.OutputDirectory;
|
|
txtOutputZipPassword.Text = Decrypt(config.ZipPassword);
|
|
}
|
|
}
|
|
|
|
private void Service_OnUpdateStatus(object sender, StatusUpdateArgs e)
|
|
{
|
|
string line = (!string.IsNullOrEmpty(LogsText) ? LogsText : "") +DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + "[" + e.Type + "]:" + e.Data + "\r\n";
|
|
|
|
LogsText = line;
|
|
|
|
UpdateOutputStatus(line);
|
|
}
|
|
|
|
private void UpdateOutputStatus(string message)
|
|
{
|
|
if(lblStatus.InvokeRequired)
|
|
{
|
|
lblStatus.Invoke(new UpdateOutputStatusDelegate(UpdateOutputStatus), message);
|
|
}
|
|
else
|
|
{
|
|
lblStatus.Text = message;
|
|
}
|
|
}
|
|
|
|
private void button1_Click(object sender, EventArgs e)
|
|
{
|
|
Logs logs = new Logs(LogsText);
|
|
logs.ShowDialog();
|
|
}
|
|
|
|
private void SaveConfig()
|
|
{
|
|
try
|
|
{
|
|
lblStatus.Text = "";
|
|
|
|
if (string.IsNullOrEmpty(txtOutputDirectory.Text))
|
|
{
|
|
lblStatus.Text = "Please select the output directory";
|
|
}
|
|
else if (string.IsNullOrEmpty(txtOutputZipPassword.Text))
|
|
{
|
|
lblStatus.Text = "Please enter output zip file password";
|
|
}
|
|
else if (string.IsNullOrEmpty(txtConfluenceURL.Text))
|
|
{
|
|
lblStatus.Text = "Please enter a confluence url";
|
|
}
|
|
else if (string.IsNullOrEmpty(txtConfluenceUsername.Text))
|
|
{
|
|
lblStatus.Text = "Please enter a confluence username";
|
|
}
|
|
else if (string.IsNullOrEmpty(txtConfluencePassword.Text))
|
|
{
|
|
lblStatus.Text = "Please enter a confluence password";
|
|
}
|
|
else if (string.IsNullOrEmpty(txtConfluenceParentPageId.Text))
|
|
{
|
|
lblStatus.Text = "Please enter a confluence parent page id";
|
|
}
|
|
else
|
|
{
|
|
if (config == null)
|
|
{
|
|
config = new Config();
|
|
}
|
|
|
|
/** Confluence **/
|
|
config.ConfluenceUrl = txtConfluenceURL.Text;
|
|
config.ConfluenceUsername = txtConfluenceUsername.Text;
|
|
config.ConfluencePassword = Encrypt(txtConfluencePassword.Text);
|
|
config.ConfluenceParentPageId = Convert.ToInt32(txtConfluenceParentPageId.Text);
|
|
|
|
/** Output **/
|
|
config.OutputDirectory = txtOutputDirectory.Text;
|
|
config.ZipPassword = Encrypt(txtOutputZipPassword.Text);
|
|
|
|
/** Inside **/
|
|
if (!string.IsNullOrEmpty(txtServiceInsideProjectFile.Text))
|
|
{
|
|
if (config.Inside == null)
|
|
{
|
|
config.Inside = new Project();
|
|
}
|
|
|
|
config.Inside.Name = "ServiceInside";
|
|
config.Inside.Path = txtServiceInsideProjectFile.Text;
|
|
config.Inside.Platform = Project.Platforms.NET_CORE;
|
|
config.Inside.VersionAutoIncrement = cbxServiceInsideAutoIncrement.CheckState == CheckState.Checked;
|
|
}
|
|
|
|
/** Outside **/
|
|
if (!string.IsNullOrEmpty(txtServiceOutsideProjectFile.Text))
|
|
{
|
|
if (config.Outside == null)
|
|
{
|
|
config.Outside = new Project();
|
|
}
|
|
|
|
config.Outside.Name = "ServiceOutside";
|
|
config.Outside.Path = txtServiceOutsideProjectFile.Text;
|
|
config.Outside.Platform = Project.Platforms.NET_CORE;
|
|
config.Outside.VersionAutoIncrement = cbxServiceOutsideAutoIncrement.CheckState == CheckState.Checked;
|
|
}
|
|
|
|
string json = JsonConvert.SerializeObject(config);
|
|
|
|
File.WriteAllText(ConfigPath, json);
|
|
|
|
if (File.Exists(ConfigPath))
|
|
{
|
|
lblStatus.Text = "Configuration has been successfully saved";
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show(ex.Message);
|
|
}
|
|
}
|
|
|
|
public static string Encrypt(string value)
|
|
{
|
|
string result = null;
|
|
|
|
try
|
|
{
|
|
IBufferedCipher encCipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
|
|
byte[] keyBytes = GetKey(MemoryMasterKey);
|
|
KeyParameter key = new KeyParameter(keyBytes);
|
|
byte[] nonce = new byte[12];
|
|
RandomNumberGenerator.Create().GetBytes(nonce);
|
|
encCipher.Init(true, new ParametersWithIV(key, nonce));
|
|
byte[] plainText = Encoding.UTF8.GetBytes(value);
|
|
byte[] chiperBuffer = null;
|
|
byte[] tag = new byte[16];
|
|
byte[] resultBuffer = null;
|
|
|
|
using (MemoryStream memStream = new MemoryStream())
|
|
{
|
|
using (CipherStream encStream = new CipherStream(memStream, null, encCipher))
|
|
{
|
|
encStream.Write(plainText, 0, plainText.Length);
|
|
}
|
|
|
|
chiperBuffer = memStream.ToArray();
|
|
|
|
resultBuffer = nonce.Concat(chiperBuffer).ToArray();
|
|
}
|
|
|
|
result = Convert.ToBase64String(resultBuffer);
|
|
}
|
|
catch
|
|
{
|
|
result = null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static string Decrypt(string value)
|
|
{
|
|
string result = null;
|
|
|
|
try
|
|
{
|
|
IBufferedCipher decCipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
|
|
byte[] keyBytes = GetKey(MemoryMasterKey);
|
|
KeyParameter key = new KeyParameter(keyBytes);
|
|
byte[] combined = Convert.FromBase64String(value);
|
|
byte[] tag = combined.Skip(combined.Length - 16).ToArray();
|
|
byte[] nonce = combined.Take(12).ToArray();
|
|
byte[] chiperText = combined.Skip(nonce.Length).Take(combined.Length - nonce.Length).ToArray();
|
|
byte[] plainTextBuffer = null;
|
|
|
|
decCipher.Init(false, new ParametersWithIV(key, nonce));
|
|
|
|
using (MemoryStream memStream = new MemoryStream(chiperText, false))
|
|
{
|
|
MemoryStream dataStream = new MemoryStream();
|
|
|
|
using (dataStream)
|
|
{
|
|
using (CipherStream decStream = new CipherStream(memStream, (IBufferedCipher)decCipher, null))
|
|
{
|
|
int ch;
|
|
|
|
while ((ch = decStream.ReadByte()) >= 0)
|
|
{
|
|
dataStream.WriteByte((byte)ch);
|
|
}
|
|
}
|
|
}
|
|
|
|
plainTextBuffer = dataStream.ToArray();
|
|
|
|
result = Encoding.UTF8.GetString(plainTextBuffer);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
result = null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static byte[] GetKey(string password)
|
|
{
|
|
byte[] result = null;
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(password))
|
|
{
|
|
if (password.Length < 32)
|
|
{
|
|
password = password.PadRight(32, '@');
|
|
}
|
|
else if (password.Length > 32)
|
|
{
|
|
password = MD5Encrypt(password);
|
|
}
|
|
|
|
result = Encoding.ASCII.GetBytes(password);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static string MD5Encrypt(string value)
|
|
{
|
|
string result = null;
|
|
|
|
try
|
|
{
|
|
byte[] bytes = Encoding.UTF8.GetBytes(value);
|
|
|
|
using (System.Security.Cryptography.MD5 hash = System.Security.Cryptography.MD5.Create())
|
|
{
|
|
byte[] hashedInputBytes = hash.ComputeHash(bytes);
|
|
|
|
StringBuilder hashedInputStringBuilder = new StringBuilder(128);
|
|
|
|
foreach (var b in hashedInputBytes)
|
|
{
|
|
hashedInputStringBuilder.Append(b.ToString("X2"));
|
|
}
|
|
|
|
result = hashedInputStringBuilder.ToString().ToLower();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
result = null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void button2_Click(object sender, EventArgs e)
|
|
{
|
|
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
|
|
|
|
if(folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
txtOutputDirectory.Text = folderBrowserDialog.SelectedPath;
|
|
}
|
|
}
|
|
|
|
private void btnSelectServiceOutsideProjectFile_Click(object sender, EventArgs e)
|
|
{
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
openFileDialog.Filter = "Project File (*.csproj)|*.csproj";
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
txtServiceOutsideProjectFile.Text = openFileDialog.FileName;
|
|
}
|
|
}
|
|
|
|
private void btnSelectServiceInsideProjectFile_Click(object sender, EventArgs e)
|
|
{
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
openFileDialog.Filter = "Project File (*.csproj)|*.csproj";
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
txtServiceInsideProjectFile.Text = openFileDialog.FileName;
|
|
}
|
|
}
|
|
|
|
private void btnPublish_Click(object sender, EventArgs e)
|
|
{
|
|
LogsText = "";
|
|
|
|
if (this.config == null)
|
|
{
|
|
button1_Click(null, null);
|
|
}
|
|
|
|
if(this.config != null &&
|
|
!string.IsNullOrEmpty(this.config.ConfluenceUrl) &&
|
|
!string.IsNullOrEmpty(this.config.ConfluenceUsername) &&
|
|
!string.IsNullOrEmpty(this.config.ConfluencePassword) &&
|
|
this.config.ConfluenceParentPageId > 0 &&
|
|
!string.IsNullOrEmpty(this.config.OutputDirectory) &&
|
|
!string.IsNullOrEmpty(this.config.ZipPassword))
|
|
{
|
|
string html = tinyMCE1.HtmlContent;
|
|
|
|
Thread thread = new Thread(() => {
|
|
|
|
UpdateOutputStatus("Publishing...");
|
|
|
|
string dotnet_exe = @"C:\Program Files\dotnet\dotnet.exe";
|
|
|
|
/** inside **/
|
|
string zipInside = null;
|
|
|
|
if (cbxReleaseServiceInside.CheckState == CheckState.Checked)
|
|
{
|
|
UpdateOutputStatus("Create release package of ServiceInside...");
|
|
zipInside = this.config.Inside.Publish(dotnet_exe, this.config.OutputDirectory, Decrypt(this.config.ZipPassword));
|
|
}
|
|
|
|
/** outside **/
|
|
string zipOutside = null;
|
|
|
|
if (cbxReleaseServiceOutside.CheckState == CheckState.Checked)
|
|
{
|
|
UpdateOutputStatus("Create release package of ServiceOutside...");
|
|
zipOutside = this.config.Outside.Publish(dotnet_exe, this.config.OutputDirectory, Decrypt(this.config.ZipPassword));
|
|
}
|
|
|
|
Services.Confluence confluence = new Services.Confluence(config.ConfluenceUrl, config.ConfluenceUsername, Decrypt(config.ConfluencePassword));
|
|
|
|
UpdateOutputStatus("Create confluence Release Page...");
|
|
|
|
string release = config.Outside.GetVersion();
|
|
|
|
html = html.Replace("[RELEASE]", release);
|
|
|
|
string ts = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss");
|
|
|
|
html = html.Replace("[SERVICE_INSIDE]", config.Inside.Name);
|
|
html = html.Replace("[SERVICE_INSIDE_VERSION]", config.Inside.GetVersion(false));
|
|
html = html.Replace("[SERVICE_INSIDE_PUBLISHED_ON]", ts);
|
|
|
|
html = html.Replace("[SERVICE_OUTSIDE]", config.Outside.Name);
|
|
html = html.Replace("[SERVICE_OUTSIDE_VERSION]", config.Outside.GetVersion(false));
|
|
html = html.Replace("[SERVICE_OUTSIDE_PUBLISHED_ON]", ts);
|
|
|
|
html = html.Replace("[SERVICE_SUPPORT]", config.Support.Name);
|
|
html = html.Replace("[SERVICE_SUPPORT_VERSION]", config.Support.GetVersion(false));
|
|
html = html.Replace("[SERVICE_SUPPORT_PUBLISHED_ON]", ts);
|
|
|
|
/** delete old **/
|
|
confluence.DeleteOldChildPages(config.ConfluenceParentPageId, 4);
|
|
|
|
ResponsePage res = confluence.CreatePage(release, "PB", html, config.ConfluenceParentPageId);
|
|
|
|
ResponseAttachment res1 = null;
|
|
ResponseAttachment res2 = null;
|
|
ResponseAttachment res3 = null;
|
|
|
|
if (res != null)
|
|
{
|
|
string downloadURL = config.ConfluenceUrl + "/download/attachments/" + res.id.ToString() + "/";
|
|
|
|
UpdateOutputStatus("Confluence page has been created (" + res.title + ", " + res.id + ")");
|
|
|
|
if (!string.IsNullOrEmpty(zipInside))
|
|
{
|
|
UpdateOutputStatus("Upload ServiceInside to confluence (" + Path.GetFileName(zipInside) + ")");
|
|
res1 = confluence.AddAttachment(res.id, zipInside, "application/zip");
|
|
UpdateOutputStatus(Path.GetFileName(zipInside) + " has been successfully uploaded");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(zipOutside))
|
|
{
|
|
UpdateOutputStatus("Upload ServiceOutside to confluence (" + Path.GetFileName(zipOutside) + ")");
|
|
res2 = confluence.AddAttachment(res.id, zipOutside, "application/zip");
|
|
UpdateOutputStatus(Path.GetFileName(zipOutside) + " has been successfully uploaded");
|
|
}
|
|
|
|
/** Updates Links **/
|
|
if (res1 != null && !string.IsNullOrEmpty(res1.id) && !string.IsNullOrEmpty(res1.title))
|
|
{
|
|
html = html.Replace("[SERVICE_INSIDE_LINK]", "<a href=\"" + downloadURL + res1.title + "\">Download</a>");
|
|
}
|
|
else
|
|
{
|
|
html = html.Replace("[SERVICE_INSIDE_LINK]", "");
|
|
}
|
|
|
|
if (res2 != null && !string.IsNullOrEmpty(res2.id) && !string.IsNullOrEmpty(res2.title))
|
|
{
|
|
html = html.Replace("[SERVICE_OUTSIDE_LINK]", "<a href=\"" + downloadURL + res2.title + "/" + res2.title + "\">Download</a>");
|
|
}
|
|
else
|
|
{
|
|
html = html.Replace("[SERVICE_OUTSIDE_LINK]", "");
|
|
}
|
|
|
|
if (res3 != null && !string.IsNullOrEmpty(res3.id) && !string.IsNullOrEmpty(res3.title))
|
|
{
|
|
html = html.Replace("[SERVICE_SUPPORT_LINK]", "<a href=\"" + downloadURL + res3.title + "/" + res3.title + "\">Download</a>");
|
|
}
|
|
else
|
|
{
|
|
html = html.Replace("[SERVICE_SUPPORT_LINK]", "");
|
|
}
|
|
|
|
ResponsePage resUpdate = confluence.UpdatePage(release, "PB", res.id, html);
|
|
|
|
if(resUpdate != null && !string.IsNullOrEmpty(resUpdate.id))
|
|
{
|
|
UpdateOutputStatus(release + " has been successfully published");
|
|
}
|
|
else
|
|
{
|
|
UpdateOutputStatus(release + " dwonload links could not be updated");
|
|
}
|
|
}
|
|
});
|
|
|
|
thread.Start();
|
|
}
|
|
}
|
|
|
|
private void Main_Load(object sender, EventArgs e)
|
|
{
|
|
tinyMCE1.CreateEditor();
|
|
}
|
|
}
|
|
}
|