espial-0.0.39: test/Handler/LocalesSpec.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Handler.LocalesSpec (spec) where
import Data.ByteString qualified as BS
import Handler.Locales (isSafePiece, isWithinDir)
import System.Directory
( createDirectoryIfMissing,
getTemporaryDirectory,
removeDirectoryRecursive,
)
import TestImport
spec :: Spec
spec = do
describe "Handler.Locales.isSafePiece" $ do
it "allows ordinary locale path segments" $ do
mapM_
(`shouldSatisfy` isSafePiece)
["en", "translation.json", "pt-BR", "zh_CN", "a.b-c_9"]
it "rejects empty segments" $
isSafePiece "" `shouldBe` False
it "rejects '.' and '..'" $ do
isSafePiece "." `shouldBe` False
isSafePiece ".." `shouldBe` False
it "rejects anything starting with '.', including hidden files" $ do
isSafePiece ".env" `shouldBe` False
isSafePiece ".git" `shouldBe` False
it "rejects segments containing a path separator" $ do
isSafePiece "foo/bar" `shouldBe` False
isSafePiece "foo\\bar" `shouldBe` False
it "rejects a drive-letter colon that could hijack an absolute path join" $
isSafePiece "C:" `shouldBe` False
it "rejects other punctuation and whitespace outside the whitelist" $ do
isSafePiece "foo bar" `shouldBe` False
isSafePiece "foo;bar" `shouldBe` False
isSafePiece "foo\0bar" `shouldBe` False
around withScratchDir $
describe "Handler.Locales.isWithinDir" $ do
it "allows a file that exists inside the directory" $ \root -> do
let dir = root </> "locales"
file = dir </> "en" </> "translation.json"
createDirectoryIfMissing True (dir </> "en")
BS.writeFile file "{}"
isWithinDir dir file `shouldReturn` True
it "rejects a path that does not exist" $ \root -> do
let dir = root </> "locales"
file = dir </> "en" </> "missing.json"
createDirectoryIfMissing True (dir </> "en")
isWithinDir dir file `shouldReturn` False
it "rejects a path outside the directory even without traversal syntax" $ \root -> do
let dir = root </> "locales"
outsideFile = root </> "secret.yml"
createDirectoryIfMissing True dir
BS.writeFile outsideFile "secret"
isWithinDir dir outsideFile `shouldReturn` False
it "rejects a sibling directory sharing a name prefix" $ \root -> do
let dir = root </> "locales"
evilDir = root </> "locales-evil"
evilFile = evilDir </> "translation.json"
createDirectoryIfMissing True dir
createDirectoryIfMissing True evilDir
BS.writeFile evilFile "{}"
isWithinDir dir evilFile `shouldReturn` False
where
withScratchDir :: (FilePath -> IO ()) -> IO ()
withScratchDir action = do
tmp <- getTemporaryDirectory
let root = tmp </> "espial-locales-spec"
removeDirectoryRecursive root `catchAny` \_ -> pure ()
createDirectoryIfMissing True root
action root `finally` (removeDirectoryRecursive root `catchAny` \_ -> pure ())