Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate downloaded files against metadata before adding to cache #2243

Merged
merged 1 commit into from
Jan 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions ConsoleUI/DownloadImportDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Cryptography;
using CKAN.ConsoleUI.Toolkit;

namespace CKAN.ConsoleUI {
Expand Down Expand Up @@ -74,7 +73,7 @@ public static void ImportFiles(KSP gameInst, HashSet<FileInfo> files,
int percent = i * 100 / files.Count;
user.RaiseProgress($"Importing {f.Name}... ({percent}%)", percent);
// Calc SHA-1 sum
string sha1 = GetFileHashSha1(f.FullName);
string sha1 = NetModuleCache.GetFileHashSha1(f.FullName);
// Find SHA-1 sum in registry (potentially multiple)
if (index.ContainsKey(sha1)) {
deletable.Add(f);
Expand All @@ -83,11 +82,11 @@ public static void ImportFiles(KSP gameInst, HashSet<FileInfo> files,
if (mod.IsCompatibleKSP(gameInst.VersionCriteria())) {
installable.Add(mod.identifier);
}
if (inst.Cache.IsCachedZip(mod.download)) {
if (inst.Cache.IsMaybeCachedZip(mod)) {
user.RaiseMessage("Already cached: {0}", f.Name);
} else {
user.RaiseMessage($"Importing {mod.identifier} {Formatting.StripEpoch(mod.version)}...");
inst.Cache.Store(mod.download, f.FullName);
inst.Cache.Store(mod, f.FullName);
}
}
} else {
Expand All @@ -109,16 +108,6 @@ public static void ImportFiles(KSP gameInst, HashSet<FileInfo> files,
}
}

private static string GetFileHashSha1(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (SHA1Cng sha1 = new SHA1Cng())
{
return BitConverter.ToString(sha1.ComputeHash(bs)).Replace("-", "");
}
}

}

}
4 changes: 2 additions & 2 deletions ConsoleUI/ModInfoScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m, bool dbg)
AddBinding(Keys.Escape, (object sender) => false);

