Return 400 status for invalid hashes
This commit is contained in:
@@ -51,6 +51,7 @@ executable nix-serve-ng
|
|||||||
, base32
|
, base32
|
||||||
, bsd-sysctl
|
, bsd-sysctl
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, charset
|
||||||
, http-types
|
, http-types
|
||||||
, managed
|
, managed
|
||||||
, megaparsec
|
, megaparsec
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
{ mkDerivation, base, base16, base32, bsd-sysctl, bytestring
|
{ mkDerivation, base, base16, base32, bsd-sysctl, bytestring
|
||||||
, http-types, lib, managed, megaparsec, mtl, network, nixstore
|
, charset, http-types, lib, managed, megaparsec, mtl, network
|
||||||
, nixutil, optparse-applicative, vector, wai, wai-extra, warp
|
, nixstore, nixutil, optparse-applicative, vector, wai, wai-extra
|
||||||
, warp-tls
|
, warp, warp-tls
|
||||||
}:
|
}:
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
pname = "nix-serve-ng";
|
pname = "nix-serve-ng";
|
||||||
version = "1.0.0";
|
version = "1.0.0";
|
||||||
src = ./.;
|
src = ./..;
|
||||||
isLibrary = false;
|
isLibrary = false;
|
||||||
isExecutable = true;
|
isExecutable = true;
|
||||||
executableHaskellDepends = [
|
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
|
megaparsec mtl network optparse-applicative vector wai wai-extra
|
||||||
warp warp-tls
|
warp warp-tls
|
||||||
];
|
];
|
||||||
|
|||||||
35
src/Main.hs
35
src/Main.hs
@@ -8,6 +8,7 @@ module Main where
|
|||||||
|
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import Data.CharSet.ByteSet (ByteSet(..))
|
||||||
import Data.Function ((&))
|
import Data.Function ((&))
|
||||||
import Network.Socket (SockAddr(..))
|
import Network.Socket (SockAddr(..))
|
||||||
import Network.Wai (Application)
|
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.Char8 as ByteString.Char8
|
||||||
import qualified Data.ByteString.Builder as Builder
|
import qualified Data.ByteString.Builder as Builder
|
||||||
import qualified Data.ByteString.Lazy as ByteString.Lazy
|
import qualified Data.ByteString.Lazy as ByteString.Lazy
|
||||||
|
import qualified Data.CharSet.ByteSet as ByteSet
|
||||||
import qualified Data.Vector as Vector
|
import qualified Data.Vector as Vector
|
||||||
import qualified Data.Void as Void
|
import qualified Data.Void as Void
|
||||||
import qualified Network.HTTP.Types as Types
|
import qualified Network.HTTP.Types as Types
|
||||||
@@ -41,6 +43,22 @@ data ApplicationOptions = ApplicationOptions
|
|||||||
, secretKey :: Maybe ByteString
|
, 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 -> Application
|
||||||
makeApplication ApplicationOptions{..} request respond = do
|
makeApplication ApplicationOptions{..} request respond = do
|
||||||
let stripStore = ByteString.stripPrefix (storeDirectory <> "/")
|
let stripStore = ByteString.stripPrefix (storeDirectory <> "/")
|
||||||
@@ -63,8 +81,21 @@ makeApplication ApplicationOptions{..} request respond = do
|
|||||||
result <- Except.runExceptT do
|
result <- Except.runExceptT do
|
||||||
let rawPath = Wai.rawPathInfo request
|
let rawPath = Wai.rawPathInfo request
|
||||||
|
|
||||||
if | Just suffix <- ByteString.stripSuffix ".narinfo" rawPath
|
if | Just prefix <- ByteString.stripSuffix ".narinfo" rawPath
|
||||||
, Just hashPart <- ByteString.stripPrefix "/" suffix -> do
|
, 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)
|
maybeStorePath <- liftIO (Nix.queryPathFromHashPart hashPart)
|
||||||
|
|
||||||
storePath <- case maybeStorePath of
|
storePath <- case maybeStorePath of
|
||||||
|
|||||||
Reference in New Issue
Block a user