{-# LANGUAGE NoImplicitPrelude #-} module Language.Haskell.Brittany.Internal.Obfuscation where import Data.Char import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as Text import qualified GHC.OldList as List import Language.Haskell.Brittany.Internal.Prelude import Language.Haskell.Brittany.Internal.PreludeUtils import System.Random obfuscate :: Text -> IO Text obfuscate input = do let predi x = isAlphaNum x || x `elem` "_'" let groups = List.groupBy (\a b -> predi a && predi b) (Text.unpack input) let idents = Set.toList $ Set.fromList $ filter (all predi) groups let exceptionFilter x | x `elem` keywords = False exceptionFilter x | x `elem` extraKWs = False exceptionFilter x = not $ null $ drop 1 x let filtered = filter exceptionFilter idents mappings <- fmap Map.fromList $ filtered `forM` \x -> do r <- createAlias x pure (x, r) let groups' = groups <&> \w -> fromMaybe w (Map.lookup w mappings) pure $ Text.concat $ fmap Text.pack groups' keywords :: [String] keywords = [ "case" , "class" , "data" , "default" , "deriving" , "do" , "mdo" , "else" , "forall" , "if" , "import" , "in" , "infix" , "infixl" , "infixr" , "instance" , "let" , "module" , "newtype" , "of" , "qualified" , "then" , "type" , "where" , "_" , "foreign" , "ccall" , "as" , "safe" , "unsafe" , "hiding" , "proc" , "rec" , "family" ] extraKWs :: [String] extraKWs = ["return", "pure", "Int", "True", "False", "otherwise"] createAlias :: String -> IO String createAlias xs = go NoHint xs where go _hint "" = pure "" go hint (c : cr) = do c' <- case hint of VocalHint | isUpper c -> randomFrom $ "AAAEEEOOOIIIUUU" ++ ['A' .. 'Z'] _ | isUpper c -> randomFrom ['A' .. 'Z'] VocalHint | isLower c -> randomFrom $ "aaaeeeoooiiiuuu" ++ ['a' .. 'z'] _ | isLower c -> randomFrom ['a' .. 'z'] _ -> pure c cr' <- go (if c' `elem` "aeuioAEUIO" then NoVocalHint else VocalHint) cr pure (c' : cr') data Hint = NoHint | VocalHint | NoVocalHint _randomRange :: Random a => a -> a -> IO a _randomRange lo hi = do gen <- getStdGen let (x, gen') = randomR (lo, hi) gen setStdGen gen' pure x randomFrom :: [a] -> IO a randomFrom l = do let hi = length l - 1 gen <- getStdGen let (x, gen') = randomR (0, hi) gen setStdGen gen' pure $ l List.!! x