builtins.{fetchurl,fetchTarball}: Support a sha256 attribute
Also, allow builtins.{fetchurl,fetchTarball} in restricted mode if a hash is specified.
This commit is contained in:
parent
ee3032e4de
commit
06bbfb6004
3 changed files with 37 additions and 12 deletions
|
@ -1680,9 +1680,8 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
|
||||||
void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
||||||
const string & who, bool unpack)
|
const string & who, bool unpack)
|
||||||
{
|
{
|
||||||
if (state.restricted) throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
|
|
||||||
|
|
||||||
string url;
|
string url;
|
||||||
|
Hash expectedHash;
|
||||||
|
|
||||||
state.forceValue(*args[0]);
|
state.forceValue(*args[0]);
|
||||||
|
|
||||||
|
@ -1694,6 +1693,8 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
||||||
string name(attr.name);
|
string name(attr.name);
|
||||||
if (name == "url")
|
if (name == "url")
|
||||||
url = state.forceStringNoCtx(*attr.value, *attr.pos);
|
url = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||||
|
else if (name == "sha256")
|
||||||
|
expectedHash = parseHash16or32(htSHA256, state.forceStringNoCtx(*attr.value, *attr.pos));
|
||||||
else
|
else
|
||||||
throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
|
throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
|
||||||
}
|
}
|
||||||
|
@ -1704,7 +1705,10 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
||||||
} else
|
} else
|
||||||
url = state.forceStringNoCtx(*args[0], pos);
|
url = state.forceStringNoCtx(*args[0], pos);
|
||||||
|
|
||||||
Path res = makeDownloader()->downloadCached(state.store, url, unpack);
|
if (state.restricted && !expectedHash)
|
||||||
|
throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
|
||||||
|
|
||||||
|
Path res = makeDownloader()->downloadCached(state.store, url, unpack, expectedHash);
|
||||||
mkString(v, res, PathSet({res}));
|
mkString(v, res, PathSet({res}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
#include "archive.hh"
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
@ -221,10 +222,21 @@ ref<Downloader> makeDownloader()
|
||||||
return make_ref<CurlDownloader>();
|
return make_ref<CurlDownloader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack)
|
Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, const Hash & expectedHash)
|
||||||
{
|
{
|
||||||
auto url = resolveUri(url_);
|
auto url = resolveUri(url_);
|
||||||
|
|
||||||
|
string name;
|
||||||
|
auto p = url.rfind('/');
|
||||||
|
if (p != string::npos) name = string(url, p + 1);
|
||||||
|
|
||||||
|
Path expectedStorePath;
|
||||||
|
if (expectedHash) {
|
||||||
|
expectedStorePath = store->makeFixedOutputPath(unpack, expectedHash.type, expectedHash, name);
|
||||||
|
if (store->isValidPath(expectedStorePath))
|
||||||
|
return expectedStorePath;
|
||||||
|
}
|
||||||
|
|
||||||
Path cacheDir = getCacheDir() + "/nix/tarballs";
|
Path cacheDir = getCacheDir() + "/nix/tarballs";
|
||||||
createDirs(cacheDir);
|
createDirs(cacheDir);
|
||||||
|
|
||||||
|
@ -258,10 +270,6 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
|
||||||
storePath = "";
|
storePath = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
string name;
|
|
||||||
auto p = url.rfind('/');
|
|
||||||
if (p != string::npos) name = string(url, p + 1);
|
|
||||||
|
|
||||||
if (!skip) {
|
if (!skip) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -269,8 +277,16 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
|
||||||
options.expectedETag = expectedETag;
|
options.expectedETag = expectedETag;
|
||||||
auto res = download(url, options);
|
auto res = download(url, options);
|
||||||
|
|
||||||
if (!res.cached)
|
if (!res.cached) {
|
||||||
storePath = store->addTextToStore(name, *res.data, PathSet(), false);
|
ValidPathInfo info;
|
||||||
|
StringSink sink;
|
||||||
|
dumpString(*res.data, sink);
|
||||||
|
Hash hash = hashString(expectedHash ? expectedHash.type : htSHA256, *res.data);
|
||||||
|
info.path = store->makeFixedOutputPath(false, hash.type, hash, name);
|
||||||
|
info.narHash = hashString(htSHA256, *sink.s);
|
||||||
|
store->addToStore(info, *sink.s, false, true);
|
||||||
|
storePath = info.path;
|
||||||
|
}
|
||||||
|
|
||||||
assert(!storePath.empty());
|
assert(!storePath.empty());
|
||||||
replaceSymlink(storePath, fileLink);
|
replaceSymlink(storePath, fileLink);
|
||||||
|
@ -300,9 +316,12 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa
|
||||||
unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false);
|
unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false);
|
||||||
}
|
}
|
||||||
replaceSymlink(unpackedStorePath, unpackedLink);
|
replaceSymlink(unpackedStorePath, unpackedLink);
|
||||||
return unpackedStorePath;
|
storePath = unpackedStorePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expectedStorePath != "" && storePath != expectedStorePath)
|
||||||
|
throw nix::Error(format("hash mismatch in file downloaded from ‘%s’") % url);
|
||||||
|
|
||||||
return storePath;
|
return storePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
#include "hash.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -27,7 +28,8 @@ struct Downloader
|
||||||
{
|
{
|
||||||
virtual DownloadResult download(string url, const DownloadOptions & options) = 0;
|
virtual DownloadResult download(string url, const DownloadOptions & options) = 0;
|
||||||
|
|
||||||
Path downloadCached(ref<Store> store, const string & url, bool unpack);
|
Path downloadCached(ref<Store> store, const string & url, bool unpack,
|
||||||
|
const Hash & expectedHash = Hash());
|
||||||
|
|
||||||
enum Error { NotFound, Forbidden, Misc };
|
enum Error { NotFound, Forbidden, Misc };
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue