Compare commits

..

4 Commits

Author SHA1 Message Date
d676436e38
Fix private file path checks 2025-10-06 14:35:11 +02:00
70ea76007c
Sample package 2025-10-06 14:33:59 +02:00
2ef34fe396
Add debug output 2025-10-06 14:33:59 +02:00
9126d8d979
Do not serve derivations with /.private 2025-10-06 14:33:59 +02:00
2 changed files with 26 additions and 8 deletions

View File

@ -83,6 +83,10 @@
rec {
packages = {
inherit nix-serve-ng lix-serve-ng;
private = pkgs.runCommand "private" { } ''
mkdir $out
touch $out/.private
'';
default = nix-serve-ng;
};

View File

@ -12,6 +12,7 @@ import Control.Monad.IO.Class (liftIO)
import Data.ByteString (ByteString)
import Data.CharSet.ByteSet (ByteSet(..))
import Data.Function ((&))
import Data.Word (Word8)
import Network.Socket (SockAddr(..))
import Network.Wai (Application)
import Nix (NoSuchPath(..), PathInfo(..))
@ -57,6 +58,20 @@ validHashPartBytes =
<> [ 0x76 .. 0x7A ] -- vwxyz
)
type HostAddressTuple = (Word8, Word8, Word8, Word8)
isAllowed :: Socket.HostAddress -> Bool
isAllowed host = any (uncurry (ipMatches $ Socket.hostAddressToTuple host)) allowedIPs
where
allowedIPs :: [(HostAddressTuple, HostAddressTuple)]
allowedIPs = [
((127,0,0,1), (127,0,0,1)),
((10,0,0,1), (10,255,255,254)),
((192,168,72,1), (192,168,79,254))
]
ipMatches ip a b = ip >= a && ip <= b
validHashPart :: ByteString -> Bool
validHashPart hash = ByteString.all (`ByteSet.member` validHashPartBytes) hash
@ -253,22 +268,21 @@ makeApplication ApplicationOptions{..} request respond = do
done response
isPrivate <- not <$> liftIO (Directory.doesPathExist (ByteString.Char8.unpack storePath ++ "/.private"))
let privateFilePath = ByteString.Char8.unpack storePath ++ "/.private"
isPrivate <- liftIO $ Directory.doesPathExist privateFilePath
let sockAddr = Wai.remoteHost request
hostAddr <- case sockAddr of
SockAddrInet _ host -> return host
_ -> return $ Socket.tupleToHostAddress (255, 255, 255, 255)
let isInternalClient = hostAddr >= Socket.tupleToHostAddress (10, 0, 0, 0) && hostAddr < Socket.tupleToHostAddress (11, 0, 0, 0)
traceM $ show (Socket.hostAddressToTuple hostAddr, isAllowed hostAddr)
traceM $ show (privateFilePath, isPrivate)
traceM $ show (ByteString.Char8.unpack storePath, "private", isPrivate,
"host", hostAddr,
"isInternalClient", isInternalClient
)
Monad.unless (isInternalClient || not isPrivate) do
Monad.when (isPrivate && (not $ isAllowed hostAddr)) do
let headers = [ ("Content-Type", "text/plain") ]
let builder = "Forbbiden.\n"
let builder = "Forbidden.\n"
let response =
Wai.responseBuilder