packages feed

base64 0.4.2.1 → 0.4.2.2

raw patch · 21 files changed

+1195/−198 lines, 21 filesdep −quickcheck-instancesdep ~deepseqPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies removed: quickcheck-instances

Dependency ranges changed: deepseq

API changes (from Hackage documentation)

+ Data.Text.Encoding.Base64.Error: instance Control.DeepSeq.NFData e => Control.DeepSeq.NFData (Data.Text.Encoding.Base64.Error.Base64Error e)
+ Data.Text.Encoding.Base64.Error: instance GHC.Exception.Type.Exception e => GHC.Exception.Type.Exception (Data.Text.Encoding.Base64.Error.Base64Error e)
+ Data.Text.Encoding.Base64.Error: instance GHC.Generics.Generic (Data.Text.Encoding.Base64.Error.Base64Error e)

Files

CHANGELOG.md view
@@ -1,8 +1,16 @@ # Revision history for base64 +## 0.4.2.2++* Add `NFData`, `Exception`, and `Generic` instances for `Base64Error` + `@since` annotations for new instances. ([#28](https://github.com/emilypi/base64/pull/28))+* Doc improvements and add `-XTrustworty` and `-XSafe` annotations where needed. ([#27](https://github.com/emilypi/base64/pull/27))+* Improve URL canonicity validation and correctness checking (now supports correct checking for unpadded Base64url) ([#26](https://github.com/emilypi/base64/pull/26))+* Fixed perf regressions in decode+* Test coverage is at 98%+ ## 0.4.2.1 -* [Security fix]: reject non-canonical base64 encoded values - ([#25](https://github.com/emilypi/base64/pull/25))+* Security fix: reject non-canonical base64 encoded values - ([#25](https://github.com/emilypi/base64/pull/25))  * Perf improvements 
README.md view
@@ -25,4 +25,4 @@ - Checks for both validity and correctness of Base64 and Base64url encodings - Rejects non-canonical encodings that do not roundtrip in other base64 libraries like `ZE==`. -There are no dependencies aside from those bundled with GHC, and the `ghc-byteorder` re-export.+There are no dependencies aside from those bundled with GHC, `text-short`, and the `ghc-byteorder` re-export.
base64.cabal view
@@ -1,20 +1,20 @@-cabal-version:      2.0-name:               base64-version:            0.4.2.1-synopsis:           Fast RFC 4648-compliant Base64 encoding+cabal-version:   2.0+name:            base64+version:         0.4.2.2+synopsis:        Fast RFC 4648-compliant Base64 encoding description:   RFC 4648-compliant padded and unpadded base64 and base64url encoding and decoding. This library provides   performant encoding and decoding primitives, as well as support for textual values. -homepage:           https://github.com/emilypi/base64-bug-reports:        https://github.com/emilypi/base64/issues-license:            BSD3-license-file:       LICENSE-author:             Emily Pillmore-maintainer:         emilypi@cohomolo.gy-copyright:          (c) 2019-2020 Emily Pillmore-category:           Data-build-type:         Simple+homepage:        https://github.com/emilypi/base64+bug-reports:     https://github.com/emilypi/base64/issues+license:         BSD3+license-file:    LICENSE+author:          Emily Pillmore+maintainer:      emilypi@cohomolo.gy+copyright:       (c) 2019-2020 Emily Pillmore+category:        Data+build-type:      Simple extra-doc-files:   CHANGELOG.md   README.md@@ -61,6 +61,7 @@   build-depends:       base           >=4.10     && <5     , bytestring     ^>=0.10+    , deepseq        >=1.4.3.0  && <1.4.5.0     , ghc-byteorder  ^>=4.11.0.0     , text           ^>=1.2     , text-short     ^>=0.1@@ -76,12 +77,11 @@   other-modules:    Internal   main-is:          Main.hs   build-depends:-      base                  >=4.10 && <5+      base               >=4.10 && <5     , base64     , base64-bytestring     , bytestring     , QuickCheck-    , quickcheck-instances     , random-bytestring     , tasty     , tasty-hunit
src/Data/ByteString/Base64.hs view
@@ -1,23 +1,28 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Base64 -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.ByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64+-- encoding format. This includes lenient decoding variants, as well as+-- internal and external validation for canonicity. -- module Data.ByteString.Base64-( encodeBase64+( -- * Encoding+  encodeBase64 , encodeBase64'+  -- * Decoding , decodeBase64 , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -38,33 +43,54 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: ByteString -> Text encodeBase64 = T.decodeUtf8 . encodeBase64'-{-# INLINE encodeBase64 #-}+{-# inline encodeBase64 #-}  -- | Encode a 'ByteString' value as a Base64 'ByteString'  value with padding. -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64' "Sun"+-- "U3Vu"+-- encodeBase64' :: ByteString -> ByteString encodeBase64' = encodeBase64_ base64Table-{-# INLINE encodeBase64' #-}+{-# inline encodeBase64' #-}  -- | Decode a padded Base64-encoded 'ByteString' value. -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: ByteString -> Either Text ByteString-decodeBase64 bs@(PS _ _ l)+decodeBase64 bs@(PS _ _ !l)     | l == 0 = Right bs     | r == 1 = Left "Base64-encoded bytestring has invalid size"     | r /= 0 = Left "Base64-encoded bytestring requires padding"     | otherwise = unsafeDupablePerformIO $ decodeBase64_ dlen decodeB64Table bs   where-    q = l `quot` 4-    r = l `rem` 4-    dlen = q * 3-{-# INLINE decodeBase64 #-}+    !q = l `quot` 4+    !r = l `rem` 4+    !dlen = q * 3+{-# inline decodeBase64 #-}  -- | Leniently decode an unpadded Base64-encoded 'ByteString' value. This function -- will not generate parse errors. If input data contains padding chars,@@ -72,15 +98,41 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = decodeBase64Lenient_ decodeB64Table-{-# INLINE decodeBase64Lenient #-}+{-# inline decodeBase64Lenient #-}  -- | Tell whether a 'ByteString' value is base64 encoded. --+-- This function will also detect non-canonical encodings such as @ZE==@, which are+-- externally valid Base64url-encoded values, but are internally inconsistent "impossible"+-- values.+--+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: ByteString -> Bool isBase64 bs = isValidBase64 bs && isRight (decodeBase64 bs)-{-# INLINE isBase64 #-}+{-# inline isBase64 #-}  -- | Tell whether a 'ByteString' value is a valid Base64 format. --@@ -88,6 +140,20 @@ -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ByteString' value, use 'isBase64'. --+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False+-- isValidBase64 :: ByteString -> Bool isValidBase64 = validateBase64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"-{-# INLINE isValidBase64 #-}+{-# inline isValidBase64 #-}
src/Data/ByteString/Base64/Internal.hs view
@@ -18,6 +18,7 @@ -- module Data.ByteString.Base64.Internal ( validateBase64+, validateBase64Url , validateLastPad ) where @@ -52,6 +53,34 @@          if f w then go (plusPtr p 1) end else return False {-# INLINE validateBase64 #-}++validateBase64Url :: ByteString -> ByteString -> Bool+validateBase64Url !alphabet bs@(PS _ _ l)+    | l == 0 = True+    | r == 0 = f bs+    | r == 2 = f (BS.append bs "==")+    | r == 3 = f (BS.append bs "=")+    | otherwise = False++  where+    r = l `rem` 4++    f (PS fp o n) = accursedUnutterablePerformIO $+      withForeignPtr fp $ \p -> go (plusPtr p o) (plusPtr p (n + o))++    go !p !end+      | p == end = return True+      | otherwise = do+        w <- peek p++        let check a+              | a == 0x3d, plusPtr p 1 == end = True+              | a == 0x3d, plusPtr p 2 == end = True+              | a == 0x3d = False+              | otherwise = BS.elem a alphabet++        if check w then go (plusPtr p 1) end else return False+{-# INLINE validateBase64Url #-}  -- | This function checks that the last char of a bytestring is '=' -- and, if true, fails with a message or completes some io action.
src/Data/ByteString/Base64/Internal/Head.hs view
@@ -44,13 +44,13 @@   encodeBase64_ :: EncodingTable -> ByteString -> ByteString-encodeBase64_ (EncodingTable aptr efp) (PS sfp soff slen) =+encodeBase64_ (EncodingTable !aptr !efp) (PS !sfp !soff !slen) =     unsafeDupablePerformIO $ do       dfp <- mallocPlainForeignPtrBytes dlen       withForeignPtr dfp $ \dptr ->         withForeignPtr sfp $ \sptr ->         withForeignPtr efp $ \eptr -> do-          let end = plusPtr sptr (soff + slen)+          let !end = plusPtr sptr (soff + slen)           innerLoop             eptr             (castPtr (plusPtr sptr soff))@@ -58,7 +58,7 @@             end             (loopTail dfp aptr dptr (castPtr end))   where-    dlen = 4 * ((slen + 2) `div` 3)+    !dlen = 4 * ((slen + 2) `div` 3)  encodeBase64Nopad_ :: EncodingTable -> ByteString -> ByteString encodeBase64Nopad_ (EncodingTable !aptr !efp) (PS !sfp !soff !slen) =@@ -92,17 +92,16 @@     -> ForeignPtr Word8     -> ByteString     -> IO (Either Text ByteString)-decodeBase64_ dlen dtfp (PS sfp soff slen) =+decodeBase64_ !dlen !dtfp (PS !sfp !soff !slen) =     withForeignPtr dtfp $ \dtable ->     withForeignPtr sfp $ \sptr -> do       dfp <- mallocPlainForeignPtrBytes dlen-      withForeignPtr dfp $ \dptr ->-        decodeLoop-          dtable+      withForeignPtr dfp $ \dptr -> do+        let !end = plusPtr sptr (soff + slen)+        decodeLoop dtable           (plusPtr sptr soff)-          dptr-          (plusPtr sptr (soff + slen))-          dfp+          dptr end dfp+{-# inline decodeBase64_ #-}  decodeBase64Lenient_ :: ForeignPtr Word8 -> ByteString -> ByteString decodeBase64Lenient_ !dtfp (PS !sfp !soff !slen) = unsafeDupablePerformIO $
src/Data/ByteString/Base64/Internal/W16/Loop.hs view
@@ -53,9 +53,9 @@         !j <- w32 <$> peek (plusPtr src 1)         !k <- w32 <$> peek (plusPtr src 2) -        let !w = (shiftL i 16) .|. (shiftL j 8) .|. k+        let !w = (unsafeShiftL i 16) .|. (unsafeShiftL j 8) .|. k -        !x <- peekElemOff etable (fromIntegral (shiftR w 12))+        !x <- peekElemOff etable (fromIntegral (unsafeShiftR w 12))         !y <- peekElemOff etable (fromIntegral (w .&. 0xfff))          poke dst x@@ -76,22 +76,25 @@     -> IO (Either Text ByteString) decodeLoop !dtable !sptr !dptr !end !dfp = go dptr sptr   where+    err :: Ptr Word8 -> IO (Either Text ByteString)     err p = return . Left . T.pack       $ "invalid character at offset: "       ++ show (p `minusPtr` sptr) +    padErr :: Ptr Word8 -> IO (Either Text ByteString)     padErr p =  return . Left . T.pack       $ "invalid padding at offset: "       ++ show (p `minusPtr` sptr) +    canonErr :: Ptr Word8 -> IO (Either Text ByteString)     canonErr p = return . Left . T.pack       $ "non-canonical encoding detected at offset: "       ++ show (p `minusPtr` sptr)      look :: Ptr Word8 -> IO Word32     look !p = do-      i <- peekByteOff @Word8 p 0-      v <- peekByteOff @Word8 dtable (fromIntegral i)+      !i <- peekByteOff @Word8 p 0+      !v <- peekByteOff @Word8 dtable (fromIntegral i)       return (fromIntegral v)      go !dst !src@@ -103,17 +106,17 @@         finalChunk dst src a b c d        | otherwise = do-        !a <- look src-        !b <- look (src `plusPtr` 1)-        !c <- look (src `plusPtr` 2)-        !d <- look (src `plusPtr` 3)+        a <- look src+        b <- look (src `plusPtr` 1)+        c <- look (src `plusPtr` 2)+        d <- look (src `plusPtr` 3)         decodeChunk dst src a b c d      -- | Decodes chunks of 4 bytes at a time, recombining into     -- 3 bytes. Note that in the inner loop stage, no padding     -- characters are admissible.     ---    decodeChunk !dst !src !a !b !c !d+    decodeChunk !dst !src a b c d      | a == 0x63 = padErr src      | b == 0x63 = padErr (plusPtr src 1)      | c == 0x63 = padErr (plusPtr src 2)@@ -138,7 +141,7 @@     -- 3 bytes. Note that in this stage, we can have padding chars     -- but only in the final 2 positions.     ---    finalChunk !dst !src !a !b !c !d+    finalChunk !dst !src a b c d       | a == 0x63 = padErr src       | b == 0x63 = padErr (plusPtr src 1)       | c == 0x63 && d /= 0x63 = err (plusPtr src 3) -- make sure padding is coherent.
src/Data/ByteString/Base64/URL.hs view
@@ -1,28 +1,32 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Base64.URL -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64-URL encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.ByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient decoding+-- variants, as well as internal and external validation for canonicity. -- module Data.ByteString.Base64.URL-( encodeBase64+( -- * Encoding+  encodeBase64 , encodeBase64'-, decodeBase64 , encodeBase64Unpadded , encodeBase64Unpadded'+  -- * Decoding+, decodeBase64 , decodeBase64Unpadded , decodeBase64Padded , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -44,6 +48,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: ByteString -> Text encodeBase64 = T.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-}@@ -52,6 +61,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64' "<<?>>"+-- "PDw_Pj4="+-- encodeBase64' :: ByteString -> ByteString encodeBase64' = encodeBase64_ base64UrlTable @@ -63,17 +77,31 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: ByteString -> Either Text ByteString-decodeBase64 bs@(PS _ _ l)+decodeBase64 bs@(PS _ _ !l)     | l == 0 = Right bs     | r == 0 = unsafeDupablePerformIO $ decodeBase64_ dlen decodeB64UrlTable bs     | r == 2 = unsafeDupablePerformIO $ decodeBase64_ dlen decodeB64UrlTable (BS.append bs "==")     | r == 3 = validateLastPad bs $ decodeBase64_ dlen decodeB64UrlTable (BS.append bs "=")     | otherwise = Left "Base64-encoded bytestring has invalid size"   where-    q = l `quot` 4-    r = l `rem` 4-    dlen = q * 3+    !q = l `quot` 4+    !r = l `rem` 4+    !dlen = q * 3 {-# INLINE decodeBase64 #-}  -- | Encode a 'ByteString' value as Base64url 'Text' without padding. Note that for Base64url,@@ -82,6 +110,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: ByteString -> Text encodeBase64Unpadded = T.decodeUtf8 . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-}@@ -92,6 +125,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded' "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded' :: ByteString -> ByteString encodeBase64Unpadded' = encodeBase64Nopad_ base64UrlTable @@ -104,17 +142,25 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: ByteString -> Either Text ByteString-decodeBase64Unpadded bs@(PS _ _ l)+decodeBase64Unpadded bs@(PS _ _ !l)     | l == 0 = Right bs     | r == 0 = validateLastPad bs $ decodeBase64_ dlen decodeB64UrlTable bs     | r == 2 = validateLastPad bs $ decodeBase64_ dlen decodeB64UrlTable (BS.append bs "==")     | r == 3 = validateLastPad bs $ decodeBase64_ dlen decodeB64UrlTable (BS.append bs "=")     | otherwise = Left "Base64-encoded bytestring has invalid size"   where-    q = l `quot` 4-    r = l `rem` 4-    dlen = q * 3+    !q = l `quot` 4+    !r = l `rem` 4+    !dlen = q * 3 {-# INLINE decodeBase64Unpadded #-}  -- | Decode a padded Base64url-encoded 'ByteString' value. Input strings are@@ -126,16 +172,24 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: ByteString -> Either Text ByteString-decodeBase64Padded bs@(PS _ _ l)+decodeBase64Padded bs@(PS _ _ !l)     | l == 0 = Right bs     | r == 1 = Left "Base64-encoded bytestring has invalid size"     | r /= 0 = Left "Base64-encoded bytestring requires padding"     | otherwise = unsafeDupablePerformIO $ decodeBase64_ dlen decodeB64UrlTable bs   where-    q = l `quot` 4-    r = l `rem` 4-    dlen = q * 3+    !q = l `quot` 4+    !r = l `rem` 4+    !dlen = q * 3 {-# INLINE decodeBase64Padded #-}  -- | Leniently decode an unpadded Base64url-encoded 'ByteString'. This function@@ -144,12 +198,35 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = decodeBase64Lenient_ decodeB64UrlTable {-# INLINE decodeBase64Lenient #-} --- | Tell whether a 'ByteString' is Base64url-encoded.+-- | Tell whether a 'ByteString' is encoded in padded /or/ unpadded Base64url format. --+-- This function will also detect non-canonical encodings such as @ZE==@, which are+-- externally valid Base64url-encoded values, but are internally inconsistent "impossible"+-- values.+--+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: ByteString -> Bool isBase64Url bs = isValidBase64Url bs && isRight (decodeBase64 bs) {-# INLINE isBase64Url #-}@@ -160,6 +237,17 @@ -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ByteString' value, use 'isBase64Url'. --+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False+-- isValidBase64Url :: ByteString -> Bool-isValidBase64Url = validateBase64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"+isValidBase64Url = validateBase64Url "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" {-# INLINE isValidBase64Url #-}
src/Data/ByteString/Lazy/Base64.hs view
@@ -1,23 +1,27 @@-{-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Lazy.Base64 -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.Lazy.ByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64+-- encoding format. This includes lenient decoding variants, as well as+-- internal and external validation for canonicity. -- module Data.ByteString.Lazy.Base64-( encodeBase64+( -- * Encoding+  encodeBase64 , encodeBase64'+  -- * Decoding , decodeBase64 , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -39,6 +43,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: ByteString -> TL.Text encodeBase64 = TL.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-}@@ -47,6 +56,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64' "Sun"+-- "U3Vu"+-- encodeBase64' :: ByteString -> ByteString encodeBase64' = fromChunks   . fmap B64.encodeBase64'@@ -58,6 +72,17 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: ByteString -> Either T.Text ByteString decodeBase64 = fmap (fromChunks . (:[]))   . B64.decodeBase64@@ -71,6 +96,17 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = fromChunks     . fmap B64.decodeBase64Lenient@@ -81,6 +117,21 @@  -- | Tell whether a 'ByteString' value is base64 encoded. --+-- This function will also detect non-canonical encodings such as @ZE==@, which are+-- externally valid Base64url-encoded values, but are internally inconsistent "impossible"+-- values.+--+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: ByteString -> Bool isBase64 bs = isValidBase64 bs && isRight (decodeBase64 bs) {-# INLINE isBase64 #-}@@ -90,6 +141,20 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ByteString' value, use 'isBase64'.+--+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False -- isValidBase64 :: ByteString -> Bool isValidBase64 = go . toChunks
src/Data/ByteString/Lazy/Base64/URL.hs view
@@ -1,27 +1,32 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Lazy.Base64.URL -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.Lazy.ByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient+-- decoding variants, as well as internal and external validation for canonicity. -- module Data.ByteString.Lazy.Base64.URL-( encodeBase64+( -- * Encoding+  encodeBase64 , encodeBase64' , encodeBase64Unpadded , encodeBase64Unpadded'+  -- * Decoding , decodeBase64-, decodeBase64Padded , decodeBase64Unpadded+, decodeBase64Padded , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -44,6 +49,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: ByteString -> TL.Text encodeBase64 = TL.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-}@@ -52,6 +62,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64' "<<?>>"+-- "PDw_Pj4="+-- encodeBase64' :: ByteString -> ByteString encodeBase64' = fromChunks   . fmap B64U.encodeBase64'@@ -66,6 +81,20 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: ByteString -> Either T.Text ByteString decodeBase64 = fmap (fromChunks . (:[]))   . B64U.decodeBase64@@ -79,6 +108,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: ByteString -> TL.Text encodeBase64Unpadded = TL.decodeUtf8 . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-}@@ -89,6 +123,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded' "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded' :: ByteString -> ByteString encodeBase64Unpadded' = fromChunks   . fmap B64U.encodeBase64Unpadded'@@ -104,6 +143,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: ByteString -> Either T.Text ByteString decodeBase64Unpadded = fmap (fromChunks . (:[]))   . B64U.decodeBase64Unpadded@@ -120,6 +167,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: ByteString -> Either T.Text ByteString decodeBase64Padded = fmap (fromChunks . (:[]))   . B64U.decodeBase64Padded@@ -133,6 +188,14 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = fromChunks     . fmap B64U.decodeBase64Lenient@@ -143,6 +206,17 @@  -- | Tell whether a 'ByteString' is Base64url-encoded. --+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: ByteString -> Bool isBase64Url bs = isValidBase64Url bs && isRight (decodeBase64 bs) {-# INLINE isBase64Url #-}@@ -152,6 +226,17 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ByteString' value, use 'isBase64Url'.+--+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False -- isValidBase64Url :: ByteString -> Bool isValidBase64Url = go . toChunks
src/Data/ByteString/Short/Base64.hs view
@@ -1,21 +1,26 @@+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Short.Base64 -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.Short.ShortByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64+-- encoding format. This includes lenient decoding variants, as well as+-- internal and external validation for canonicity. -- module Data.ByteString.Short.Base64-( encodeBase64+( -- * Encoding+  encodeBase64 , encodeBase64'+  -- * Decoding , decodeBase64 , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -27,10 +32,15 @@ import Data.Text.Short (ShortText) import Data.Text.Short.Unsafe (fromShortByteStringUnsafe) --- | Encode a 'ShortByteString' value as Base64 'Text' with padding.+-- | Encode a 'ShortByteString' value as Base64 'ShortText' with padding. -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: ShortByteString -> ShortText encodeBase64 = fromShortByteStringUnsafe . encodeBase64' {-# INLINE encodeBase64 #-}@@ -39,6 +49,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64' "Sun"+-- "U3Vu"+-- encodeBase64' :: ShortByteString -> ShortByteString encodeBase64' = toShort . B64.encodeBase64' . fromShort {-# INLINE encodeBase64' #-}@@ -47,6 +62,17 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: ShortByteString -> Either Text ShortByteString decodeBase64 = fmap toShort . B64.decodeBase64 . fromShort {-# INLINE decodeBase64 #-}@@ -57,12 +83,34 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: ShortByteString -> ShortByteString decodeBase64Lenient = toShort . B64.decodeBase64Lenient . fromShort {-# INLINE decodeBase64Lenient #-}  -- | Tell whether a 'ShortByteString' value is base64 encoded. --+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: ShortByteString -> Bool isBase64 = B64.isBase64 . fromShort {-# INLINE isBase64 #-}@@ -72,6 +120,20 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ShortByteString' value, use 'isBase64'.+--+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False -- isValidBase64 :: ShortByteString -> Bool isValidBase64 = B64.isValidBase64 . fromShort
src/Data/ByteString/Short/Base64/URL.hs view
@@ -1,25 +1,30 @@+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.ByteString.Short.Base64.URL -- Copyright    : (c) 2019-2020 Emily Pillmore -- License      : BSD-style -- -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>--- Stability    : Experimental--- Portability  : portable+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64url encoding including--- unpadded and lenient variants+-- This module contains 'Data.ByteString.Short.ShortByteString'-valued combinators for+-- implementing the RFC 4648 specification of the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient decoding+-- variants, as well as internal and external validation for canonicity. -- module Data.ByteString.Short.Base64.URL-( encodeBase64-, encodeBase64Unpadded+( -- * Encoding+  encodeBase64 , encodeBase64'+, encodeBase64Unpadded , encodeBase64Unpadded'+  -- * Decoding , decodeBase64-, decodeBase64Padded , decodeBase64Unpadded+, decodeBase64Padded , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -35,6 +40,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: ShortByteString -> ShortText encodeBase64 = fromShortByteStringUnsafe . encodeBase64' {-# INLINE encodeBase64 #-}@@ -43,6 +53,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64' "<<?>>"+-- "PDw_Pj4="+-- encodeBase64' :: ShortByteString -> ShortByteString encodeBase64' = toShort . B64U.encodeBase64' . fromShort @@ -54,6 +69,20 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: ShortByteString -> Either Text ShortByteString decodeBase64 = fmap toShort . B64U.decodeBase64 . fromShort @@ -65,6 +94,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: ShortByteString -> ShortText encodeBase64Unpadded = fromShortByteStringUnsafe . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-}@@ -75,6 +109,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded' "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded' :: ShortByteString -> ShortByteString encodeBase64Unpadded' = toShort . B64U.encodeBase64Unpadded' . fromShort @@ -87,6 +126,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: ShortByteString -> Either Text ShortByteString decodeBase64Unpadded = fmap toShort . B64U.decodeBase64Unpadded . fromShort {-# INLINE decodeBase64Unpadded #-}@@ -100,6 +147,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: ShortByteString -> Either Text ShortByteString decodeBase64Padded = fmap toShort . B64U.decodeBase64Padded . fromShort {-# INLINE decodeBase64Padded #-}@@ -110,12 +165,31 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: ShortByteString -> ShortByteString decodeBase64Lenient = toShort . B64U.decodeBase64Lenient . fromShort {-# INLINE decodeBase64Lenient #-}  -- | Tell whether a 'ShortByteString' is Base64url-encoded. --+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: ShortByteString -> Bool isBase64Url = B64U.isBase64Url . fromShort {-# INLINE isBase64Url #-}@@ -125,6 +199,17 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ShortByteString' value, use 'isBase64Url'.+--+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False -- isValidBase64Url :: ShortByteString -> Bool isValidBase64Url = B64U.isValidBase64Url . fromShort
src/Data/Text/Encoding/Base64.hs view
@@ -1,22 +1,26 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Safe #-} -- | -- Module       : Data.Text.Encoding.Base64--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Text'-valued combinators for+-- implementing the RFC 4648 specification of the Base64+-- encoding format. This includes lenient decoding variants, as well as+-- internal and external validation for canonicity. -- module Data.Text.Encoding.Base64-( encodeBase64+( -- * Encoding+  encodeBase64+  -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -34,6 +38,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: Text -> Text encodeBase64 = B64.encodeBase64 . T.encodeUtf8 {-# INLINE encodeBase64 #-}@@ -48,6 +57,17 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: Text -> Either Text Text decodeBase64 = fmap T.decodeLatin1 . B64.decodeBase64 . T.encodeUtf8 {-# INLINE decodeBase64 #-}@@ -58,7 +78,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8''@@ -82,6 +102,17 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: Text -> Text decodeBase64Lenient = T.decodeLatin1     . B64.decodeBase64Lenient@@ -90,6 +121,17 @@  -- | Tell whether a 'Text' value is Base64-encoded. --+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: Text -> Bool isBase64 = B64.isBase64 . T.encodeUtf8 {-# INLINE isBase64 #-}@@ -99,6 +141,20 @@ -- This will not tell you whether or not this is a correct Base64 representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'Text' value, use 'isBase64'.+--+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False -- isValidBase64 :: Text -> Bool isValidBase64 = B64.isValidBase64 . T.encodeUtf8
src/Data/Text/Encoding/Base64/Error.hs view
@@ -1,11 +1,13 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE Safe #-} -- | -- Module       : Data.Text.Encoding.Base64.Error--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable -- -- This module contains the error types raised (not as exceptions!) -- in the decoding process.@@ -15,8 +17,13 @@ ) where  +import Control.DeepSeq (NFData(..))+import Control.Exception (Exception(..))+ import Data.Text (Text) +import GHC.Generics+ -- | This data type represents the type of decoding errors of -- various kinds as they pertain to decoding 'Text' values. -- Namely, to distinguish between decoding errors from opaque@@ -29,4 +36,21 @@   | ConversionError e     -- ^ The error associated with the decoding failure     -- as a result of the conversion process-  deriving (Eq, Show)+  deriving+    ( Eq, Show+    , Generic+      -- ^ @since 4.2.2+    )++-- |+--+-- @since 4.2.2+--+instance Exception e => Exception (Base64Error e)+++-- |+--+-- @since 4.2.2+--+instance NFData e => NFData (Base64Error e)
src/Data/Text/Encoding/Base64/URL.hs view
@@ -1,26 +1,31 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Safe #-} -- | -- Module       : Data.Text.Encoding.Base64.URL--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64-URL encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Text'-valued combinators for+-- implementing the RFC 4648 specification of the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient decoding+-- variants, as well as internal and external validation for canonicity.+-- module Data.Text.Encoding.Base64.URL-( encodeBase64+( -- * Encoding+  encodeBase64+, encodeBase64Unpadded+  -- * Decoding , decodeBase64 , decodeBase64With-, encodeBase64Unpadded , decodeBase64Unpadded , decodeBase64UnpaddedWith , decodeBase64Padded , decodeBase64PaddedWith , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -38,6 +43,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: Text -> Text encodeBase64 = B64U.encodeBase64 . T.encodeUtf8 {-# INLINE encodeBase64 #-}@@ -56,6 +66,20 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: Text -> Either Text Text decodeBase64 = fmap T.decodeLatin1 . B64U.decodeBase64 . T.encodeUtf8 {-# INLINE decodeBase64 #-}@@ -66,7 +90,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8''@@ -90,6 +114,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: Text -> Text encodeBase64Unpadded = B64U.encodeBase64Unpadded . T.encodeUtf8 {-# INLINE encodeBase64Unpadded #-}@@ -104,6 +133,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: Text -> Either Text Text decodeBase64Unpadded = fmap T.decodeLatin1     . B64U.decodeBase64Unpadded@@ -116,10 +153,10 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @--- 'decodeBase64With' 'T.decodeUtf8''+-- 'decodeBase64UnpaddedWith' 'T.decodeUtf8'' --   :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ --@@ -144,6 +181,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: Text -> Either Text Text decodeBase64Padded = fmap T.decodeLatin1     . B64U.decodeBase64Padded@@ -156,10 +201,10 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @--- 'decodeBase64With' 'T.decodeUtf8''+-- 'decodeBase64PaddedWith' 'T.decodeUtf8'' --   :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ --@@ -180,6 +225,14 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: Text -> Text decodeBase64Lenient = T.decodeLatin1     . B64U.decodeBase64Lenient@@ -188,6 +241,17 @@  -- | Tell whether a 'Text' value is Base64url-encoded. --+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: Text -> Bool isBase64Url = B64U.isBase64Url . T.encodeUtf8 {-# INLINE isBase64Url #-}@@ -197,6 +261,17 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'Text' value, use 'isBase64Url'.+--+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False -- isValidBase64Url :: Text -> Bool isValidBase64Url = B64U.isValidBase64Url . T.encodeUtf8
src/Data/Text/Lazy/Encoding/Base64.hs view
@@ -1,21 +1,26 @@+{-# LANGUAGE Safe #-} -- | -- Module       : Data.Text.Lazy.Encoding.Base64--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Lazy.Text'-valued combinators+-- implementing the RFC 4648 specification for the Base64+-- encoding format. This includes lenient decoding variants, and+-- external + internal validations for canonicity. -- module Data.Text.Lazy.Encoding.Base64-( encodeBase64+( -- * Encoding+  encodeBase64+  -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -34,6 +39,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: TL.Text -> TL.Text encodeBase64 = BL64.encodeBase64 . TL.encodeUtf8 {-# INLINE encodeBase64 #-}@@ -48,6 +58,17 @@ -- caller to make sure inputs are valid. If unsure, defer to `decodeBase64With` -- and pass in a custom decode function. --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: TL.Text -> Either T.Text TL.Text decodeBase64 = fmap TL.decodeLatin1 . BL64.decodeBase64 . TL.encodeUtf8 {-# INLINE decodeBase64 #-}@@ -58,7 +79,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @ -- 'decodeBase64With' 'TL.decodeUtf8''@@ -82,6 +103,17 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: TL.Text -> TL.Text decodeBase64Lenient = TL.decodeLatin1     . BL64.decodeBase64Lenient@@ -90,6 +122,17 @@  -- | Tell whether a 'TL.Text' value is Base64-encoded. --+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: TL.Text -> Bool isBase64 = BL64.isBase64 . TL.encodeUtf8 {-# INLINE isBase64 #-}@@ -99,6 +142,20 @@ -- This will not tell you whether or not this is a correct Base64 representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'TL.Text' value, use 'isBase64'.+--+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False -- isValidBase64 :: TL.Text -> Bool isValidBase64 = BL64.isValidBase64 . TL.encodeUtf8
src/Data/Text/Lazy/Encoding/Base64/URL.hs view
@@ -1,26 +1,31 @@+{-# LANGUAGE Safe #-} -- | -- Module       : Data.Text.Lazy.Encoding.Base64.URL--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64-URL encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Lazy.Text'-valued combinators for+-- implementing the RFC 4648 specification of the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient decoding+-- variants, as well as internal and external validation for canonicity. -- module Data.Text.Lazy.Encoding.Base64.URL-( encodeBase64+( -- * Encoding+  encodeBase64+, encodeBase64Unpadded+  -- * Decoding , decodeBase64 , decodeBase64With-, encodeBase64Unpadded , decodeBase64Unpadded , decodeBase64UnpaddedWith , decodeBase64Padded , decodeBase64PaddedWith , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -39,6 +44,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: TL.Text -> TL.Text encodeBase64 = BL64U.encodeBase64 . TL.encodeUtf8 {-# INLINE encodeBase64 #-}@@ -57,6 +67,20 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: TL.Text -> Either T.Text TL.Text decodeBase64 = fmap TL.decodeLatin1 . BL64U.decodeBase64 . TL.encodeUtf8 {-# INLINE decodeBase64 #-}@@ -67,7 +91,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @ -- 'decodeBase64With' 'TL.decodeUtf8''@@ -91,6 +115,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: TL.Text -> TL.Text encodeBase64Unpadded = BL64U.encodeBase64Unpadded . TL.encodeUtf8 {-# INLINE encodeBase64Unpadded #-}@@ -105,6 +134,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: TL.Text -> Either T.Text TL.Text decodeBase64Unpadded = fmap TL.decodeLatin1     . BL64U.decodeBase64Unpadded@@ -117,10 +154,10 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @--- 'decodeBase64With' 'TL.decodeUtf8''+-- 'decodeBase64UnpaddedWith' 'TL.decodeUtf8'' --   :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'TL.Text' -- @ --@@ -145,6 +182,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: TL.Text -> Either T.Text TL.Text decodeBase64Padded = fmap TL.decodeLatin1     . BL64U.decodeBase64Padded@@ -157,11 +202,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @--- 'decodeBase64With' 'TL.decodeUtf8''---   :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'TL.Text'+-- 'decodeBase64PaddedWith' 'T.decodeUtf8''+--   :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ -- decodeBase64PaddedWith@@ -181,14 +226,33 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: TL.Text -> TL.Text decodeBase64Lenient = TL.decodeLatin1     . BL64U.decodeBase64Lenient     . TL.encodeUtf8 {-# INLINE decodeBase64Lenient #-} --- | Tell whether a 'TL.Text' value is Base64url-encoded.+-- | Tell whether a 'TL.Text' value is Base64url-encoded --+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: TL.Text -> Bool isBase64Url = BL64U.isBase64Url . TL.encodeUtf8 {-# INLINE isBase64Url #-}@@ -198,6 +262,17 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'TL.Text' value, use 'isBase64Url'.+--+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False -- isValidBase64Url :: TL.Text -> Bool isValidBase64Url = BL64U.isValidBase64Url . TL.encodeUtf8
src/Data/Text/Short/Encoding/Base64.hs view
@@ -1,22 +1,26 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Trustworthy #-} -- |--- Module       : Data.Text.Encoding.Base64--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Module       : Data.Text.Short.Encoding.Base64+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64 encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Short.ShortText'-valued combinators+-- implementing the RFC 4648 specification for the Base64+-- encoding format. This includes lenient decoding variants, and+-- external + internal validations for canonicity. -- module Data.Text.Short.Encoding.Base64-( encodeBase64+( -- * Encoding+  encodeBase64+  -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient+  -- * Validation , isBase64 , isValidBase64 ) where@@ -36,6 +40,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> encodeBase64 "Sun"+-- "U3Vu"+-- encodeBase64 :: ShortText -> ShortText encodeBase64 = fromByteStringUnsafe   . B64.encodeBase64'@@ -52,6 +61,17 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "U3Vu"+-- Right "Sun"+--+-- >>> decodeBase64 "U3V"+-- Left "Base64-encoded bytestring requires padding"+--+-- >>> decodebase64 "U3V="+-- Left "non-canonical encoding detected at offset: 2"+-- decodeBase64 :: ShortText -> Either Text ShortText decodeBase64 = fmap fromText . B64T.decodeBase64 . toText {-# INLINE decodeBase64 #-}@@ -62,7 +82,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Example__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8''@@ -86,12 +106,34 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "U3Vu"+-- "Sun"+--+-- >>> decodeBase64Lenient "U3V"+-- "Su"+--+-- >>> decodebase64Lenient "U3V="+-- "Su"+-- decodeBase64Lenient :: ShortText -> ShortText decodeBase64Lenient = fromText . B64T.decodeBase64Lenient . toText {-# INLINE decodeBase64Lenient #-}  -- | Tell whether a 'ShortText' value is Base64-encoded. --+-- === __Examples__:+--+-- >>> isBase64 "U3Vu"+-- True+--+-- >>> isBase64 "U3V"+-- False+--+-- >>> isBase64 "U3V="+-- False+-- isBase64 :: ShortText -> Bool isBase64 = B64.isBase64 . toByteString {-# INLINE isBase64 #-}@@ -101,6 +143,20 @@ -- This will not tell you whether or not this is a correct Base64 representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ShortText' value, use 'isBase64'.+--+-- === __Examples__:+--+-- >>> isValidBase64 "U3Vu"+-- True+--+-- >>> isValidBase64 "U3V"+-- True+--+-- >>> isValidBase64 "U3V="+-- True+--+-- >>> isValidBase64 "%"+-- False -- isValidBase64 :: ShortText -> Bool isValidBase64 = B64.isValidBase64 . toByteString
src/Data/Text/Short/Encoding/Base64/URL.hs view
@@ -1,25 +1,31 @@+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.Text.Short.Encoding.Base64.URL--- Copyright 	: (c) 2019-2020 Emily Pillmore--- License	: BSD-style+-- Copyright    : (c) 2019-2020 Emily Pillmore+-- License      : BSD-style ----- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>--- Stability	: Experimental--- Portability	: portable+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>+-- Stability    : stable+-- Portability  : non-portable ----- This module contains the combinators implementing the--- RFC 4648 specification for the Base64-URL encoding including--- unpadded and lenient variants+-- This module contains 'Data.Text.Short.ShortText'-valued combinators+-- implementing the RFC 4648 specification for the Base64url+-- encoding format. This includes strictly padded/unpadded and lenient+-- decoding variants, and external + internal validations for canonicity.+-- module Data.Text.Short.Encoding.Base64.URL-( encodeBase64+( -- * Encoding+  encodeBase64+, encodeBase64Unpadded+  -- * Decoding , decodeBase64 , decodeBase64With-, encodeBase64Unpadded , decodeBase64Unpadded , decodeBase64UnpaddedWith , decodeBase64Padded , decodeBase64PaddedWith , decodeBase64Lenient+  -- * Validation , isBase64Url , isValidBase64Url ) where@@ -39,6 +45,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> --+-- === __Examples__:+--+-- >>> encodeBase64 "<<?>>"+-- "PDw_Pj4="+-- encodeBase64 :: ShortText -> ShortText encodeBase64 = fromByteStringUnsafe   . B64U.encodeBase64'@@ -59,6 +70,20 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64 "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64 "PDw-Pg="+-- Left "Base64-encoded bytestring has invalid padding"+--+-- >>> decodeBase64 "PDw-Pg"+-- Right "<<>>"+-- decodeBase64 :: ShortText -> Either Text ShortText decodeBase64 = fmap fromText . B64TU.decodeBase64 . toText {-# INLINE decodeBase64 #-}@@ -69,7 +94,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8''@@ -93,6 +118,11 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> --+-- === __Examples__:+--+-- >>> encodeBase64Unpadded "<<?>>"+-- "PDw_Pj4"+-- encodeBase64Unpadded :: ShortText -> ShortText encodeBase64Unpadded = fromByteStringUnsafe   . B64U.encodeBase64Unpadded'@@ -109,6 +139,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Unpadded "PDw_Pj4"+-- Right "<<?>>"+--+-- >>> decodeBase64Unpadded "PDw_Pj4="+-- Left "Base64-encoded bytestring has invalid padding"+-- decodeBase64Unpadded :: ShortText -> Either Text ShortText decodeBase64Unpadded = fmap fromText . B64TU.decodeBase64Unpadded . toText {-# INLINE decodeBase64Unpadded #-}@@ -119,10 +157,10 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @--- 'decodeBase64With' 'T.decodeUtf8''+-- 'decodeBase64UnpaddedWith' 'T.decodeUtf8'' --   :: 'ShortByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'ShortText' -- @ --@@ -147,6 +185,14 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> --+-- === __Examples__:+--+-- >>> decodeBase64Padded "PDw_Pj4="+-- Right "<<?>>"+--+-- >>> decodeBase64Padded "PDw_Pj4"+-- Left "Base64-encoded bytestring requires padding"+-- decodeBase64Padded :: ShortText -> Either Text ShortText decodeBase64Padded = fmap fromText . B64TU.decodeBase64Padded . toText {-# INLINE decodeBase64Padded #-}@@ -157,7 +203,7 @@ -- -- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> ----- Example:+-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8''@@ -181,12 +227,31 @@ -- -- __Note:__ This is not RFC 4648-compliant. --+-- === __Examples__:+--+-- >>> decodeBase64Lenient "PDw_Pj4="+-- "<<?>>"+--+-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"+-- "<<?>>"+-- decodeBase64Lenient :: ShortText -> ShortText decodeBase64Lenient = fromText . B64TU.decodeBase64Lenient . toText {-# INLINE decodeBase64Lenient #-}  -- | Tell whether a 'ShortText' value is Base64url-encoded. --+-- === __Examples__:+--+-- >>> isBase64Url "PDw_Pj4="+-- True+--+-- >>> isBase64Url "PDw_Pj4"+-- True+--+-- >>> isBase64Url "PDw_Pj"+-- False+-- isBase64Url :: ShortText -> Bool isBase64Url = B64U.isBase64Url . toByteString {-# INLINE isBase64Url #-}@@ -196,6 +261,17 @@ -- This will not tell you whether or not this is a correct Base64url representation, -- only that it conforms to the correct shape. To check whether it is a true -- Base64 encoded 'ShortText' value, use 'isBase64Url'.+--+-- === __Examples__:+--+-- >>> isValidBase64Url "PDw_Pj4="+-- True+--+-- >>> isValidBase64Url "PDw_Pj"+-- True+--+-- >>> isValidBase64Url "%"+-- False -- isValidBase64Url :: ShortText -> Bool isValidBase64Url = B64U.isValidBase64Url . toByteString
test/Internal.hs view
@@ -44,7 +44,6 @@ import "base64" Data.Text.Short.Encoding.Base64.URL as TS64U  import Test.QuickCheck hiding (label)-import Test.QuickCheck.Instances ()  -- ------------------------------------------------------------------ -- -- Test Harnesses@@ -237,14 +236,44 @@ -- ------------------------------------------------------------------ -- -- Quickcheck instances +instance Arbitrary BS.ByteString where+    arbitrary = BS.pack <$> arbitrary+    shrink xs = BS.pack <$> shrink (BS.unpack xs)++instance CoArbitrary BS.ByteString where+    coarbitrary = coarbitrary . BS.unpack++instance Arbitrary LBS.ByteString where+    arbitrary = LBS.pack <$> arbitrary+    shrink xs = LBS.pack <$> shrink (LBS.unpack xs)++instance CoArbitrary LBS.ByteString where+    coarbitrary = coarbitrary . LBS.unpack++instance Arbitrary SBS.ShortByteString where+    arbitrary = SBS.pack <$> arbitrary+    shrink xs = SBS.pack <$> shrink (SBS.unpack xs)++instance CoArbitrary SBS.ShortByteString where+    coarbitrary = coarbitrary . SBS.unpack++instance Arbitrary T.Text where+    arbitrary = T.pack <$> arbitrary+    shrink xs = T.pack <$> shrink (T.unpack xs)++instance Arbitrary TL.Text where+    arbitrary = TL.pack <$> arbitrary+    shrink xs = TL.pack <$> shrink (TL.unpack xs)++instance CoArbitrary T.Text where+    coarbitrary = coarbitrary . T.unpack++instance CoArbitrary TL.Text where+    coarbitrary = coarbitrary . TL.unpack+ instance Arbitrary TS.ShortText where   arbitrary = TS.fromText <$> arbitrary   shrink xs = fmap TS.fromText $ shrink (TS.toText xs)  instance CoArbitrary TS.ShortText where   coarbitrary = coarbitrary . TS.toText--instance Function TS.ShortText where-  function = functionMap-    (T.unpack . TS.toText)-    (TS.fromText . T.pack)
test/Main.hs view
@@ -130,6 +130,8 @@   [ paddingTests last_ length_   , rfcVectors   , offsetVectors+  , validityTests+  , canonicityTests   ]  -- | Make unit tests for textual 'decode*With' functions@@ -373,7 +375,10 @@       decode @a "eAoe=Ao=" @=? Left "invalid padding at offset: 4"       decode @a "eAoeA=o=" @=? Left "invalid padding at offset: 5"     ]-  , testGroup "Non-canonical encodings fail and canonical encodings succeed"+  ]++canonicityTests :: forall a b proxy. Harness a b => proxy a -> TestTree+canonicityTests _ =  testGroup "Canonicity unit tests"     [ testCase "roundtrip for d ~ ZA==" $ do       decode @a "ZE==" @=? Left "non-canonical encoding detected at offset: 1"       decode @a "ZK==" @=? Left "non-canonical encoding detected at offset: 1"@@ -393,7 +398,6 @@       decode @a "Zm9vYmD=" @=? Left "non-canonical encoding detected at offset: 6"       decode @a "Zm9vYmA=" @=? Right "foob`"     ]-  ]  -- | Unit test trees for the `decode*With` family of text-valued functions --@@ -462,5 +466,60 @@       a <- either (assertFailure . show) pure $ decodeUrlNopad @a "PDw_Pz4-"       b <- either (assertFailure . show) pure $ decodeUrlUnpaddedWith_ @a utf8 "PDw_Pz4-"       a @=? b+    ]+  ]++-- | Validity unit tests for the URL workflow+--+validityTests :: forall a b proxy. Harness a b => proxy a -> TestTree+validityTests _ = testGroup "Validity and correctness unit tests"+  [ testGroup "Validity unit tests"+    [ testCase "Padding tests" $ do+      not (validateUrl @a "P") @? "P"+      validateUrl @a "PA" @? "PA"+      validateUrl @a "PDw" @? "PDw"+      validateUrl @a "PDw_" @? "PDw_"+      validateUrl @a "PA==" @? "PA=="+      validateUrl @a "PDw=" @? "PDw="+      validateUrl @a "PDw_" @? "PDw_"++    , testCase "Canonicity tests" $ do+      validateUrl @a "ZK==" @? "ZK=="+      validateUrl @a "ZE==" @? "ZE=="++      validateUrl @a "ZA==" @? "ZA=="+      validateUrl @a "ZK==" @? "ZK=="+      validateUrl @a "ZK" @? "ZK"++      validateUrl @a "ZmA=" @? "ZmA="+      validateUrl @a "ZmC=" @? "ZmC="+      validateUrl @a "ZmE" @? "ZmE"++      validateUrl @a "Zm9vYmA=" @? "Zm9vYmA="+      validateUrl @a "Zm9vYmC=" @? "Zm9vYmC="+      validateUrl @a "Zm9vYmC" @? "Zm9vYmC"+    ]+  , testGroup "Correctness unit tests"+    [ testCase "Padding tests" $ do+      not (validateUrl @a "P") @? "P"+      correctUrl @a "PA" @? "PA"+      correctUrl @a "PDw" @? "PDw"+      correctUrl @a "PDw_" @? "PDw_"+      correctUrl @a "PA==" @? "PA=="+      correctUrl @a "PDw=" @? "PDw="+      correctUrl @a "PDw_" @? "PDw_"++    , testCase "Canonicity tests" $ do+      not (correctUrl @a "ZK==") @? "ZK=="+      not (correctUrl @a "ZE==") @? "ZE=="+      correctUrl @a "ZA==" @? "ZA=="++      correctUrl @a "ZmA=" @? "ZmA="+      not (correctUrl @a "ZmC=") @? "ZmC="+      not (correctUrl @a "ZmD") @? "ZmD"++      correctUrl @a "Zm9vYmA=" @? "Zm9vYmA="+      not (correctUrl @a "Zm9vYmC=") @? "Zm9vYmC="+      not (correctUrl @a "Zm9vYmC") @? "Zm9vYmC"     ]   ]