mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Merge pull request #224 from mRemoteNG/160_portable_update_check
160 portable update check
This commit is contained in:
12
Tools/create_upg_chk_files.ps1
Normal file
12
Tools/create_upg_chk_files.ps1
Normal file
@@ -0,0 +1,12 @@
|
||||
#Requires -Version 4.0
|
||||
|
||||
$file = gci ..\Release | sort LastWriteTime | select -last 1 | % { $_.FullName }
|
||||
|
||||
$version = $file.tostring().Split("-")[2].trim(".zip")
|
||||
Write-Host Version: $version
|
||||
|
||||
Write-Host dURL:
|
||||
Write-Host clURL:
|
||||
|
||||
$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash }
|
||||
Write-Host CertificateThumbprint: $hash
|
||||
@@ -4,14 +4,31 @@
|
||||
{
|
||||
public static string FileName
|
||||
{
|
||||
#if PORTABLE
|
||||
get
|
||||
{
|
||||
/* */
|
||||
/* return PORTABLE update files here */
|
||||
/* */
|
||||
#if DEBUG
|
||||
return "update-portable-debug.txt";
|
||||
#else
|
||||
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-portable-debug.txt" : "update-portable.txt";
|
||||
#endif
|
||||
}
|
||||
#else //NOT portable
|
||||
get
|
||||
{
|
||||
/* */
|
||||
/* return INSTALLER update files here */
|
||||
/* */
|
||||
#if DEBUG
|
||||
return "update-debug.txt";
|
||||
#else
|
||||
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-debug.txt" : "update.txt";
|
||||
#endif
|
||||
}
|
||||
#endif //endif for PORTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using mRemoteNG.Tools;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
|
||||
@@ -28,7 +31,7 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive;
|
||||
|
||||
public bool IsDownloadUpdateRunning => (_downloadUpdateWebClient != null);
|
||||
public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -92,7 +95,7 @@ namespace mRemoteNG.App.Update
|
||||
{
|
||||
if (_currentUpdateInfo == null || !_currentUpdateInfo.IsValid)
|
||||
{
|
||||
throw (new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."));
|
||||
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
|
||||
}
|
||||
|
||||
if (IsGetChangeLogRunning)
|
||||
@@ -110,20 +113,36 @@ namespace mRemoteNG.App.Update
|
||||
{
|
||||
if (_downloadUpdateWebClient != null)
|
||||
{
|
||||
throw (new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress."));
|
||||
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
|
||||
}
|
||||
|
||||
if (_currentUpdateInfo == null || !_currentUpdateInfo.IsValid)
|
||||
{
|
||||
throw (new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."));
|
||||
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
|
||||
}
|
||||
|
||||
_currentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "exe"));
|
||||
DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, _currentUpdateInfo.UpdateFilePath);
|
||||
#if !PORTABLE
|
||||
_currentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "exe"));
|
||||
#else
|
||||
var sfd = new SaveFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
|
||||
FileName = _currentUpdateInfo.FileName,
|
||||
RestoreDirectory = true
|
||||
};
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
_currentUpdateInfo.UpdateFilePath = sfd.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, _currentUpdateInfo.UpdateFilePath);
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Private Properties
|
||||
#region Private Properties
|
||||
private WebClient _downloadUpdateWebClient;
|
||||
private WebClient DownloadUpdateWebClient
|
||||
{
|
||||
@@ -142,9 +161,9 @@ namespace mRemoteNG.App.Update
|
||||
return _downloadUpdateWebClient;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
#region Private Methods
|
||||
private WebClient CreateWebClient()
|
||||
{
|
||||
var webClient = new WebClient();
|
||||
@@ -231,7 +250,8 @@ namespace mRemoteNG.App.Update
|
||||
{
|
||||
try
|
||||
{
|
||||
var updateAuthenticode = new Authenticode(_currentUpdateInfo.UpdateFilePath)
|
||||
#if !PORTABLE
|
||||
var updateAuthenticode = new Authenticode(_currentUpdateInfo.UpdateFilePath)
|
||||
{
|
||||
RequireThumbprintMatch = true,
|
||||
ThumbprintToMatch = _currentUpdateInfo.CertificateThumbprint
|
||||
@@ -246,7 +266,19 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
throw (new Exception(updateAuthenticode.StatusMessage));
|
||||
}
|
||||
}
|
||||
#else
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
using (var stream = File.OpenRead(_currentUpdateInfo.UpdateFilePath))
|
||||
{
|
||||
var hash = md5.ComputeHash(stream);
|
||||
var hashString = BitConverter.ToString(hash).Replace("-", "");
|
||||
if (!hashString.Equals(_currentUpdateInfo.CertificateThumbprint))
|
||||
throw new Exception("MD5 Hashes didn't match!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
|
||||
@@ -263,9 +295,9 @@ namespace mRemoteNG.App.Update
|
||||
_downloadUpdateWebClient.Dispose();
|
||||
_downloadUpdateWebClient = null;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
#region Events
|
||||
private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent;
|
||||
public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent
|
||||
{
|
||||
@@ -317,6 +349,6 @@ namespace mRemoteNG.App.Update
|
||||
DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,9 @@ namespace mRemoteNG.App.Update
|
||||
public class UpdateFile
|
||||
{
|
||||
#region Public Properties
|
||||
private Dictionary<string, string> _items = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
// ReSharper disable MemberCanBePrivate.Local
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
public Dictionary<string, string> Items => _items;
|
||||
|
||||
public Dictionary<string, string> Items { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
@@ -52,7 +50,7 @@ namespace mRemoteNG.App.Update
|
||||
var key = parts[0].Trim();
|
||||
var value = parts[1].Trim();
|
||||
|
||||
_items.Add(key, value);
|
||||
Items.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +59,7 @@ namespace mRemoteNG.App.Update
|
||||
private string GetString(string key)
|
||||
{
|
||||
// ReSharper restore MemberCanBePrivate.Local
|
||||
return !Items.ContainsKey(key) ? string.Empty : this._items[key];
|
||||
return !Items.ContainsKey(key) ? string.Empty : this.Items[key];
|
||||
}
|
||||
|
||||
public Version GetVersion(string key)
|
||||
@@ -80,6 +78,13 @@ namespace mRemoteNG.App.Update
|
||||
{
|
||||
return GetString(key).Replace(" ", "").ToUpperInvariant();
|
||||
}
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
var value = GetString("dURL");
|
||||
var sv = value.Split('/');
|
||||
return sv[sv.Length-1];
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ namespace mRemoteNG.App.Update
|
||||
public Uri ImageAddress { get; private set; }
|
||||
public Uri ImageLinkAddress { get; private set; }
|
||||
public string CertificateThumbprint { get; private set; }
|
||||
public string FileName { get; private set; }
|
||||
|
||||
public static UpdateInfo FromString(string input)
|
||||
{
|
||||
@@ -29,6 +30,7 @@ namespace mRemoteNG.App.Update
|
||||
newInfo.ImageAddress = updateFile.GetUri("imgURL");
|
||||
newInfo.ImageLinkAddress = updateFile.GetUri("imgURLLink");
|
||||
newInfo.CertificateThumbprint = updateFile.GetThumbprint("CertificateThumbprint");
|
||||
newInfo.FileName = updateFile.GetFileName();
|
||||
newInfo.IsValid = true;
|
||||
}
|
||||
return newInfo;
|
||||
|
||||
18
mRemoteV1/Resources/Language/Language.Designer.cs
generated
18
mRemoteV1/Resources/Language/Language.Designer.cs
generated
@@ -1448,6 +1448,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Download.
|
||||
/// </summary>
|
||||
internal static string strDownloadPortable {
|
||||
get {
|
||||
return ResourceManager.GetString("strDownloadPortable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Duplicate.
|
||||
/// </summary>
|
||||
@@ -6677,6 +6686,15 @@ namespace mRemoteNG {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Download Completed!.
|
||||
/// </summary>
|
||||
internal static string strUpdatePortableDownloadComplete {
|
||||
get {
|
||||
return ResourceManager.GetString("strUpdatePortableDownloadComplete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use a different username and password.
|
||||
/// </summary>
|
||||
|
||||
@@ -2415,4 +2415,10 @@ mRemoteNG will now quit and begin with the installation.</value>
|
||||
<data name="strPropertyNameSoundQuality" xml:space="preserve">
|
||||
<value>Sound Quality</value>
|
||||
</data>
|
||||
<data name="strUpdatePortableDownloadComplete" xml:space="preserve">
|
||||
<value>Download Completed!</value>
|
||||
</data>
|
||||
<data name="strDownloadPortable" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -42,7 +42,6 @@ namespace mRemoteNG.UI.Forms
|
||||
private bool _showFullPathInTitle;
|
||||
private ConnectionInfo _selectedConnection;
|
||||
private SystemMenu _systemMenu;
|
||||
private MiscTools.Fullscreen _fullscreen;
|
||||
private ConnectionTreeWindow ConnectionTreeWindow { get; set; }
|
||||
|
||||
|
||||
@@ -51,7 +50,7 @@ namespace mRemoteNG.UI.Forms
|
||||
{
|
||||
_showFullPathInTitle = Settings.Default.ShowCompleteConsPathInTitle;
|
||||
InitializeComponent();
|
||||
_fullscreen = new MiscTools.Fullscreen(this);
|
||||
Fullscreen = new MiscTools.Fullscreen(this);
|
||||
pnlDock.Theme = new VS2012LightTheme();
|
||||
}
|
||||
|
||||
@@ -120,11 +119,8 @@ namespace mRemoteNG.UI.Forms
|
||||
}
|
||||
}
|
||||
|
||||
public MiscTools.Fullscreen Fullscreen
|
||||
{
|
||||
get { return _fullscreen; }
|
||||
set { _fullscreen = value; }
|
||||
}
|
||||
public MiscTools.Fullscreen Fullscreen { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup & Shutdown
|
||||
@@ -164,8 +160,6 @@ namespace mRemoteNG.UI.Forms
|
||||
Windows.Show(WindowType.ComponentsCheck);
|
||||
}
|
||||
|
||||
ApplySpecialSettingsForPortableVersion();
|
||||
|
||||
Startup.Instance.CreateConnectionsProvider();
|
||||
AddSysMenuItems();
|
||||
Microsoft.Win32.SystemEvents.DisplaySettingsChanged += DisplayChanged;
|
||||
@@ -174,14 +168,6 @@ namespace mRemoteNG.UI.Forms
|
||||
ConnectionTreeWindow = Windows.TreeForm;
|
||||
}
|
||||
|
||||
private void ApplySpecialSettingsForPortableVersion()
|
||||
{
|
||||
#if PORTABLE
|
||||
mMenToolsUpdate.Visible = false;
|
||||
mMenInfoSep2.Visible = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void ApplyLanguage()
|
||||
{
|
||||
mMenFile.Text = Language.strMenuFile;
|
||||
@@ -285,7 +271,6 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
private void frmMain_Shown(object sender, EventArgs e)
|
||||
{
|
||||
#if !PORTABLE
|
||||
if (!Settings.Default.CheckForUpdatesAsked)
|
||||
{
|
||||
string[] commandButtons =
|
||||
@@ -314,7 +299,7 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
if (!Settings.Default.CheckForUpdatesOnStartup) return;
|
||||
|
||||
DateTime nextUpdateCheck = Convert.ToDateTime(
|
||||
var nextUpdateCheck = Convert.ToDateTime(
|
||||
Settings.Default.CheckForUpdatesLastCheck.Add(
|
||||
TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays))));
|
||||
|
||||
@@ -322,7 +307,6 @@ namespace mRemoteNG.UI.Forms
|
||||
if (!IsHandleCreated) CreateHandle(); // Make sure the handle is created so that InvokeRequired returns the correct result
|
||||
|
||||
Startup.Instance.CheckForUpdate();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
|
||||
@@ -458,7 +442,7 @@ namespace mRemoteNG.UI.Forms
|
||||
|
||||
#region Menu
|
||||
#region File
|
||||
private void mMenFile_DropDownOpening(Object sender, EventArgs e)
|
||||
private void mMenFile_DropDownOpening(object sender, EventArgs e)
|
||||
{
|
||||
var selectedNodeType = ConnectionTreeWindow.SelectedNode?.GetTreeNodeType();
|
||||
if (selectedNodeType == TreeNodeType.Root)
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Update;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
#if !PORTABLE
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
|
||||
namespace mRemoteNG.UI.Window
|
||||
{
|
||||
public partial class UpdateWindow : BaseWindow
|
||||
{
|
||||
#region Public Methods
|
||||
#region Public Methods
|
||||
public UpdateWindow(DockContent panel)
|
||||
{
|
||||
WindowType = WindowType.Update;
|
||||
@@ -21,10 +25,11 @@ namespace mRemoteNG.UI.Window
|
||||
InitializeComponent();
|
||||
Runtime.FontOverride(this);
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Form Stuff
|
||||
public void Update_Load(object sender, EventArgs e)
|
||||
#region Form Stuff
|
||||
|
||||
private void Update_Load(object sender, EventArgs e)
|
||||
{
|
||||
ApplyLanguage();
|
||||
CheckForUpdate();
|
||||
@@ -35,8 +40,12 @@ namespace mRemoteNG.UI.Window
|
||||
Text = Language.strMenuCheckForUpdates;
|
||||
TabText = Language.strMenuCheckForUpdates;
|
||||
btnCheckForUpdate.Text = Language.strCheckForUpdate;
|
||||
btnDownload.Text = Language.strDownloadAndInstall;
|
||||
lblChangeLogLabel.Text = Language.strLabelChangeLog;
|
||||
#if !PORTABLE
|
||||
btnDownload.Text = Language.strDownloadAndInstall;
|
||||
#else
|
||||
btnDownload.Text = Language.strDownloadPortable;
|
||||
#endif
|
||||
lblChangeLogLabel.Text = Language.strLabelChangeLog;
|
||||
lblInstalledVersion.Text = Language.strVersion;
|
||||
lblInstalledVersionLabel.Text = $"{Language.strCurrentVersion}:";
|
||||
lblLatestVersion.Text = Language.strVersion;
|
||||
@@ -62,14 +71,14 @@ namespace mRemoteNG.UI.Window
|
||||
}
|
||||
Process.Start(linkUri.ToString());
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
#region Private Fields
|
||||
private AppUpdater _appUpdate;
|
||||
private bool _isUpdateDownloadHandlerDeclared;
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
#region Private Methods
|
||||
private void CheckForUpdate()
|
||||
{
|
||||
if (_appUpdate == null)
|
||||
@@ -120,7 +129,7 @@ namespace mRemoteNG.UI.Window
|
||||
}
|
||||
if (e.Error != null)
|
||||
{
|
||||
throw (e.Error);
|
||||
throw e.Error;
|
||||
}
|
||||
|
||||
if (_appUpdate.IsUpdateAvailable())
|
||||
@@ -181,7 +190,7 @@ namespace mRemoteNG.UI.Window
|
||||
if (InvokeRequired)
|
||||
{
|
||||
var myDelegate = new AsyncCompletedEventHandler(GetChangeLogCompleted);
|
||||
Invoke(myDelegate, new object[] {sender, e});
|
||||
Invoke(myDelegate, sender, e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,10 +201,10 @@ namespace mRemoteNG.UI.Window
|
||||
if (e.Cancelled)
|
||||
return;
|
||||
if (e.Error != null)
|
||||
throw (e.Error);
|
||||
|
||||
txtChangeLog.Text = _appUpdate.ChangeLog;
|
||||
}
|
||||
throw e.Error;
|
||||
|
||||
txtChangeLog.Text = _appUpdate.ChangeLog.Replace("\n", Environment.NewLine);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateGetChangeLogFailed, ex);
|
||||
@@ -224,10 +233,10 @@ namespace mRemoteNG.UI.Window
|
||||
Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateDownloadFailed, ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
private void DownloadUpdateProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
|
||||
#region Events
|
||||
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
||||
{
|
||||
prgbDownload.Value = e.ProgressPercentage;
|
||||
}
|
||||
@@ -242,22 +251,25 @@ namespace mRemoteNG.UI.Window
|
||||
if (e.Cancelled)
|
||||
return;
|
||||
if (e.Error != null)
|
||||
throw (e.Error);
|
||||
|
||||
if (MessageBox.Show(Language.strUpdateDownloadComplete, Language.strMenuCheckForUpdates, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
|
||||
throw e.Error;
|
||||
#if !PORTABLE
|
||||
if (MessageBox.Show(Language.strUpdateDownloadComplete, Language.strMenuCheckForUpdates, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
|
||||
{
|
||||
Shutdown.Quit(_appUpdate.CurrentUpdateInfo.UpdateFilePath);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
File.Delete(_appUpdate.CurrentUpdateInfo.UpdateFilePath);
|
||||
}
|
||||
#else
|
||||
MessageBox.Show(Language.strUpdatePortableDownloadComplete, Language.strMenuCheckForUpdates, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(Language.strUpdateDownloadCompleteFailed, ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user