Return 400 status for invalid hashes

This commit is contained in:
Gabriella Gonzalez 2022-06-30 13:28:50 -07:00
parent 87daaac881
commit 7f1251cc47
3 changed files with 39 additions and 7 deletions

View File

@ -51,6 +51,7 @@ executable nix-serve-ng
, base32
, bsd-sysctl
, bytestring
, charset
, http-types
, managed
, megaparsec

View File

@ -1,16 +1,16 @@
{ mkDerivation, base, base16, base32, bsd-sysctl, bytestring
, http-types, lib, managed, megaparsec, mtl, network, nixstore
, nixutil, optparse-applicative, vector, wai, wai-extra, warp
, warp-tls
, charset, http-types, lib, managed, megaparsec, mtl, network
, nixstore, nixutil, optparse-applicative, vector, wai, wai-extra
, warp, warp-tls
}:
mkDerivation {
pname = "nix-serve-ng";
version = "1.0.0";
src = ./.;
src = ./..;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
base base16 base32 bsd-sysctl bytestring http-types managed
base base16 base32 bsd-sysctl bytestring charset http-types managed
megaparsec mtl network optparse-applicative vector wai wai-extra
warp warp-tls
];

View File

@ -8,6 +8,7 @@ module Main where
import Control.Monad.IO.Class (liftIO)
import Data.ByteString (ByteString)
import Data.CharSet.ByteSet (ByteSet(..))
import Data.Function ((&))
import Network.Socket (SockAddr(..))
import Network.Wai (Application)
@ -21,6 +22,7 @@ import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as ByteString.Char8
import qualified Data.ByteString.Builder as Builder
import qualified Data.ByteString.Lazy as ByteString.Lazy
import qualified Data.CharSet.ByteSet as ByteSet
import qualified Data.Vector as Vector
import qualified Data.Void as Void
import qualified Network.HTTP.Types as Types
@ -41,6 +43,22 @@ data ApplicationOptions = ApplicationOptions
, secretKey :: Maybe ByteString
}
-- https://github.com/NixOS/nix/blob/2.8.1/src/libutil/hash.cc#L83-L84
validHashPartBytes :: ByteSet
validHashPartBytes =
ByteSet.fromList
( [ 0x30 .. 0x39 ] -- 0..9
<> [ 0x61 .. 0x64 ] -- abcd
<> [ 0x66 .. 0x6e ] -- fghijklmn
<> [ 0x70 .. 0x73 ] -- pqrs
<> [ 0x76 .. 0x7a ] -- vwxyz
)
validHashPart :: ByteString -> Bool
validHashPart hash =
ByteString.length hash == 32
&& ByteString.all (`ByteSet.member` validHashPartBytes) hash
makeApplication :: ApplicationOptions -> Application
makeApplication ApplicationOptions{..} request respond = do
let stripStore = ByteString.stripPrefix (storeDirectory <> "/")
@ -63,8 +81,21 @@ makeApplication ApplicationOptions{..} request respond = do
result <- Except.runExceptT do
let rawPath = Wai.rawPathInfo request
if | Just suffix <- ByteString.stripSuffix ".narinfo" rawPath
, Just hashPart <- ByteString.stripPrefix "/" suffix -> do
if | Just prefix <- ByteString.stripSuffix ".narinfo" rawPath
, Just hashPart <- ByteString.stripPrefix "/" prefix -> do
Monad.unless (validHashPart hashPart) do
let headers = [ ("Content-Type", "text/plain") ]
let builder = "Invalid hash part.\n"
let response =
Wai.responseBuilder
Types.status400
headers
builder
done response
maybeStorePath <- liftIO (Nix.queryPathFromHashPart hashPart)
storePath <- case maybeStorePath of