{-# LANGUAGE OverloadedStrings #-}
module Network.Gopher.Util (
sanitizePath
, sanitizeIfNotUrl
, dropPrivileges
, asciiOrd
, asciiChr
, asciiToLower
, uEncode
, uDecode
, stripNewline
, boolToMaybe
) where
import Data.ByteString (ByteString ())
import qualified Data.ByteString as B
import Data.Char (ord, chr, toLower)
import qualified Data.String.UTF8 as U
import Data.Word (Word8 ())
import System.FilePath.Posix.ByteString (RawFilePath, normalise, joinPath, splitPath)
import System.Posix.User
asciiChr :: Word8 -> Char
asciiChr :: Word8 -> Char
asciiChr = Int -> Char
chr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral
asciiOrd :: Char -> Word8
asciiOrd :: Char -> Word8
asciiOrd = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
asciiToLower :: Word8 -> Word8
asciiToLower :: Word8 -> Word8
asciiToLower Word8
w =
if forall {a}. (Ord a, Num a) => a -> Bool
inBounds Int
lower
then forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lower
else Word8
w
where inBounds :: a -> Bool
inBounds a
i = a
i forall a. Ord a => a -> a -> Bool
>= forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
minBound :: Word8) Bool -> Bool -> Bool
&&
a
i forall a. Ord a => a -> a -> Bool
<= forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Word8)
lower :: Int
lower :: Int
lower = Char -> Int
ord forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Char
toLower forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Char
asciiChr forall a b. (a -> b) -> a -> b
$ Word8
w
uEncode :: String -> ByteString
uEncode :: [Char] -> RawFilePath
uEncode = [Word8] -> RawFilePath
B.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Word8]
U.encode
uDecode :: ByteString -> String
uDecode :: RawFilePath -> [Char]
uDecode = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ([Char], [(Error, Int)])
U.decode forall b c a. (b -> c) -> (a -> b) -> a -> c
. RawFilePath -> [Word8]
B.unpack
stripNewline :: ByteString -> ByteString
stripNewline :: RawFilePath -> RawFilePath
stripNewline RawFilePath
s
| RawFilePath -> Bool
B.null RawFilePath
s = RawFilePath
B.empty
| HasCallStack => RawFilePath -> Word8
B.head RawFilePath
s forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`
(forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord) [Char]
"\n\r") = RawFilePath -> RawFilePath
stripNewline (HasCallStack => RawFilePath -> RawFilePath
B.tail RawFilePath
s)
| Bool
otherwise = HasCallStack => RawFilePath -> Word8
B.head RawFilePath
s Word8 -> RawFilePath -> RawFilePath
`B.cons` RawFilePath -> RawFilePath
stripNewline (HasCallStack => RawFilePath -> RawFilePath
B.tail RawFilePath
s)
sanitizePath :: RawFilePath -> RawFilePath
sanitizePath :: RawFilePath -> RawFilePath
sanitizePath = [RawFilePath] -> RawFilePath
joinPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (\RawFilePath
p -> RawFilePath
p forall a. Eq a => a -> a -> Bool
/= RawFilePath
".." Bool -> Bool -> Bool
&& RawFilePath
p forall a. Eq a => a -> a -> Bool
/= RawFilePath
".")
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RawFilePath -> [RawFilePath]
splitPath forall b c a. (b -> c) -> (a -> b) -> a -> c
. RawFilePath -> RawFilePath
normalise
sanitizeIfNotUrl :: RawFilePath -> RawFilePath
sanitizeIfNotUrl :: RawFilePath -> RawFilePath
sanitizeIfNotUrl RawFilePath
path =
if RawFilePath
"URL:" RawFilePath -> RawFilePath -> Bool
`B.isPrefixOf` RawFilePath
path
then RawFilePath
path
else RawFilePath -> RawFilePath
sanitizePath RawFilePath
path
boolToMaybe :: Bool -> a -> Maybe a
boolToMaybe :: forall a. Bool -> a -> Maybe a
boolToMaybe Bool
True a
a = forall a. a -> Maybe a
Just a
a
boolToMaybe Bool
False a
_ = forall a. Maybe a
Nothing
dropPrivileges :: String -> IO ()
dropPrivileges :: [Char] -> IO ()
dropPrivileges [Char]
username = do
UserEntry
user <- [Char] -> IO UserEntry
getUserEntryForName [Char]
username
GroupID -> IO ()
setGroupID forall a b. (a -> b) -> a -> b
$ UserEntry -> GroupID
userGroupID UserEntry
user
UserID -> IO ()
setUserID forall a b. (a -> b) -> a -> b
$ UserEntry -> UserID
userID UserEntry
user