From 19aa892f2064d437d32a3c12758d6a623b7ae8e5 Mon Sep 17 00:00:00 2001
From: Matthew Bauer <mjbauer95@gmail.com>
Date: Tue, 9 Jun 2020 11:10:54 -0500
Subject: [PATCH] Support empty hash in fetchers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

fetchTarball, fetchTree, and fetchGit all have *optional* hash attrs.
This means that we need to be careful with what we allow to avoid
accidentally making these defaults. When ‘hash = ""’ we assume the
empty hash is wanted.
---
 src/libexpr/primops.cc           | 11 ++++++++---
 src/libexpr/primops/fetchTree.cc | 11 ++++++++---
 src/libfetchers/fetchers.cc      | 11 ++++++++---
 src/libfetchers/tarball.cc       | 11 ++++++++---
 4 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index de04fd2be..df3d4a459 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1131,9 +1131,14 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
             filterFun = attr.value;
         } else if (n == "recursive")
             method = FileIngestionMethod { state.forceBool(*attr.value, *attr.pos) };
-        else if (n == "sha256")
-            expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
-        else
+        else if (n == "sha256") {
+            auto hashStr = state.forceStringNoCtx(*attr.value, *attr.pos);
+            if (hashStr == "") {
+                expectedHash = Hash(htSHA256);
+                printError("warning: found empty hash, assuming you wanted '%s'", expectedHash.to_string());
+            } else
+                expectedHash = Hash(hashStr, htSHA256);
+        } else
             throw EvalError(format("unsupported argument '%1%' to 'addPath', at %2%") % attr.name % *attr.pos);
     }
     if (path.empty())
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index c5a0d9886..745f65adf 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -102,9 +102,14 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
             string n(attr.name);
             if (n == "url")
                 url = state.forceStringNoCtx(*attr.value, *attr.pos);
-            else if (n == "sha256")
-                expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
-            else if (n == "name")
+            else if (n == "sha256") {
+                auto hashStr = state.forceStringNoCtx(*attr.value, *attr.pos);
+                if (hashStr == "") {
+                    expectedHash = Hash(htSHA256);
+                    printError("warning: found empty hash, assuming you wanted '%s'", expectedHash->to_string());
+                } else
+                    expectedHash = Hash(hashStr, htSHA256);
+            } else if (n == "name")
                 name = state.forceStringNoCtx(*attr.value, *attr.pos);
             else
                 throw EvalError("unsupported argument '%s' to '%s', at %s",
diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc
index 94ac30e38..988a8dc69 100644
--- a/src/libfetchers/fetchers.cc
+++ b/src/libfetchers/fetchers.cc
@@ -34,9 +34,14 @@ std::unique_ptr<Input> inputFromAttrs(const Attrs & attrs)
     for (auto & inputScheme : *inputSchemes) {
         auto res = inputScheme->inputFromAttrs(attrs2);
         if (res) {
-            if (auto narHash = maybeGetStrAttr(attrs, "narHash"))
-                // FIXME: require SRI hash.
-                res->narHash = Hash(*narHash);
+            if (auto narHash = maybeGetStrAttr(attrs, "narHash")) {
+                if (narHash->empty()) {
+                    res->narHash = Hash(htUnknown);
+                    printError("warning: found empty hash, assuming you wanted '%s'", res->narHash->to_string());
+                } else
+                    // FIXME: require SRI hash.
+                    res->narHash = Hash(*narHash);
+            }
             return res;
         }
     }
diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc
index b6e57379b..e4dafec0b 100644
--- a/src/libfetchers/tarball.cc
+++ b/src/libfetchers/tarball.cc
@@ -263,9 +263,14 @@ struct TarballInputScheme : InputScheme
                 throw Error("unsupported tarball input attribute '%s'", name);
 
         auto input = std::make_unique<TarballInput>(parseURL(getStrAttr(attrs, "url")));
-        if (auto hash = maybeGetStrAttr(attrs, "hash"))
-            // FIXME: require SRI hash.
-            input->hash = Hash(*hash);
+        if (auto hash = maybeGetStrAttr(attrs, "hash")) {
+            if (hash->empty()) {
+                input->hash = Hash(htUnknown);
+                printError("warning: found empty hash, assuming you wanted '%s'", input->hash->to_string());
+            } else
+                // FIXME: require SRI hash.
+                input->hash = Hash(*hash);
+        }
 
         return input;
     }
-- 
GitLab