Revisiting the machine-id concept.
Removed the text from the update folder as it is no longer being used. Added a new `machineid.txt` file that controls the machine-id. De-coupled the machine-id from the installationid as the latter is used for usage reporting, and should not be connected to the machine-id
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
This folder is used to store updates.
|
||||
|
||||
Each folder is checked before launch to ensure the integrity of the application.
|
||||
|
||||
DO NOT MODIFY THE FOLDERS!
|
||||
|
||||
This means:
|
||||
DO NOT CHANGE ANY FILES!
|
||||
DO NOT DELETE ANY FILES!
|
||||
DO NOT ADD ANY FILES!
|
||||
|
||||
If anything is changed, the updates will be rejected, and a previous version is used.
|
||||
|
||||
If you need to modify something, use the folder where the application is installed.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{0}
|
||||
|
||||
This file is used to assign a unique ID to the machine, and used to identify the machine in reports.
|
||||
The first line in the file is used as an ID, but can be changed with --machine-id for a single or multiple runs.
|
||||
@@ -33,13 +33,12 @@ namespace Duplicati.Library.AutoUpdater
|
||||
private const string UPDATE_URL = "AutoUpdateURL.txt";
|
||||
private const string UPDATE_KEY = "AutoUpdateSignKey.txt";
|
||||
private const string UPDATE_CHANNEL = "AutoUpdateBuildChannel.txt";
|
||||
private const string UPDATE_README = "AutoUpdateFolderReadme.txt";
|
||||
private const string UPDATE_INSTALL_FILE = "AutoUpdateInstallIDTemplate.txt";
|
||||
private const string UPDATE_MACHINE_FILE = "AutoUpdateMachineIDTemplate.txt";
|
||||
|
||||
private const string OEM_APP_NAME = "oem-app-name.txt";
|
||||
private const string OEM_UPDATE_URL = "oem-update-url.txt";
|
||||
private const string OEM_UPDATE_KEY = "oem-update-key.txt";
|
||||
private const string OEM_UPDATE_README = "oem-update-readme.txt";
|
||||
private const string OEM_UPDATE_INSTALL_FILE = "oem-update-installid.txt";
|
||||
|
||||
public const string UPDATEURL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_URLS";
|
||||
@@ -49,13 +48,13 @@ namespace Duplicati.Library.AutoUpdater
|
||||
internal const string MATCH_UPDATE_URL_CHANNEL_GROUP = "channel";
|
||||
internal const string MATCH_UPDATE_URL_FILENAME_GROUP = "filename";
|
||||
|
||||
internal static readonly Regex MATCH_AUTOUPDATE_URL =
|
||||
internal static readonly Regex MATCH_AUTOUPDATE_URL =
|
||||
new Regex(string.Format(
|
||||
"(?<{0}>.+)(?<{1}>{3})(?<{2}>/([^/]+).manifest)",
|
||||
"(?<{0}>.+)(?<{1}>{3})(?<{2}>/([^/]+).manifest)",
|
||||
MATCH_UPDATE_URL_PREFIX_GROUP,
|
||||
MATCH_UPDATE_URL_CHANNEL_GROUP,
|
||||
MATCH_UPDATE_URL_FILENAME_GROUP,
|
||||
string.Join("|", Enum.GetNames(typeof(ReleaseType)).Union(new [] { "preview", "rene" }) )), RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
string.Join("|", Enum.GetNames(typeof(ReleaseType)).Union(new[] { "preview" }))), RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
|
||||
static AutoUpdateSettings()
|
||||
@@ -63,8 +62,8 @@ namespace Duplicati.Library.AutoUpdater
|
||||
ReadResourceText(APP_NAME, OEM_APP_NAME);
|
||||
ReadResourceText(UPDATE_URL, OEM_UPDATE_URL);
|
||||
ReadResourceText(UPDATE_KEY, OEM_UPDATE_KEY);
|
||||
ReadResourceText(UPDATE_README, OEM_UPDATE_README);
|
||||
ReadResourceText(UPDATE_INSTALL_FILE, OEM_UPDATE_INSTALL_FILE);
|
||||
ReadResourceText(UPDATE_MACHINE_FILE, null);
|
||||
ReadResourceText(UPDATE_CHANNEL, null);
|
||||
}
|
||||
|
||||
@@ -104,8 +103,8 @@ namespace Duplicati.Library.AutoUpdater
|
||||
|
||||
public static string[] URLs
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UsesAlternateURLs)
|
||||
return Environment.GetEnvironmentVariable(string.Format(UPDATEURL_ENVNAME_TEMPLATE, AppName)).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
else
|
||||
@@ -115,7 +114,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
|
||||
public static bool UsesAlternateURLs
|
||||
{
|
||||
get
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(string.Format(UPDATEURL_ENVNAME_TEMPLATE, AppName)));
|
||||
}
|
||||
@@ -129,14 +128,14 @@ namespace Duplicati.Library.AutoUpdater
|
||||
|
||||
if (UsesAlternateURLs && string.IsNullOrWhiteSpace(channelstring))
|
||||
{
|
||||
foreach(var url in URLs)
|
||||
foreach (var url in URLs)
|
||||
{
|
||||
var match = AutoUpdateSettings.MATCH_AUTOUPDATE_URL.Match(url);
|
||||
if (match.Success)
|
||||
{
|
||||
channelstring = match.Groups[AutoUpdateSettings.MATCH_UPDATE_URL_CHANNEL_GROUP].Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +147,7 @@ namespace Duplicati.Library.AutoUpdater
|
||||
channelstring = ReleaseType.Experimental.ToString();
|
||||
if (string.Equals(channelstring, "rene", StringComparison.OrdinalIgnoreCase))
|
||||
channelstring = ReleaseType.Canary.ToString();
|
||||
|
||||
|
||||
ReleaseType rt;
|
||||
if (!Enum.TryParse<ReleaseType>(channelstring, true, out rt))
|
||||
rt = ReleaseType.Stable;
|
||||
@@ -167,16 +166,14 @@ namespace Duplicati.Library.AutoUpdater
|
||||
get { return ReadResourceText(UPDATE_CHANNEL, null); }
|
||||
}
|
||||
|
||||
public static string UpdateFolderReadme
|
||||
{
|
||||
get { return ReadResourceText(UPDATE_README, OEM_UPDATE_README); }
|
||||
}
|
||||
|
||||
public static string UpdateInstallFileText
|
||||
{
|
||||
get { return string.Format(ReadResourceText(UPDATE_INSTALL_FILE, OEM_UPDATE_INSTALL_FILE), Guid.NewGuid().ToString("N")); }
|
||||
}
|
||||
|
||||
public static string UpdateMachineFileText(string machineid)
|
||||
=> string.Format(ReadResourceText(UPDATE_MACHINE_FILE, "{0}"), string.IsNullOrWhiteSpace(machineid) ? Guid.NewGuid().ToString("N") : machineid);
|
||||
|
||||
public static System.Security.Cryptography.RSACryptoServiceProvider[] SignKeys
|
||||
{
|
||||
get
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<EmbeddedResource Include="AutoUpdateAppName.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateSignKeys.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateURL.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateFolderReadme.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateInstallIDTemplate.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateMachineIDTemplate.txt" />
|
||||
<EmbeddedResource Include="AutoUpdateBuildChannel.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -91,14 +91,15 @@ namespace Duplicati.Library.AutoUpdater
|
||||
/// </summary>
|
||||
private const string PACKAGE_TYPE_FILE = "package_type_id.txt";
|
||||
/// <summary>
|
||||
/// The README file stored in the <see cref="UPDATEDIR"/> folder, explaining what the folder is for
|
||||
/// </summary>
|
||||
private const string README_FILE = "README.txt";
|
||||
/// <summary>
|
||||
/// The installation ID filename stored in <see cref="UPDATEDIR"/>
|
||||
/// </summary>
|
||||
private const string INSTALL_FILE = "installation.txt";
|
||||
|
||||
/// <summary>
|
||||
/// The machine ID filename stored in <see cref="UPDATEDIR"/>
|
||||
/// </summary>
|
||||
private const string MACHINE_FILE = "machineid.txt";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last version found from an update
|
||||
/// </summary>
|
||||
@@ -119,19 +120,31 @@ namespace Duplicati.Library.AutoUpdater
|
||||
var candidates = new List<string>();
|
||||
if (Platform.IsClientWindows)
|
||||
{
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME, "updates"));
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"));
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME));
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Platform.IsClientOSX)
|
||||
candidates.Add(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support", APPNAME, "updates"));
|
||||
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"));
|
||||
candidates.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME));
|
||||
}
|
||||
|
||||
if (Platform.IsClientOSX)
|
||||
candidates.Add(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support", APPNAME));
|
||||
|
||||
// Find the first writeable directory in the list
|
||||
UPDATEDIR = candidates.FirstOrDefault(p => !string.IsNullOrWhiteSpace(p) && System.IO.Directory.Exists(p) && TestDirectoryIsWriteable(p));
|
||||
|
||||
// Try to create a writeable folder, if none is found
|
||||
if (string.IsNullOrWhiteSpace(UPDATEDIR))
|
||||
UPDATEDIR = candidates.Where(p => !string.IsNullOrWhiteSpace(p) && !System.IO.Directory.Exists(p))
|
||||
.Select(p =>
|
||||
{
|
||||
try { System.IO.Directory.CreateDirectory(p); }
|
||||
catch { }
|
||||
return p;
|
||||
})
|
||||
.Where(p => System.IO.Directory.Exists(p) && TestDirectoryIsWriteable(p))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -141,10 +154,18 @@ namespace Duplicati.Library.AutoUpdater
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(UPDATEDIR))
|
||||
{
|
||||
if (!System.IO.File.Exists(System.IO.Path.Combine(UPDATEDIR, README_FILE)))
|
||||
System.IO.File.WriteAllText(System.IO.Path.Combine(UPDATEDIR, README_FILE), AutoUpdateSettings.UpdateFolderReadme);
|
||||
if (!System.IO.File.Exists(System.IO.Path.Combine(UPDATEDIR, INSTALL_FILE)))
|
||||
System.IO.File.WriteAllText(System.IO.Path.Combine(UPDATEDIR, INSTALL_FILE), AutoUpdateSettings.UpdateInstallFileText);
|
||||
{
|
||||
// In case there was already a machine id file, copy it to the new location
|
||||
if (System.IO.File.Exists(System.IO.Path.Combine(UPDATEDIR, "updates", INSTALL_FILE)))
|
||||
System.IO.File.Copy(System.IO.Path.Combine(UPDATEDIR, "updates", INSTALL_FILE), System.IO.Path.Combine(UPDATEDIR, INSTALL_FILE), true);
|
||||
else
|
||||
System.IO.File.WriteAllText(System.IO.Path.Combine(UPDATEDIR, INSTALL_FILE), AutoUpdateSettings.UpdateInstallFileText);
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(System.IO.Path.Combine(UPDATEDIR, MACHINE_FILE)))
|
||||
System.IO.File.WriteAllText(System.IO.Path.Combine(UPDATEDIR, MACHINE_FILE), AutoUpdateSettings.UpdateMachineFileText(InstallID));
|
||||
|
||||
}
|
||||
|
||||
// Attempt to read the installed manifest file
|
||||
@@ -226,6 +247,23 @@ namespace Duplicati.Library.AutoUpdater
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unique machine ID
|
||||
/// </summary>
|
||||
public static string MachineID
|
||||
{
|
||||
get
|
||||
{
|
||||
string machinedId = null;
|
||||
try { machinedId = System.IO.File.ReadAllLines(System.IO.Path.Combine(UPDATEDIR, MACHINE_FILE)).FirstOrDefault(x => !string.IsNullOrWhiteSpace(x))?.Trim() ?? ""; }
|
||||
catch { }
|
||||
|
||||
return string.IsNullOrWhiteSpace(machinedId)
|
||||
? InstallID
|
||||
: machinedId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The package type ID
|
||||
/// </summary>
|
||||
|
||||
@@ -346,7 +346,7 @@ namespace Duplicati.Library.Modules.Builtin
|
||||
if (input.IndexOf("%machine-id%", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
if (!m_options.ContainsKey("machine-id"))
|
||||
extra["machine-id"] = Library.AutoUpdater.UpdaterManager.InstallID;
|
||||
extra["machine-id"] = Library.AutoUpdater.UpdaterManager.MachineID;
|
||||
}
|
||||
|
||||
if (input.IndexOf("%backup-id%", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
@@ -394,7 +394,7 @@ namespace Duplicati.Library.Modules.Builtin
|
||||
input = Regex.Replace(input, "\\%backup-id\\%", Library.Utility.Utility.ByteArrayAsHexString(Library.Utility.Utility.RepeatedHashWithSalt(m_remoteurl, SALT)), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
if (!m_options.ContainsKey("machine-id"))
|
||||
input = Regex.Replace(input, "\\%machine-id\\%", Library.AutoUpdater.UpdaterManager.InstallID, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
input = Regex.Replace(input, "\\%machine-id\\%", Library.AutoUpdater.UpdaterManager.MachineID, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
input = Regex.Replace(input, "\\%[^\\%]+\\%", "");
|
||||
return input;
|
||||
|
||||
Reference in New Issue
Block a user