2022-05-17 00:23:30 +02:00
#!/ usr / bin / env runhaskell
2024-05-19 13:23:39 +02:00
2022-05-17 00:23:30 +02:00
{- # LANGUAGE DeriveDataTypeable # -}
module Main where
import System.Console.CmdArgs
import Control.Arrow
2024-05-19 13:23:39 +02:00
-- import Data.Text (pack, unpack, Text)
-- import Data.Bits
2024-05-14 00:18:48 +02:00
-- import Data.Char
2024-05-19 13:23:39 +02:00
-- import Text.Read (readMaybe)
-- import qualified Data.Text as T
-- import qualified Data.Text.Encoding as T
-- import qualified Data.Text.IO as T
2024-05-14 00:18:48 +02:00
-- import Data.Text (Text)
2024-05-19 13:23:39 +02:00
-- import qualified Data.Text.Lazy as TL
-- import Data.Text.Lazy.Builder (toLazyText)
-- import Data.Text.Encoding (decodeUtf8With, decodeUtf8, encodeUtf8)
-- import Data.Maybe (fromJust, fromMaybe)
-- import Data.Text.Encoding.Error (lenientDecode)
-- import TextShow (toText)
-- import Text.XML.HXT.DOM.Util (hexStringToInt, intToHexString, decimalStringToInt)
-- import TextShow.Data.Integral (showbBin, showbOct)
-- import Text.Ascii (fromBinDigit, fromOctDigit)
-- import Codec.CBOR.Magic (intToWord64)
-- import qualified Data.Either.Unwrap as U
-- import Data.Bytes.Text.Latin1 as Latin1
-- import qualified Codec.Binary.Base91 as B91
-- import qualified Codec.Binary.Base85 as B85
-- import qualified Codec.Binary.Base64 as B64
-- import qualified Data.ByteString.Base64 as B64L
-- import qualified Codec.Binary.Base64Url as B64U
-- import qualified Network.HTTP.Base as HB
-- import qualified Data.Word.Base62 as B62
-- import qualified Haskoin.Address.Base58 as B58
-- import qualified Codec.Binary.Base32 as B32
-- import qualified Codec.Binary.Base16 as B16
-- import qualified Codec.Binary.QuotedPrintable as QP
-- import qualified Codec.Binary.Uu as UU
-- import qualified Codec.Binary.Xx as XX
-- import qualified Codec.Binary.Yenc as Y
-- import qualified Data.Bytes as Bytes
-- import qualified Data.Bytes.Text.Ascii as ASCII
-- import Data.Bytes.Get (getWord64host)
2024-05-01 23:25:57 +02:00
-- import Data.ByteString (singleton)
2024-05-19 13:23:39 +02:00
-- import GHC.Word (Word8)
-- import Data.Word (Word8)
-- import Data.Char (ord, chr, intToDigit, digitToInt)
import Data.ByteString.UTF8 as BSU -- from utf8-string
2022-05-17 00:23:30 +02:00
import qualified Data.ByteString.Char8 as C
2024-05-02 23:12:40 +02:00
-- Regex imports
import Text.Regex.TDFA
2024-05-19 13:23:39 +02:00
import Encoding.Base2 ( enc2 , dec2 )
import Encoding.Base8 ( enc8 , dec8 )
import Encoding.Base10 ( enc10 , dec10 )
import Encoding.Base16 ( enc16 , dec16 )
import Encoding.Base32 ( enc32 , dec32 )
import Encoding.Base58 ( enc58 , dec58 )
import Encoding.Base62 ( enc62 , dec62 )
import Encoding.Base64 ( enc64 , dec64 , enc64url , dec64url )
import Encoding.Base85 ( enc85 , dec85 )
import Encoding.Base91 ( enc91 , dec91 )
import Encoding.Url ( encurl , decurl )
import Encoding.Xx ( encxx , decxx )
import Encoding.QuotedPrintable ( encqp , decqp )
import Encoding.UnixToUnix ( encuu , decuu )
import Encoding.Yenc ( ency , decy )
2022-05-17 00:23:30 +02:00
data Based = Decode {
b91 :: Bool ,
b85 :: Bool ,
b64 :: Bool ,
2022-05-22 22:48:44 +02:00
b64url :: Bool ,
2022-09-19 23:11:13 +02:00
url :: Bool ,
2022-05-17 00:23:30 +02:00
b62 :: Bool ,
2022-05-19 23:55:26 +02:00
b58 :: Bool ,
2022-05-17 00:23:30 +02:00
b32 :: Bool ,
2022-05-19 23:55:26 +02:00
b16 :: Bool ,
b10 :: Bool ,
2022-05-22 22:48:44 +02:00
b8 :: Bool ,
b2 :: Bool ,
2022-05-19 23:55:26 +02:00
qp :: Bool ,
uu :: Bool ,
xx :: Bool ,
2024-05-02 23:12:40 +02:00
yenc :: Bool ,
solve :: Bool
2022-05-17 00:23:30 +02:00
}
| Encode {
b91 :: Bool ,
b85 :: Bool ,
b64 :: Bool ,
2022-05-22 22:48:44 +02:00
b64url :: Bool ,
2022-09-19 23:11:13 +02:00
url :: Bool ,
2022-05-17 00:23:30 +02:00
b62 :: Bool ,
2022-05-19 23:55:26 +02:00
b58 :: Bool ,
2022-05-17 00:23:30 +02:00
b32 :: Bool ,
2022-05-19 23:55:26 +02:00
b16 :: Bool ,
b10 :: Bool ,
2022-05-22 22:48:44 +02:00
b8 :: Bool ,
b2 :: Bool ,
2022-05-19 23:55:26 +02:00
qp :: Bool ,
uu :: Bool ,
xx :: Bool ,
yenc :: Bool
2022-05-17 00:23:30 +02:00
}
deriving ( Show , Data , Typeable )
2022-05-22 22:48:44 +02:00
-- helper functions
2024-04-18 00:18:39 +02:00
2024-04-20 01:20:53 +02:00
-- convertToByteString :: String -> Either String C.ByteString
-- convertToByteString str =
-- case BSU.fromString str of
-- Just bs -> Right bs
-- Nothing -> Left "Failed to convert string to ByteString."
2024-04-18 00:18:39 +02:00
2024-04-28 23:47:31 +02:00
-- decodeFromBase91 :: String -> Either String C.ByteString
-- decodeFromBase91 decoded =
2024-04-20 01:20:53 +02:00
-- case B91.decode of
2024-04-28 23:47:31 +02:00
-- decoded | C.null decoded -> Left "Failed to decode from base91"
-- | otherwise -> Right decoded
2024-04-18 00:18:39 +02:00
2022-05-22 22:48:44 +02:00
binToInt :: [ Int ] -> Int
binToInt [] = 0
binToInt ( x : xs ) = x + 2 * binToInt xs
octToInt :: [ Int ] -> Int
octToInt [] = 0
octToInt ( x : xs ) = x + 8 * octToInt xs
-- base functions
2022-05-17 00:23:30 +02:00
-- without the show func, sequences like \n will not be shown as characters but will be executed as newline
2024-04-18 00:18:39 +02:00
2024-05-02 23:12:40 +02:00
base91Regex = " ^[!-~]*$ "
2024-05-05 00:04:19 +02:00
base85Regex = " ^[0-9A-Za-z!#$%&()*+,-;<=>?@^_`{|}~]+$ "
2024-05-02 23:12:40 +02:00
-- base85Regex = "^[A-Za-u0-9!\"#$%&((*+,-./;:<=@[]\\`]*$"
base64Regex = " ^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$ "
base58Regex = " ^[1-9A-HJ-NP-Za-km-z]+$ " -- incorrect
base32Regex = " ^(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}=)?$ "
base16Regex = " ^[0-9A-FXx]*$ "
2024-05-05 23:45:05 +02:00
base10Regex = " ^[0-9]*$ "
base8Regex = " ^[0-7]*$ "
2024-05-05 00:04:19 +02:00
base2Regex = " ^[01]*$ "
urlRegex = " ^[a-zA-Z0-9%]*$ "
2024-05-02 23:12:40 +02:00
solveEnc :: String -> String
solveEnc input =
2024-05-03 23:36:35 +02:00
let isBase91 = BSU . fromString input =~ base91Regex :: Bool
2024-05-05 00:04:19 +02:00
isBase85 = BSU . fromString input =~ base85Regex :: Bool
2024-05-03 23:36:35 +02:00
isBase64 = BSU . fromString input =~ base64Regex :: Bool
2024-05-02 23:12:40 +02:00
isBase58 = BSU . fromString input =~ base58Regex :: Bool
isBase32 = BSU . fromString input =~ base32Regex :: Bool
isBase16 = BSU . fromString input =~ base16Regex :: Bool
2024-05-05 23:45:05 +02:00
isBase10 = BSU . fromString input =~ base10Regex :: Bool
isBase8 = BSU . fromString input =~ base8Regex :: Bool
2024-05-05 00:04:19 +02:00
isBase2 = BSU . fromString input =~ base2Regex :: Bool
isURL = BSU . fromString input =~ urlRegex :: Bool
2024-05-03 23:36:35 +02:00
base91Result = if isBase91 then " \ n Trying base91: \ n " ++ dec91 input else " "
2024-05-05 00:04:19 +02:00
base85Result = if isBase85 then " \ n Trying base85: \ n " ++ dec85 input else " "
2024-05-02 23:12:40 +02:00
base64Result = if isBase64 then " \ n Trying base64: \ n " ++ dec64 input else " "
base58Result = if isBase58 then " \ n Trying base58: \ n " ++ dec58 input else " "
base32Result = if isBase64 then " \ n Trying base32: \ n " ++ dec32 input else " "
base16Result = if isBase16 then " \ n Trying base16: \ n " ++ dec16 input else " "
2024-05-05 23:45:05 +02:00
base10Result = if isBase10 then " \ n Trying base10: \ n " ++ dec10 input else " "
2024-05-05 00:04:19 +02:00
base2Result = if isBase2 then " \ n Trying base2: \ n " ++ dec2 input else " "
2024-05-05 23:45:05 +02:00
base8Result = if isBase8 then " \ n Trying base8: \ n " ++ dec8 input else " "
2024-05-05 00:04:19 +02:00
urlResult = if isURL then " \ n Trying URL decode: \ n " ++ decurl input else " "
2024-05-05 23:45:05 +02:00
results = filter ( not . null ) [ base91Result , base85Result , base64Result , base58Result , base32Result , base16Result , base10Result , base8Result , base2Result , urlResult ]
2024-05-02 23:12:40 +02:00
in
if null results
then " Not able to solve the encoding. \ n "
else unlines results
--
-- | input =~ base64Regex = dec64 input
-- | input =~ base32Regex = dec32 input
-- | otherwise = "Cannot decode: " ++ input
--
-- if BSU.fromString input =~ base64Regex :: Bool
-- then dec64 input
-- else "Not Base64.\n"
-- ++ if BSU.fromString input =~ base32Regex :: Bool
-- then dec32 input
-- else "Not able to solve the encoding.\n"
2022-05-19 23:55:26 +02:00
2024-05-19 13:23:39 +02:00
2024-05-05 23:45:05 +02:00
-- optionHandler :: EncodeOptions -> Text -> Text
2022-05-17 00:23:30 +02:00
optionHandler Decode { b91 = True } = dec91
optionHandler Encode { b91 = True } = enc91
optionHandler Decode { b85 = True } = dec85
optionHandler Encode { b85 = True } = enc85
optionHandler Decode { b64 = True } = dec64
optionHandler Encode { b64 = True } = enc64
2022-05-22 22:48:44 +02:00
optionHandler Decode { b64url = True } = dec64url
optionHandler Encode { b64url = True } = enc64url
2022-09-19 23:11:13 +02:00
optionHandler Decode { url = True } = decurl
optionHandler Encode { url = True } = encurl
2022-05-17 00:23:30 +02:00
optionHandler Decode { b62 = True } = dec62
optionHandler Encode { b62 = True } = enc62
2022-05-19 23:55:26 +02:00
optionHandler Decode { b58 = True } = dec58
optionHandler Encode { b58 = True } = enc58
2022-05-17 00:23:30 +02:00
optionHandler Decode { b32 = True } = dec32
optionHandler Encode { b32 = True } = enc32
optionHandler Decode { b16 = True } = dec16
optionHandler Encode { b16 = True } = enc16
2022-05-19 23:55:26 +02:00
optionHandler Decode { b10 = True } = dec10
optionHandler Encode { b10 = True } = enc10
2022-05-22 22:48:44 +02:00
optionHandler Decode { b8 = True } = dec8
optionHandler Encode { b8 = True } = enc8
optionHandler Decode { b2 = True } = dec2
optionHandler Encode { b2 = True } = enc2
2022-05-19 23:55:26 +02:00
optionHandler Decode { qp = True } = decqp
optionHandler Encode { qp = True } = encqp
2024-05-05 00:04:19 +02:00
optionHandler Encode { uu = True } = encuu
optionHandler Decode { uu = True } = decuu
2022-05-19 23:55:26 +02:00
optionHandler Decode { xx = True } = decxx
optionHandler Encode { xx = True } = encxx
optionHandler Decode { yenc = True } = decy
optionHandler Encode { yenc = True } = ency
2024-05-02 23:12:40 +02:00
optionHandler Decode { solve = True } = solveEnc
2022-05-17 00:23:30 +02:00
2023-07-25 23:17:25 +02:00
decodeMode :: Based
decodeMode = Decode {
2022-05-17 00:23:30 +02:00
b91 = def &= help " decode base91 " ,
b85 = def &= help " decode base85 " ,
b64 = def &= help " decode base64 " ,
2022-05-22 22:48:44 +02:00
b64url = def &= help " decode base64Url " ,
2022-09-19 23:11:13 +02:00
url = def &= help " decode URI " ,
2022-05-17 00:23:30 +02:00
b62 = def &= help " decode base62 " ,
2022-05-19 23:55:26 +02:00
b58 = def &= help " decode base58 " ,
2022-05-17 00:23:30 +02:00
b32 = def &= help " decode base32 " ,
2022-05-19 23:55:26 +02:00
b16 = def &= help " decode base16 " ,
2022-05-22 22:48:44 +02:00
b10 = def &= help " decode decimal from hex " ,
b8 = def &= help " decode octal from hex " ,
b2 = def &= help " decode binary from hex " ,
2022-05-19 23:55:26 +02:00
qp = def &= help " decode quoted-printable " ,
uu = def &= help " decode uu " ,
xx = def &= help " decode xx " ,
2024-05-02 23:12:40 +02:00
yenc = def &= help " decode yEncode " ,
solve = def &= help " solve encoding "
2022-05-17 00:23:30 +02:00
} &= help " Decode chosen base " &= auto
2023-07-25 23:17:25 +02:00
encodeMode :: Based
encodeMode = Encode {
2022-05-17 00:23:30 +02:00
b91 = def &= help " encode base91 " ,
b85 = def &= help " encode base85 " ,
b64 = def &= help " encode base64 " ,
2022-05-22 22:48:44 +02:00
b64url = def &= help " encode base64Url " ,
2022-09-19 23:11:13 +02:00
url = def &= help " encode URI " ,
2022-05-17 00:23:30 +02:00
b62 = def &= help " encode base62 " ,
2022-05-19 23:55:26 +02:00
b58 = def &= help " encode base58 " ,
2022-05-17 00:23:30 +02:00
b32 = def &= help " encode base32 " ,
2022-05-19 23:55:26 +02:00
b16 = def &= help " encode base16 " ,
b10 = def &= help " encode base10 to hex " ,
2022-05-22 22:48:44 +02:00
b8 = def &= help " encode octal to hex " ,
b2 = def &= help " encode binary to hex " ,
2022-05-19 23:55:26 +02:00
qp = def &= help " encode quoted-printable " ,
uu = def &= help " encode uu " ,
xx = def &= help " encode xx " ,
yenc = def &= help " encode yEncode "
2022-05-17 00:23:30 +02:00
} &= help " Encode chosen base "
2023-07-25 23:17:25 +02:00
main :: IO ()
main = cmdArgs ( modes [ decodeMode , encodeMode ] &= help " Anybased, when Cyberchef simply doesn't cut it. \ n To see every parameter of every mode use --help=all " &= program " based " &= summary " based v0.4 " ) >>= interact . optionHandler