AddTip("Ctrl+D", "Download",
() => !manager.CurrentInstance.Cache.IsCachedZip(mod.download)
() => !manager.CurrentInstance.Cache.IsMaybeCachedZip(mod)
);
AddBinding(Keys.CtrlD, (object sender) => {
Download();
Expand Down Expand Up @@ -459,7 +459,7 @@ private void Download()
() => {
try {
dl.DownloadModules(inst.Cache, new List<CkanModule> {mod});
if (!inst.Cache.IsCachedZip(mod.download)) {
if (!inst.Cache.IsMaybeCachedZip(mod)) {
ps.RaiseError("Download failed, file is corrupted");
}
} catch (Exception ex) {
Expand Down
1 change: 1 addition & 0 deletions Core/CKAN-core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
<Compile Include="Net\NetAsyncDownloader.cs" />
<Compile Include="Net\NetAsyncModulesDownloader.cs" />
<Compile Include="Net\NetFileCache.cs" />
<Compile Include="Net\NetModuleCache.cs" />
<Compile Include="Net\Repo.cs" />
<Compile Include="Platform.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
4 changes: 2 additions & 2 deletions Core/KSP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class KSP : IDisposable
public KspVersion VersionOfKspWhenCompatibleVersionsWereStored { get; private set; }
public bool CompatibleVersionsAreFromDifferentKsp { get { return _compatibleVersions.Count > 0 && VersionOfKspWhenCompatibleVersionsWereStored != Version(); } }

public NetFileCache Cache { get; private set; }
public NetModuleCache Cache { get; private set; }

#endregion
#region Construction and Initialisation
Expand All @@ -56,7 +56,7 @@ public KSP(string gameDir, string name, IUser user)
{
SetupCkanDirectories();
LoadCompatibleVersions();
Cache = new NetFileCache(DownloadCacheDir());
Cache = new NetModuleCache(DownloadCacheDir());
}
}

Expand Down
62 changes: 20 additions & 42 deletions Core/ModuleInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class ModuleInstaller
public ModuleInstallerReportModInstalled onReportModInstalled = null;

// Our own cache is that of the KSP instance we're using.
public NetFileCache Cache
public NetModuleCache Cache
{
get
{
Expand Down Expand Up @@ -84,22 +84,22 @@ public static ModuleInstaller GetInstance(KSP ksp_instance, IUser user)
/// <summary>
/// Downloads the given mod to the cache. Returns the filename it was saved to.
/// </summary>
public string Download(Uri url, string filename)
public string Download(CkanModule module, string filename)
{
User.RaiseProgress(String.Format("Downloading \"{0}\"", url), 0);
return Download(url, filename, Cache);
User.RaiseProgress(String.Format("Downloading \"{0}\"", module.download), 0);
return Download(module, filename, Cache);
}

/// <summary>
/// Downloads the given mod to the cache. Returns the filename it was saved to.
/// </summary>
public static string Download(Uri url, string filename, NetFileCache cache)
public static string Download(CkanModule module, string filename, NetModuleCache cache)
{
log.Info("Downloading " + filename);

string tmp_file = Net.Download(url);
string tmp_file = Net.Download(module.download);

return cache.Store(url, tmp_file, filename, true);
return cache.Store(module, tmp_file, filename, true);
}

/// <summary>
Expand All @@ -111,19 +111,7 @@ public static string Download(Uri url, string filename, NetFileCache cache)
/// </summary>
public string CachedOrDownload(CkanModule module, string filename = null)
{
return CachedOrDownload(module.identifier, module.version, module.download, Cache, filename);
}

/// <summary>
/// Returns the path to a cached copy of a module if it exists, or downloads
/// and returns the downloaded copy otherwise.
///
/// If no filename is provided, the module's standard name will be used.
/// Chcecks the CKAN cache first.
/// </summary>
public string CachedOrDownload(string identifier, Version version, Uri url, string filename = null)
{
return CachedOrDownload(identifier, version, url, Cache, filename);
return CachedOrDownload(module, Cache, filename);
}

/// <summary>
Expand All @@ -133,32 +121,27 @@ public string CachedOrDownload(string identifier, Version version, Uri url, stri
/// If no filename is provided, the module's standard name will be used.
/// Chcecks provided cache first.
/// </summary>
public static string CachedOrDownload(string identifier, Version version, Uri url, NetFileCache cache, string filename = null)
public static string CachedOrDownload(CkanModule module, NetModuleCache cache, string filename = null)
{
if (filename == null)
{
filename = CkanModule.StandardName(identifier, version);
filename = CkanModule.StandardName(module.identifier, module.version);
}

string full_path = cache.GetCachedZip(url);
string full_path = cache.GetCachedZip(module);
if (full_path == null)
{
return Download(url, filename, cache);
return Download(module, filename, cache);
}

log.DebugFormat("Using {0} (cached)", filename);
return full_path;
}

public void InstallList(
List<string> modules,
RelationshipResolverOptions options,
IDownloader downloader = null
)
public void InstallList(List<string> modules, RelationshipResolverOptions options, IDownloader downloader = null)
{
var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.VersionCriteria());
var modsToInstall = resolver.ModList().ToList();
InstallList(modsToInstall, options, downloader);
InstallList(resolver.ModList().ToList(), options, downloader);
}

/// <summary>
Expand All @@ -169,14 +152,9 @@ public void InstallList(
/// Propagates a FileExistsKraken if we were going to overwrite a file.
/// Propagates a CancelledActionKraken if the user cancelled the install.
/// </summary>
//
// TODO: Break this up into smaller pieces! It's huge!
public void InstallList(
ICollection<CkanModule> modules,
RelationshipResolverOptions options,
IDownloader downloader = null
)
public void InstallList(ICollection<CkanModule> modules, RelationshipResolverOptions options, IDownloader downloader = null)
{
// TODO: Break this up into smaller pieces! It's huge!
var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.VersionCriteria());
var modsToInstall = resolver.ModList().ToList();
List<CkanModule> downloads = new List<CkanModule>();
Expand All @@ -188,7 +166,7 @@ public void InstallList(

foreach (CkanModule module in modsToInstall)
{
if (!ksp.Cache.IsCachedZip(module.download))
if (!ksp.Cache.IsCachedZip(module))
{
User.RaiseMessage(" * {0} {1} ({2})", module.name, module.version, module.download.Host);
downloads.Add(module);
Expand Down Expand Up @@ -287,7 +265,7 @@ public void InstallList(ModuleResolution modules, RelationshipResolverOptions op
// TODO: Return files relative to GameRoot
public IEnumerable<string> GetModuleContentsList(CkanModule module)
{
string filename = ksp.Cache.GetCachedZip(module.download);
string filename = ksp.Cache.GetCachedZip(module);

if (filename == null)
{
Expand Down Expand Up @@ -327,7 +305,7 @@ private void Install(CkanModule module, string filename = null)
}

// Find our in the cache if we don't already have it.
filename = filename ?? Cache.GetCachedZip(module.download, true);
filename = filename ?? Cache.GetCachedZip(module);

// If we *still* don't have a file, then kraken bitterly.
if (filename == null)
Expand Down Expand Up @@ -1099,7 +1077,7 @@ public void Upgrade(IEnumerable<CkanModule> modules, IDownloader netAsyncDownloa
/// </summary>
private void DownloadModules(IEnumerable<CkanModule> mods, IDownloader downloader)
{
List<CkanModule> downloads = mods.Where(module => !ksp.Cache.IsCachedZip(module.download)).ToList();
List<CkanModule> downloads = mods.Where(module => !ksp.Cache.IsCachedZip(module)).ToList();

if (downloads.Count > 0)
{
Expand Down
4 changes: 2 additions & 2 deletions Core/Net/IDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ public interface IDownloader
/// Even if modules share download URLs, they will only be downloaded once.
/// Blocks until the downloads are complete, cancelled, or errored.
/// </summary>
void DownloadModules(NetFileCache cache, IEnumerable<CkanModule> modules);
void DownloadModules(NetModuleCache cache, IEnumerable<CkanModule> modules);

/// <summary>
/// Cancel any running downloads.
/// </summary>
void CancelDownload();
}
}
}
15 changes: 6 additions & 9 deletions Core/Net/NetAsyncModulesDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,29 @@ public class NetAsyncModulesDownloader : IDownloader
{
public IUser User
{
get { return downloader.User; }
get { return downloader.User; }
set { downloader.User = value; }
}

private static readonly ILog log = LogManager.GetLogger(typeof (NetAsyncModulesDownloader));

private List<CkanModule> modules;
private List<CkanModule> modules;
private readonly NetAsyncDownloader downloader;

/// <summary>
/// Returns a perfectly boring NetAsyncModulesDownloader.
/// </summary>
public NetAsyncModulesDownloader(IUser user)
{
modules = new List<CkanModule>();
modules = new List<CkanModule>();
downloader = new NetAsyncDownloader(user);
}


/// <summary>
/// <see cref="IDownloader.DownloadModules(NetFileCache, IEnumerable{CkanModule})"/>
/// </summary>
public void DownloadModules(
NetFileCache cache,
IEnumerable<CkanModule> modules
)
public void DownloadModules(NetModuleCache cache, IEnumerable<CkanModule> modules)
{
// Walk through all our modules, but only keep the first of each
// one that has a unique download path.
Expand Down Expand Up @@ -67,7 +64,7 @@ IEnumerable<CkanModule> modules
/// Called by NetAsyncDownloader on completion.
/// Called with all nulls on download cancellation.
/// </summary>
private void ModuleDownloadsComplete(NetFileCache cache, Uri[] urls, string[] filenames, Exception[] errors)
private void ModuleDownloadsComplete(NetModuleCache cache, Uri[] urls, string[] filenames, Exception[] errors)
{
if (urls != null)
{
Expand Down Expand Up @@ -98,7 +95,7 @@ private void ModuleDownloadsComplete(NetFileCache cache, Uri[] urls, string[] fi

try
{
cache.Store(urls[i], filenames[i], modules[i].StandardName());
cache.Store(modules[i], filenames[i], modules[i].StandardName());
}
catch (FileNotFoundException e)
{
Expand Down
Loading