spacecookie-0.2.0.1: src/Network/Gopher/Util.hs
{-|
Module : Network.Gopher.Util
Stability : experimental
Portability : POSIX
Helper utilities used within the library and the server which also could be useful for other application code.
-}
{-# LANGUAGE OverloadedStrings #-}
module Network.Gopher.Util (
-- * Security
santinizePath
, santinizeIfNotUrl
-- * String Encoding
, asciiOrd
, asciiChr
, uEncode
, uDecode
-- * Misc Helpers
, stripNewline
) where
import Data.ByteString (ByteString ())
import qualified Data.ByteString as B
import Data.Char (ord, chr)
import Data.List (isPrefixOf)
import qualified Data.String.UTF8 as U
import Data.Word (Word8 ())
import System.FilePath.Posix (pathSeparator, normalise, joinPath, splitPath)
-- | 'chr' a 'Word8'
asciiChr :: Word8 -> Char
asciiChr = chr . fromIntegral
-- | 'ord' a 'Word8'
asciiOrd :: Char -> Word8
asciiOrd = fromIntegral . ord
-- | Encode a 'String' to a UTF-8 'ByteString'
uEncode :: String -> ByteString
uEncode = B.pack . U.encode
-- | Decode a UTF-8 'ByteString' to a 'String'
uDecode :: ByteString -> String
uDecode = fst . U.decode . B.unpack
-- | Strip @\\r@ and @\\n@ from 'ByteString's
stripNewline :: ByteString -> ByteString
stripNewline s
| B.null s = B.empty
| B.head s `elem`
(map (fromIntegral . ord) "\n\r") = stripNewline (B.tail s)
| otherwise = B.head s `B.cons` stripNewline (B.tail s)
-- | Normalise a path and prevent <https://en.wikipedia.org/wiki/Directory_traversal_attack directory traversal attacks>.
santinizePath :: FilePath -> FilePath
santinizePath path = joinPath . filter (\p -> p /= ".." && p /= ".") . splitPath . normalise $ path
santinizeIfNotUrl :: FilePath -> FilePath
santinizeIfNotUrl path = if "URL:" `isPrefixOf` path
then path
else santinizePath path