brittany/src/Language/Haskell/Brittany/Internal/Obfuscation.hs

106 lines
2.4 KiB
Haskell

module Language.Haskell.Brittany.Internal.Obfuscation
( obfuscate
)
where
import Language.Haskell.Brittany.Internal.Prelude
import Language.Haskell.Brittany.Internal.PreludeUtils
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 Data.Char
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