From 3dd41cc56d6cf0310dd74b7fea0c38ef0eb01e05 Mon Sep 17 00:00:00 2001 From: Emily Pillmore Date: Fri, 3 Jul 2020 18:48:46 -0400 Subject: [PATCH] massive doc updates (#29) * massive doc updates * small mistake --- src/Data/ByteString/Base64.hs | 62 ++++++++++++++- src/Data/ByteString/Base64/URL.hs | 87 ++++++++++++++++++++- src/Data/ByteString/Lazy/Base64.hs | 66 +++++++++++++++- src/Data/ByteString/Lazy/Base64/URL.hs | 87 ++++++++++++++++++++- src/Data/ByteString/Short/Base64.hs | 62 ++++++++++++++- src/Data/ByteString/Short/Base64/URL.hs | 89 ++++++++++++++++++++- src/Data/Text/Encoding/Base64.hs | 59 +++++++++++++- src/Data/Text/Encoding/Base64/URL.hs | 87 +++++++++++++++++++-- src/Data/Text/Lazy/Encoding/Base64.hs | 59 +++++++++++++- src/Data/Text/Lazy/Encoding/Base64/URL.hs | 91 +++++++++++++++++++--- src/Data/Text/Short/Encoding/Base64.hs | 59 +++++++++++++- src/Data/Text/Short/Encoding/Base64/URL.hs | 85 ++++++++++++++++++-- 12 files changed, 855 insertions(+), 38 deletions(-) diff --git a/src/Data/ByteString/Base64.hs b/src/Data/ByteString/Base64.hs index c2e1137..0cf229b 100644 --- a/src/Data/ByteString/Base64.hs +++ b/src/Data/ByteString/Base64.hs @@ -16,10 +16,13 @@ -- internal and external validation for canonicity. -- module Data.ByteString.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 , encodeBase64' + -- * Decoding , decodeBase64 , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -40,6 +43,11 @@ import System.IO.Unsafe -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: ByteString -> Text encodeBase64 = T.decodeUtf8 . encodeBase64' {-# inline encodeBase64 #-} @@ -48,6 +56,11 @@ encodeBase64 = T.decodeUtf8 . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "Sun" +-- "U3Vu" +-- encodeBase64' :: ByteString -> ByteString encodeBase64' = encodeBase64_ base64Table {-# inline encodeBase64' #-} @@ -56,6 +69,17 @@ encodeBase64' = encodeBase64_ base64Table -- -- See: -- +-- === __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) | l == 0 = Right bs @@ -74,6 +98,17 @@ decodeBase64 bs@(PS _ _ !l) -- -- __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 #-} @@ -84,6 +119,17 @@ decodeBase64Lenient = decodeBase64Lenient_ decodeB64Table -- 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 #-} @@ -94,6 +140,20 @@ isBase64 bs = isValidBase64 bs && isRight (decodeBase64 bs) -- 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 #-} diff --git a/src/Data/ByteString/Base64/URL.hs b/src/Data/ByteString/Base64/URL.hs index 4981ca3..e1e36f9 100644 --- a/src/Data/ByteString/Base64/URL.hs +++ b/src/Data/ByteString/Base64/URL.hs @@ -16,14 +16,17 @@ -- 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 @@ -45,6 +48,11 @@ import System.IO.Unsafe -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: ByteString -> Text encodeBase64 = T.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-} @@ -53,6 +61,11 @@ encodeBase64 = T.decodeUtf8 . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "<>" +-- "PDw_Pj4=" +-- encodeBase64' :: ByteString -> ByteString encodeBase64' = encodeBase64_ base64UrlTable @@ -64,6 +77,20 @@ encodeBase64' = encodeBase64_ base64UrlTable -- -- See: -- +-- === __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) | l == 0 = Right bs @@ -83,6 +110,11 @@ decodeBase64 bs@(PS _ _ !l) -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: ByteString -> Text encodeBase64Unpadded = T.decodeUtf8 . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-} @@ -93,6 +125,11 @@ encodeBase64Unpadded = T.decodeUtf8 . encodeBase64Unpadded' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded' "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded' :: ByteString -> ByteString encodeBase64Unpadded' = encodeBase64Nopad_ base64UrlTable @@ -105,6 +142,14 @@ encodeBase64Unpadded' = encodeBase64Nopad_ base64UrlTable -- -- See: -- +-- === __Examples__: +-- +-- >>> decodeBase64Unpadded "PDw_Pj4" +-- Right "<>" +-- +-- >>> decodeBase64Unpadded "PDw_Pj4=" +-- Left "Base64-encoded bytestring has invalid padding" +-- decodeBase64Unpadded :: ByteString -> Either Text ByteString decodeBase64Unpadded bs@(PS _ _ !l) | l == 0 = Right bs @@ -127,6 +172,14 @@ decodeBase64Unpadded bs@(PS _ _ !l) -- -- See: -- +-- === __Examples__: +-- +-- >>> decodeBase64Padded "PDw_Pj4=" +-- Right "<>" +-- +-- >>> decodeBase64Padded "PDw_Pj4" +-- Left "Base64-encoded bytestring requires padding" +-- decodeBase64Padded :: ByteString -> Either Text ByteString decodeBase64Padded bs@(PS _ _ !l) | l == 0 = Right bs @@ -145,6 +198,14 @@ decodeBase64Padded bs@(PS _ _ !l) -- -- __Note:__ This is not RFC 4648-compliant. -- +-- === __Examples__: +-- +-- >>> decodeBase64Lenient "PDw_Pj4=" +-- "<>" +-- +-- >>> decodeBase64Lenient "PDw_%%%$}Pj4" +-- "<>" +-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = decodeBase64Lenient_ decodeB64UrlTable {-# INLINE decodeBase64Lenient #-} @@ -155,6 +216,17 @@ decodeBase64Lenient = decodeBase64Lenient_ decodeB64UrlTable -- 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 #-} @@ -165,6 +237,17 @@ isBase64Url bs = isValidBase64Url bs && isRight (decodeBase64 bs) -- 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 = validateBase64Url "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" {-# INLINE isValidBase64Url #-} diff --git a/src/Data/ByteString/Lazy/Base64.hs b/src/Data/ByteString/Lazy/Base64.hs index ea7fdb0..5dc63eb 100644 --- a/src/Data/ByteString/Lazy/Base64.hs +++ b/src/Data/ByteString/Lazy/Base64.hs @@ -15,10 +15,13 @@ -- internal and external validation for canonicity. -- module Data.ByteString.Lazy.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 , encodeBase64' + -- * Decoding , decodeBase64 , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -40,6 +43,11 @@ import qualified Data.Text.Lazy.Encoding as TL -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: ByteString -> TL.Text encodeBase64 = TL.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-} @@ -48,6 +56,11 @@ encodeBase64 = TL.decodeUtf8 . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "Sun" +-- "U3Vu" +-- encodeBase64' :: ByteString -> ByteString encodeBase64' = fromChunks . fmap B64.encodeBase64' @@ -59,6 +72,17 @@ encodeBase64' = fromChunks -- -- See: -- +-- === __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 @@ -72,6 +96,17 @@ decodeBase64 = fmap (fromChunks . (:[])) -- -- __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 @@ -82,6 +117,21 @@ decodeBase64Lenient = fromChunks -- | 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 #-} @@ -92,6 +142,20 @@ isBase64 bs = isValidBase64 bs && isRight (decodeBase64 bs) -- 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 where diff --git a/src/Data/ByteString/Lazy/Base64/URL.hs b/src/Data/ByteString/Lazy/Base64/URL.hs index c80513b..59dee44 100644 --- a/src/Data/ByteString/Lazy/Base64/URL.hs +++ b/src/Data/ByteString/Lazy/Base64/URL.hs @@ -16,14 +16,17 @@ -- 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 @@ -46,6 +49,11 @@ import qualified Data.Text.Lazy.Encoding as TL -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: ByteString -> TL.Text encodeBase64 = TL.decodeUtf8 . encodeBase64' {-# INLINE encodeBase64 #-} @@ -54,6 +62,11 @@ encodeBase64 = TL.decodeUtf8 . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "<>" +-- "PDw_Pj4=" +-- encodeBase64' :: ByteString -> ByteString encodeBase64' = fromChunks . fmap B64U.encodeBase64' @@ -68,6 +81,20 @@ encodeBase64' = fromChunks -- -- See: -- +-- === __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 @@ -81,6 +108,11 @@ decodeBase64 = fmap (fromChunks . (:[])) -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: ByteString -> TL.Text encodeBase64Unpadded = TL.decodeUtf8 . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-} @@ -91,6 +123,11 @@ encodeBase64Unpadded = TL.decodeUtf8 . encodeBase64Unpadded' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded' "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded' :: ByteString -> ByteString encodeBase64Unpadded' = fromChunks . fmap B64U.encodeBase64Unpadded' @@ -106,6 +143,14 @@ encodeBase64Unpadded' = fromChunks -- -- See: -- +-- === __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 @@ -122,6 +167,14 @@ decodeBase64Unpadded = fmap (fromChunks . (:[])) -- -- See: -- +-- === __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 @@ -135,6 +188,14 @@ decodeBase64Padded = fmap (fromChunks . (:[])) -- -- __Note:__ This is not RFC 4648-compliant. -- +-- === __Examples__: +-- +-- >>> decodeBase64Lenient "PDw_Pj4=" +-- "<>" +-- +-- >>> decodeBase64Lenient "PDw_%%%$}Pj4" +-- "<>" +-- decodeBase64Lenient :: ByteString -> ByteString decodeBase64Lenient = fromChunks . fmap B64U.decodeBase64Lenient @@ -145,6 +206,17 @@ decodeBase64Lenient = fromChunks -- | 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 #-} @@ -155,6 +227,17 @@ isBase64Url bs = isValidBase64Url bs && isRight (decodeBase64 bs) -- 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 where diff --git a/src/Data/ByteString/Short/Base64.hs b/src/Data/ByteString/Short/Base64.hs index d5c5d18..a0323ad 100644 --- a/src/Data/ByteString/Short/Base64.hs +++ b/src/Data/ByteString/Short/Base64.hs @@ -14,10 +14,13 @@ -- internal and external validation for canonicity. -- module Data.ByteString.Short.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 , encodeBase64' + -- * Decoding , decodeBase64 , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -33,6 +36,11 @@ import Data.Text.Short.Unsafe (fromShortByteStringUnsafe) -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: ShortByteString -> ShortText encodeBase64 = fromShortByteStringUnsafe . encodeBase64' {-# INLINE encodeBase64 #-} @@ -41,6 +49,11 @@ encodeBase64 = fromShortByteStringUnsafe . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "Sun" +-- "U3Vu" +-- encodeBase64' :: ShortByteString -> ShortByteString encodeBase64' = toShort . B64.encodeBase64' . fromShort {-# INLINE encodeBase64' #-} @@ -49,6 +62,17 @@ encodeBase64' = toShort . B64.encodeBase64' . fromShort -- -- See: -- +-- === __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 #-} @@ -59,12 +83,34 @@ decodeBase64 = fmap toShort . B64.decodeBase64 . fromShort -- -- __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 #-} @@ -75,6 +121,20 @@ isBase64 = B64.isBase64 . fromShort -- 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 {-# INLINE isValidBase64 #-} diff --git a/src/Data/ByteString/Short/Base64/URL.hs b/src/Data/ByteString/Short/Base64/URL.hs index 0d371f4..2e9d388 100644 --- a/src/Data/ByteString/Short/Base64/URL.hs +++ b/src/Data/ByteString/Short/Base64/URL.hs @@ -14,14 +14,17 @@ -- 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 @@ -37,6 +40,11 @@ import Data.Text.Short.Unsafe (fromShortByteStringUnsafe) -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: ShortByteString -> ShortText encodeBase64 = fromShortByteStringUnsafe . encodeBase64' {-# INLINE encodeBase64 #-} @@ -45,6 +53,11 @@ encodeBase64 = fromShortByteStringUnsafe . encodeBase64' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64' "<>" +-- "PDw_Pj4=" +-- encodeBase64' :: ShortByteString -> ShortByteString encodeBase64' = toShort . B64U.encodeBase64' . fromShort @@ -56,6 +69,20 @@ encodeBase64' = toShort . B64U.encodeBase64' . fromShort -- -- See: -- +-- === __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 @@ -67,6 +94,11 @@ decodeBase64 = fmap toShort . B64U.decodeBase64 . fromShort -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: ShortByteString -> ShortText encodeBase64Unpadded = fromShortByteStringUnsafe . encodeBase64Unpadded' {-# INLINE encodeBase64Unpadded #-} @@ -77,6 +109,11 @@ encodeBase64Unpadded = fromShortByteStringUnsafe . encodeBase64Unpadded' -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded' "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded' :: ShortByteString -> ShortByteString encodeBase64Unpadded' = toShort . B64U.encodeBase64Unpadded' . fromShort @@ -89,6 +126,14 @@ encodeBase64Unpadded' = toShort . B64U.encodeBase64Unpadded' . fromShort -- -- See: -- +-- === __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 #-} @@ -102,6 +147,14 @@ decodeBase64Unpadded = fmap toShort . B64U.decodeBase64Unpadded . fromShort -- -- See: -- +-- === __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 #-} @@ -112,12 +165,31 @@ decodeBase64Padded = fmap toShort . B64U.decodeBase64Padded . fromShort -- -- __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 #-} @@ -128,6 +200,17 @@ isBase64Url = B64U.isBase64Url . fromShort -- 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 {-# INLINE isValidBase64Url #-} diff --git a/src/Data/Text/Encoding/Base64.hs b/src/Data/Text/Encoding/Base64.hs index 940a22f..5989a0d 100644 --- a/src/Data/Text/Encoding/Base64.hs +++ b/src/Data/Text/Encoding/Base64.hs @@ -14,10 +14,13 @@ -- internal and external validation for canonicity. -- module Data.Text.Encoding.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 + -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -35,6 +38,11 @@ import Data.Text.Encoding.Base64.Error -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: Text -> Text encodeBase64 = B64.encodeBase64 . T.encodeUtf8 {-# INLINE encodeBase64 #-} @@ -49,6 +57,17 @@ encodeBase64 = B64.encodeBase64 . T.encodeUtf8 -- -- See: -- +-- === __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 #-} @@ -59,7 +78,7 @@ decodeBase64 = fmap T.decodeLatin1 . B64.decodeBase64 . T.encodeUtf8 -- -- See: -- --- Example: +-- === __Example__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8'' @@ -83,6 +102,17 @@ decodeBase64With f t = case B64.decodeBase64 t of -- -- __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 @@ -91,6 +121,17 @@ decodeBase64Lenient = T.decodeLatin1 -- | 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 #-} @@ -101,6 +142,20 @@ isBase64 = B64.isBase64 . T.encodeUtf8 -- 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 {-# INLINE isValidBase64 #-} diff --git a/src/Data/Text/Encoding/Base64/URL.hs b/src/Data/Text/Encoding/Base64/URL.hs index c2a768b..54f2017 100644 --- a/src/Data/Text/Encoding/Base64/URL.hs +++ b/src/Data/Text/Encoding/Base64/URL.hs @@ -14,15 +14,18 @@ -- 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 @@ -40,6 +43,11 @@ import Data.Text.Encoding.Base64.Error -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: Text -> Text encodeBase64 = B64U.encodeBase64 . T.encodeUtf8 {-# INLINE encodeBase64 #-} @@ -58,6 +66,20 @@ encodeBase64 = B64U.encodeBase64 . T.encodeUtf8 -- -- See: -- +-- === __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 #-} @@ -68,7 +90,7 @@ decodeBase64 = fmap T.decodeLatin1 . B64U.decodeBase64 . T.encodeUtf8 -- -- See: -- --- Example: +-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8'' @@ -92,6 +114,11 @@ decodeBase64With f t = case B64U.decodeBase64 t of -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: Text -> Text encodeBase64Unpadded = B64U.encodeBase64Unpadded . T.encodeUtf8 {-# INLINE encodeBase64Unpadded #-} @@ -106,6 +133,14 @@ encodeBase64Unpadded = B64U.encodeBase64Unpadded . T.encodeUtf8 -- -- See: -- +-- === __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 @@ -118,10 +153,10 @@ decodeBase64Unpadded = fmap T.decodeLatin1 -- -- See: -- --- Example: +-- === __Example__: -- -- @ --- 'decodeBase64With' 'T.decodeUtf8'' +-- 'decodeBase64UnpaddedWith' 'T.decodeUtf8'' -- :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ -- @@ -146,6 +181,14 @@ decodeBase64UnpaddedWith f t = case B64U.decodeBase64Unpadded t of -- -- See: -- +-- === __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 @@ -158,10 +201,10 @@ decodeBase64Padded = fmap T.decodeLatin1 -- -- See: -- --- Example: +-- === __Example__: -- -- @ --- 'decodeBase64With' 'T.decodeUtf8'' +-- 'decodeBase64PaddedWith' 'T.decodeUtf8'' -- :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ -- @@ -182,6 +225,14 @@ decodeBase64PaddedWith f t = case B64U.decodeBase64Padded t of -- -- __Note:__ This is not RFC 4648-compliant. -- +-- === __Examples__: +-- +-- >>> decodeBase64Lenient "PDw_Pj4=" +-- "<>" +-- +-- >>> decodeBase64Lenient "PDw_%%%$}Pj4" +-- "<>" +-- decodeBase64Lenient :: Text -> Text decodeBase64Lenient = T.decodeLatin1 . B64U.decodeBase64Lenient @@ -190,6 +241,17 @@ decodeBase64Lenient = T.decodeLatin1 -- | 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 #-} @@ -200,6 +262,17 @@ isBase64Url = B64U.isBase64Url . T.encodeUtf8 -- 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 {-# INLINE isValidBase64Url #-} diff --git a/src/Data/Text/Lazy/Encoding/Base64.hs b/src/Data/Text/Lazy/Encoding/Base64.hs index 41c58dd..fe07566 100644 --- a/src/Data/Text/Lazy/Encoding/Base64.hs +++ b/src/Data/Text/Lazy/Encoding/Base64.hs @@ -14,10 +14,13 @@ -- external + internal validations for canonicity. -- module Data.Text.Lazy.Encoding.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 + -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -36,6 +39,11 @@ import qualified Data.Text.Lazy.Encoding as TL -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: TL.Text -> TL.Text encodeBase64 = BL64.encodeBase64 . TL.encodeUtf8 {-# INLINE encodeBase64 #-} @@ -50,6 +58,17 @@ encodeBase64 = BL64.encodeBase64 . TL.encodeUtf8 -- 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 #-} @@ -60,7 +79,7 @@ decodeBase64 = fmap TL.decodeLatin1 . BL64.decodeBase64 . TL.encodeUtf8 -- -- See: -- --- Example: +-- === __Example__: -- -- @ -- 'decodeBase64With' 'TL.decodeUtf8'' @@ -84,6 +103,17 @@ decodeBase64With f t = case BL64.decodeBase64 t of -- -- __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 @@ -92,6 +122,17 @@ decodeBase64Lenient = TL.decodeLatin1 -- | 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 #-} @@ -102,6 +143,20 @@ isBase64 = BL64.isBase64 . TL.encodeUtf8 -- 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 {-# INLINE isValidBase64 #-} diff --git a/src/Data/Text/Lazy/Encoding/Base64/URL.hs b/src/Data/Text/Lazy/Encoding/Base64/URL.hs index ec00fd5..00af9df 100644 --- a/src/Data/Text/Lazy/Encoding/Base64/URL.hs +++ b/src/Data/Text/Lazy/Encoding/Base64/URL.hs @@ -14,15 +14,18 @@ -- 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 @@ -41,6 +44,11 @@ import qualified Data.Text.Lazy.Encoding as TL -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: TL.Text -> TL.Text encodeBase64 = BL64U.encodeBase64 . TL.encodeUtf8 {-# INLINE encodeBase64 #-} @@ -59,6 +67,20 @@ encodeBase64 = BL64U.encodeBase64 . TL.encodeUtf8 -- -- See: -- +-- === __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 #-} @@ -69,7 +91,7 @@ decodeBase64 = fmap TL.decodeLatin1 . BL64U.decodeBase64 . TL.encodeUtf8 -- -- See: -- --- Example: +-- === __Examples__: -- -- @ -- 'decodeBase64With' 'TL.decodeUtf8'' @@ -93,6 +115,11 @@ decodeBase64With f t = case BL64U.decodeBase64 t of -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: TL.Text -> TL.Text encodeBase64Unpadded = BL64U.encodeBase64Unpadded . TL.encodeUtf8 {-# INLINE encodeBase64Unpadded #-} @@ -107,6 +134,14 @@ encodeBase64Unpadded = BL64U.encodeBase64Unpadded . TL.encodeUtf8 -- -- See: -- +-- === __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 @@ -119,10 +154,10 @@ decodeBase64Unpadded = fmap TL.decodeLatin1 -- -- See: -- --- Example: +-- === __Examples__: -- -- @ --- 'decodeBase64With' 'TL.decodeUtf8'' +-- 'decodeBase64UnpaddedWith' 'TL.decodeUtf8'' -- :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'TL.Text' -- @ -- @@ -147,6 +182,14 @@ decodeBase64UnpaddedWith f t = case BL64U.decodeBase64Unpadded t of -- -- See: -- +-- === __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 @@ -159,11 +202,11 @@ decodeBase64Padded = fmap TL.decodeLatin1 -- -- See: -- --- Example: +-- === __Example__: -- -- @ --- 'decodeBase64With' 'TL.decodeUtf8'' --- :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'TL.Text' +-- 'decodeBase64PaddedWith' 'T.decodeUtf8'' +-- :: 'ByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'Text' -- @ -- decodeBase64PaddedWith @@ -183,13 +226,32 @@ decodeBase64PaddedWith f t = case BL64U.decodeBase64Padded t of -- -- __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 @@ -201,6 +263,17 @@ isBase64Url = BL64U.isBase64Url . TL.encodeUtf8 -- 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 {-# INLINE isValidBase64Url #-} diff --git a/src/Data/Text/Short/Encoding/Base64.hs b/src/Data/Text/Short/Encoding/Base64.hs index d2d684d..53ec4ad 100644 --- a/src/Data/Text/Short/Encoding/Base64.hs +++ b/src/Data/Text/Short/Encoding/Base64.hs @@ -14,10 +14,13 @@ -- external + internal validations for canonicity. -- module Data.Text.Short.Encoding.Base64 -( encodeBase64 +( -- * Encoding + encodeBase64 + -- * Decoding , decodeBase64 , decodeBase64With , decodeBase64Lenient + -- * Validation , isBase64 , isValidBase64 ) where @@ -37,6 +40,11 @@ import Data.Text.Short.Unsafe -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "Sun" +-- "U3Vu" +-- encodeBase64 :: ShortText -> ShortText encodeBase64 = fromByteStringUnsafe . B64.encodeBase64' @@ -53,6 +61,17 @@ encodeBase64 = fromByteStringUnsafe -- -- See: -- +-- === __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 #-} @@ -63,7 +82,7 @@ decodeBase64 = fmap fromText . B64T.decodeBase64 . toText -- -- See: -- --- Example: +-- === __Example__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8'' @@ -87,12 +106,34 @@ decodeBase64With f t = case BS64.decodeBase64 t of -- -- __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 #-} @@ -103,6 +144,20 @@ isBase64 = B64.isBase64 . toByteString -- 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 {-# INLINE isValidBase64 #-} diff --git a/src/Data/Text/Short/Encoding/Base64/URL.hs b/src/Data/Text/Short/Encoding/Base64/URL.hs index bdde6e3..a1892b3 100644 --- a/src/Data/Text/Short/Encoding/Base64/URL.hs +++ b/src/Data/Text/Short/Encoding/Base64/URL.hs @@ -14,15 +14,18 @@ -- 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 @@ -42,6 +45,11 @@ import Data.Text.Short.Unsafe -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64 "<>" +-- "PDw_Pj4=" +-- encodeBase64 :: ShortText -> ShortText encodeBase64 = fromByteStringUnsafe . B64U.encodeBase64' @@ -62,6 +70,20 @@ encodeBase64 = fromByteStringUnsafe -- -- See: -- +-- === __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 #-} @@ -72,7 +94,7 @@ decodeBase64 = fmap fromText . B64TU.decodeBase64 . toText -- -- See: -- --- Example: +-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8'' @@ -96,6 +118,11 @@ decodeBase64With f t = case BS64U.decodeBase64 t of -- -- See: -- +-- === __Examples__: +-- +-- >>> encodeBase64Unpadded "<>" +-- "PDw_Pj4" +-- encodeBase64Unpadded :: ShortText -> ShortText encodeBase64Unpadded = fromByteStringUnsafe . B64U.encodeBase64Unpadded' @@ -112,6 +139,14 @@ encodeBase64Unpadded = fromByteStringUnsafe -- -- See: -- +-- === __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 #-} @@ -122,10 +157,10 @@ decodeBase64Unpadded = fmap fromText . B64TU.decodeBase64Unpadded . toText -- -- See: -- --- Example: +-- === __Examples__: -- -- @ --- 'decodeBase64With' 'T.decodeUtf8'' +-- 'decodeBase64UnpaddedWith' 'T.decodeUtf8'' -- :: 'ShortByteString' -> 'Either' ('Base64Error' 'UnicodeException') 'ShortText' -- @ -- @@ -150,6 +185,14 @@ decodeBase64UnpaddedWith f t = case BS64U.decodeBase64Unpadded t of -- -- See: -- +-- === __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 #-} @@ -160,7 +203,7 @@ decodeBase64Padded = fmap fromText . B64TU.decodeBase64Padded . toText -- -- See: -- --- Example: +-- === __Examples__: -- -- @ -- 'decodeBase64With' 'T.decodeUtf8'' @@ -184,12 +227,31 @@ decodeBase64PaddedWith f t = case BS64U.decodeBase64Padded t of -- -- __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 #-} @@ -200,6 +262,17 @@ isBase64Url = B64U.isBase64Url . toByteString -- 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 {-# INLINE isValidBase64Url #-}