{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
-- |
-- Module       : Data.ByteString.Lazy.Base64.URL
-- Copyright    : (c) 2019-2026 Emily Pillmore
-- License      : BSD-style
--
-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>
-- Stability    : stable
-- Portability  : non-portable
--
-- 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
( -- * Encoding
  encodeBase64
, encodeBase64'
, encodeBase64Unpadded
, encodeBase64Unpadded'
  -- * Decoding
, decodeBase64
, decodeBase64Untyped
, decodeBase64Unpadded
, decodeBase64UnpaddedUntyped
, decodeBase64Padded
, decodeBase64PaddedUntyped
, decodeBase64Lenient
  -- * Parsing
, parseBase64Padded
, parseBase64Unpadded
) where


import Data.Base64.Types
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64.URL as B64U
import Data.ByteString.Base64.Internal.Utils (reChunkN)
import Data.ByteString.Lazy (fromChunks, toChunks)
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Internal (ByteString(..))
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL


-- $setup
--
-- >>> import Data.Base64.Types
-- >>> :set -XOverloadedStrings
-- >>> :set -XTypeApplications
-- >>> :set -XDataKinds
--

-- | Encode a 'ByteString' value as a Base64url 'Text' value with padding.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5>
--
-- === __Examples__:
--
-- >>> encodeBase64 "<<?>>"
-- "PDw_Pj4="
--
encodeBase64 :: ByteString -> Base64 'UrlPadded TL.Text
encodeBase64 :: ByteString -> Base64 'UrlPadded Text
encodeBase64 = (ByteString -> Text)
-> Base64 'UrlPadded ByteString -> Base64 'UrlPadded Text
forall a b. (a -> b) -> Base64 'UrlPadded a -> Base64 'UrlPadded b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Text
TL.decodeUtf8 (Base64 'UrlPadded ByteString -> Base64 'UrlPadded Text)
-> (ByteString -> Base64 'UrlPadded ByteString)
-> ByteString
-> Base64 'UrlPadded Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base64 'UrlPadded ByteString
encodeBase64'
{-# INLINE encodeBase64 #-}

-- | Encode a 'ByteString' as a Base64url 'ByteString' value with padding.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5>
--
-- === __Examples__:
--
-- >>> encodeBase64' "<<?>>"
-- "PDw_Pj4="
--
encodeBase64' :: ByteString -> Base64 'UrlPadded ByteString
encodeBase64' :: ByteString -> Base64 'UrlPadded ByteString
encodeBase64' = ByteString -> Base64 'UrlPadded ByteString
forall (k :: Alphabet) a. a -> Base64 k a
assertBase64 (ByteString -> Base64 'UrlPadded ByteString)
-> (ByteString -> ByteString)
-> ByteString
-> Base64 'UrlPadded ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StrictByteString] -> ByteString
fromChunks
  ([StrictByteString] -> ByteString)
-> (ByteString -> [StrictByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> StrictByteString)
-> [StrictByteString] -> [StrictByteString]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Base64 'UrlPadded StrictByteString -> StrictByteString
forall (k :: Alphabet) a. Base64 k a -> a
extractBase64 (Base64 'UrlPadded StrictByteString -> StrictByteString)
-> (StrictByteString -> Base64 'UrlPadded StrictByteString)
-> StrictByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Base64 'UrlPadded StrictByteString
B64U.encodeBase64')
  ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [StrictByteString] -> [StrictByteString]
reChunkN Int
3
  ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks

-- | Decode a Base64url encoded 'ByteString' value, either padded or unpadded.
-- The correct decoding function is dispatched based on the existence of padding.
--
-- For typed values:
--   - If a padded value is required, use 'decodeBase64Padded'
--   - If an unpadded value is required, use 'decodeBase64Unpadded'
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64 $ assertBase64 @'UrlPadded "PDw_Pj4="
-- "<<?>>"
--
-- >>> decodeBase64 $ assertBase64 @'UrlUnpadded "PDw_Pj4"
-- "<<?>>"
--
-- >>> decodeBase64 $ assertBase64 @'UrlUnpadded "PDw-Pg"
-- "<<>>"
--
decodeBase64
  :: UrlAlphabet k
  => Base64 k ByteString
  -> ByteString
decodeBase64 :: forall (k :: Alphabet).
UrlAlphabet k =>
Base64 k ByteString -> ByteString
decodeBase64 = [StrictByteString] -> ByteString
fromChunks
  ([StrictByteString] -> ByteString)
-> (Base64 k ByteString -> [StrictByteString])
-> Base64 k ByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> [StrictByteString]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  (StrictByteString -> [StrictByteString])
-> (Base64 k ByteString -> StrictByteString)
-> Base64 k ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 k StrictByteString -> StrictByteString
forall (k :: Alphabet).
UrlAlphabet k =>
Base64 k StrictByteString -> StrictByteString
B64U.decodeBase64
  (Base64 k StrictByteString -> StrictByteString)
-> (Base64 k ByteString -> Base64 k StrictByteString)
-> Base64 k ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> StrictByteString)
-> Base64 k ByteString -> Base64 k StrictByteString
forall a b. (a -> b) -> Base64 k a -> Base64 k b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> StrictByteString
BS.concat ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks)
{-# INLINE decodeBase64 #-}

-- | Decode a padded Base64url encoded 'ByteString' value. If its length is not a multiple
-- of 4, then padding chars will be added to fill out the input to a multiple of
-- 4 for safe decoding as Base64url-encoded values are optionally padded.
--
-- For a decoder that fails to decode untyped values of incorrect size:
--   - If a padded value is required, use 'decodeBase64PaddedUntyped'
--   - If an unpadded value is required, use 'decodeBase64UnpaddedUntyped'
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64Untyped "PDw_Pj4="
-- Right "<<?>>"
--
-- >>> decodeBase64Untyped "PDw_Pj4"
-- Right "<<?>>"
--
-- >>> decodeBase64Untyped "PDw-Pg="
-- Left "Base64-encoded bytestring has invalid padding"
--
-- >>> decodeBase64Untyped "PDw-Pg"
-- Right "<<>>"
--
decodeBase64Untyped :: ByteString -> Either T.Text ByteString
decodeBase64Untyped :: ByteString -> Either Text ByteString
decodeBase64Untyped = (StrictByteString -> ByteString)
-> Either Text StrictByteString -> Either Text ByteString
forall a b. (a -> b) -> Either Text a -> Either Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> ByteString
fromChunks ([StrictByteString] -> ByteString)
-> (StrictByteString -> [StrictByteString])
-> StrictByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> [StrictByteString]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure)
  (Either Text StrictByteString -> Either Text ByteString)
-> (ByteString -> Either Text StrictByteString)
-> ByteString
-> Either Text ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Either Text StrictByteString
B64U.decodeBase64Untyped
  (StrictByteString -> Either Text StrictByteString)
-> (ByteString -> StrictByteString)
-> ByteString
-> Either Text StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StrictByteString] -> StrictByteString
BS.concat
  ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks
{-# INLINE decodeBase64Untyped #-}

-- | Encode a 'ByteString' value as Base64url 'Text' without padding.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2>
--
-- === __Examples__:
--
-- >>> encodeBase64Unpadded "<<?>>"
-- "PDw_Pj4"
--
encodeBase64Unpadded :: ByteString -> Base64 'UrlUnpadded TL.Text
encodeBase64Unpadded :: ByteString -> Base64 'UrlUnpadded Text
encodeBase64Unpadded = (ByteString -> Text)
-> Base64 'UrlUnpadded ByteString -> Base64 'UrlUnpadded Text
forall a b.
(a -> b) -> Base64 'UrlUnpadded a -> Base64 'UrlUnpadded b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Text
TL.decodeUtf8 (Base64 'UrlUnpadded ByteString -> Base64 'UrlUnpadded Text)
-> (ByteString -> Base64 'UrlUnpadded ByteString)
-> ByteString
-> Base64 'UrlUnpadded Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Base64 'UrlUnpadded ByteString
encodeBase64Unpadded'
{-# INLINE encodeBase64Unpadded #-}

-- | Encode a 'ByteString' value as Base64url without padding.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2>
--
-- === __Examples__:
--
-- >>> encodeBase64Unpadded' "<<?>>"
-- "PDw_Pj4"
--
encodeBase64Unpadded' :: ByteString -> Base64 'UrlUnpadded ByteString
encodeBase64Unpadded' :: ByteString -> Base64 'UrlUnpadded ByteString
encodeBase64Unpadded' = ByteString -> Base64 'UrlUnpadded ByteString
forall (k :: Alphabet) a. a -> Base64 k a
assertBase64
  (ByteString -> Base64 'UrlUnpadded ByteString)
-> (ByteString -> ByteString)
-> ByteString
-> Base64 'UrlUnpadded ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StrictByteString] -> ByteString
fromChunks
  ([StrictByteString] -> ByteString)
-> (ByteString -> [StrictByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> StrictByteString)
-> [StrictByteString] -> [StrictByteString]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Base64 'UrlUnpadded StrictByteString -> StrictByteString
forall (k :: Alphabet) a. Base64 k a -> a
extractBase64 (Base64 'UrlUnpadded StrictByteString -> StrictByteString)
-> (StrictByteString -> Base64 'UrlUnpadded StrictByteString)
-> StrictByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Base64 'UrlUnpadded StrictByteString
B64U.encodeBase64Unpadded')
  ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [StrictByteString] -> [StrictByteString]
reChunkN Int
3
  ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks

-- | Decode an unpadded Base64url-encoded 'ByteString' value.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64Unpadded $ assertBase64 @'UrlUnpadded "PDw_Pj4"
-- "<<?>>"
--
decodeBase64Unpadded :: Base64 'UrlUnpadded ByteString -> ByteString
decodeBase64Unpadded :: Base64 'UrlUnpadded ByteString -> ByteString
decodeBase64Unpadded = [StrictByteString] -> ByteString
fromChunks
  ([StrictByteString] -> ByteString)
-> (Base64 'UrlUnpadded ByteString -> [StrictByteString])
-> Base64 'UrlUnpadded ByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> [StrictByteString]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  (StrictByteString -> [StrictByteString])
-> (Base64 'UrlUnpadded ByteString -> StrictByteString)
-> Base64 'UrlUnpadded ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 'UrlUnpadded StrictByteString -> StrictByteString
B64U.decodeBase64Unpadded
  (Base64 'UrlUnpadded StrictByteString -> StrictByteString)
-> (Base64 'UrlUnpadded ByteString
    -> Base64 'UrlUnpadded StrictByteString)
-> Base64 'UrlUnpadded ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> StrictByteString)
-> Base64 'UrlUnpadded ByteString
-> Base64 'UrlUnpadded StrictByteString
forall a b.
(a -> b) -> Base64 'UrlUnpadded a -> Base64 'UrlUnpadded b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> StrictByteString
BS.concat ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks)

-- | Decode an unpadded, untyped Base64url-encoded 'ByteString' value. Input strings are
-- required to be unpadded, and will undergo validation prior to decoding to
-- confirm.
--
-- In general, unless unpadded Base64url is explicitly required, it is
-- safer to call 'decodeBase64Untyped'.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64UnpaddedUntyped "PDw_Pj4"
-- Right "<<?>>"
--
-- >>> decodeBase64UnpaddedUntyped "PDw_Pj4="
-- Left "Base64-encoded bytestring has invalid padding"
--
decodeBase64UnpaddedUntyped :: ByteString -> Either T.Text ByteString
decodeBase64UnpaddedUntyped :: ByteString -> Either Text ByteString
decodeBase64UnpaddedUntyped = (StrictByteString -> ByteString)
-> Either Text StrictByteString -> Either Text ByteString
forall a b. (a -> b) -> Either Text a -> Either Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> ByteString
fromChunks ([StrictByteString] -> ByteString)
-> (StrictByteString -> [StrictByteString])
-> StrictByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> [StrictByteString] -> [StrictByteString]
forall a. a -> [a] -> [a]
:[]))
  (Either Text StrictByteString -> Either Text ByteString)
-> (ByteString -> Either Text StrictByteString)
-> ByteString
-> Either Text ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Either Text StrictByteString
B64U.decodeBase64UnpaddedUntyped
  (StrictByteString -> Either Text StrictByteString)
-> (ByteString -> StrictByteString)
-> ByteString
-> Either Text StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StrictByteString] -> StrictByteString
BS.concat
  ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks
{-# INLINE decodeBase64UnpaddedUntyped #-}

-- | Decode a padded Base64url-encoded 'ByteString' value.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64Unpadded $ assertBase64 @'UrlUnpadded "PDw_Pj4"
-- "<<?>>"
--
decodeBase64Padded :: Base64 'UrlPadded ByteString -> ByteString
decodeBase64Padded :: Base64 'UrlPadded ByteString -> ByteString
decodeBase64Padded = [StrictByteString] -> ByteString
fromChunks
  ([StrictByteString] -> ByteString)
-> (Base64 'UrlPadded ByteString -> [StrictByteString])
-> Base64 'UrlPadded ByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> [StrictByteString]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  (StrictByteString -> [StrictByteString])
-> (Base64 'UrlPadded ByteString -> StrictByteString)
-> Base64 'UrlPadded ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 'UrlPadded StrictByteString -> StrictByteString
B64U.decodeBase64Padded
  (Base64 'UrlPadded StrictByteString -> StrictByteString)
-> (Base64 'UrlPadded ByteString
    -> Base64 'UrlPadded StrictByteString)
-> Base64 'UrlPadded ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> StrictByteString)
-> Base64 'UrlPadded ByteString
-> Base64 'UrlPadded StrictByteString
forall a b. (a -> b) -> Base64 'UrlPadded a -> Base64 'UrlPadded b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> StrictByteString
BS.concat ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks)
{-# inline decodeBase64Padded #-}

-- | Decode a padded, untyped Base64url-encoded 'ByteString' value. Input strings are
-- required to be correctly padded, and will be validated prior to decoding
-- to confirm.
--
-- In general, unless padded Base64url is explicitly required, it is
-- safer to call 'decodeBase64'.
--
-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4>
--
-- === __Examples__:
--
-- >>> decodeBase64PaddedUntyped "PDw_Pj4="
-- Right "<<?>>"
--
-- >>> decodeBase64PaddedUntyped "PDw_Pj4"
-- Left "Base64-encoded bytestring requires padding"
--
decodeBase64PaddedUntyped :: ByteString -> Either T.Text ByteString
decodeBase64PaddedUntyped :: ByteString -> Either Text ByteString
decodeBase64PaddedUntyped = (StrictByteString -> ByteString)
-> Either Text StrictByteString -> Either Text ByteString
forall a b. (a -> b) -> Either Text a -> Either Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([StrictByteString] -> ByteString
fromChunks ([StrictByteString] -> ByteString)
-> (StrictByteString -> [StrictByteString])
-> StrictByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> [StrictByteString] -> [StrictByteString]
forall a. a -> [a] -> [a]
:[]))
  (Either Text StrictByteString -> Either Text ByteString)
-> (ByteString -> Either Text StrictByteString)
-> ByteString
-> Either Text ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Either Text StrictByteString
B64U.decodeBase64PaddedUntyped
  (StrictByteString -> Either Text StrictByteString)
-> (ByteString -> StrictByteString)
-> ByteString
-> Either Text StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [StrictByteString] -> StrictByteString
BS.concat
  ([StrictByteString] -> StrictByteString)
-> (ByteString -> [StrictByteString])
-> ByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks
{-# INLINE decodeBase64PaddedUntyped #-}

-- | Leniently decode an unpadded, untyped Base64url-encoded 'ByteString'. This function
-- will not generate parse errors. If input data contains padding chars,
-- then the input will be parsed up until the first pad character.
--
-- __Note:__ This is not RFC 4648-compliant.
--
-- === __Examples__:
--
-- >>> decodeBase64Lenient "PDw_Pj4="
-- "<<?>>"
--
-- >>> decodeBase64Lenient "PDw_%%%$}Pj4"
-- "<<?>>"
--
decodeBase64Lenient :: ByteString -> ByteString
decodeBase64Lenient :: ByteString -> ByteString
decodeBase64Lenient = [StrictByteString] -> ByteString
fromChunks
    ([StrictByteString] -> ByteString)
-> (ByteString -> [StrictByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> StrictByteString)
-> [StrictByteString] -> [StrictByteString]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StrictByteString -> StrictByteString
B64U.decodeBase64Lenient
    ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [StrictByteString] -> [StrictByteString]
reChunkN Int
4
    ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StrictByteString -> StrictByteString)
-> [StrictByteString] -> [StrictByteString]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Word8 -> Bool) -> StrictByteString -> StrictByteString
BS.filter (Word8 -> ByteString -> Bool
`BL.elem` ByteString
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="))
    ([StrictByteString] -> [StrictByteString])
-> (ByteString -> [StrictByteString])
-> ByteString
-> [StrictByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [StrictByteString]
toChunks
{-# INLINE decodeBase64Lenient #-}

-- | Parse a canonical, padded Base64url-encoded 'ByteString' value.
--
-- Checks the URL-safe alphabet, length, padding, and unused padding bits.
-- Returns the original encoded value wrapped in 'Base64', ready for
-- 'decodeBase64Padded' or 'decodeBase64'. Errors match the strict ByteString
-- 'Data.ByteString.Base64.URL.decodeBase64PaddedUntyped' decoder.
-- The input is neither decoded nor normalized in the returned value.
--
-- The entire input is validated before returning 'Right'; the original
-- chunk boundaries are preserved in the result.
--
-- === __Examples__:
--
-- >>> parseBase64Padded "PDw_Pj4="
-- Right "PDw_Pj4="
--
-- >>> fmap decodeBase64Padded (parseBase64Padded "PDw_Pj4=")
-- Right "<<?>>"
--
-- >>> parseBase64Padded "PDw_Pj4"
-- Left "Base64-encoded bytestring requires padding"
--
-- >>> parseBase64Padded "ZE=="
-- Left "non-canonical encoding detected at offset: 1"
--
-- @since 2.1
--
parseBase64Padded :: ByteString -> Either T.Text (Base64 'UrlPadded ByteString)
parseBase64Padded :: ByteString -> Either Text (Base64 'UrlPadded ByteString)
parseBase64Padded ByteString
bs = ByteString -> Base64 'UrlPadded ByteString
forall (k :: Alphabet) a. a -> Base64 k a
assertBase64 ByteString
bs Base64 'UrlPadded ByteString
-> Either Text (Base64 'UrlPadded StrictByteString)
-> Either Text (Base64 'UrlPadded ByteString)
forall a b. a -> Either Text b -> Either Text a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ StrictByteString
-> Either Text (Base64 'UrlPadded StrictByteString)
B64U.parseBase64Padded ([StrictByteString] -> StrictByteString
BS.concat ([StrictByteString] -> StrictByteString)
-> [StrictByteString] -> StrictByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> [StrictByteString]
toChunks ByteString
bs)
{-# INLINE parseBase64Padded #-}

-- | Parse a canonical, unpadded Base64url-encoded 'ByteString' value.
--
-- Checks the URL-safe alphabet, length, padding, and unused padding bits.
-- Returns the original encoded value wrapped in 'Base64', ready for
-- 'decodeBase64Unpadded' or 'decodeBase64'. Errors match the strict ByteString
-- 'Data.ByteString.Base64.URL.decodeBase64UnpaddedUntyped' decoder.
-- The input is neither decoded nor normalized in the returned value.
--
-- The entire input is validated before returning 'Right'; the original
-- chunk boundaries are preserved in the result.
--
-- === __Examples__:
--
-- >>> parseBase64Unpadded "PDw_Pj4"
-- Right "PDw_Pj4"
--
-- >>> fmap decodeBase64Unpadded (parseBase64Unpadded "PDw_Pj4")
-- Right "<<?>>"
--
-- >>> parseBase64Unpadded "PDw_Pj4="
-- Left "Base64-encoded bytestring has invalid padding"
--
-- >>> parseBase64Unpadded "ZE"
-- Left "non-canonical encoding detected at offset: 1"
--
-- @since 2.1
--
parseBase64Unpadded :: ByteString -> Either T.Text (Base64 'UrlUnpadded ByteString)
parseBase64Unpadded :: ByteString -> Either Text (Base64 'UrlUnpadded ByteString)
parseBase64Unpadded ByteString
bs = ByteString -> Base64 'UrlUnpadded ByteString
forall (k :: Alphabet) a. a -> Base64 k a
assertBase64 ByteString
bs Base64 'UrlUnpadded ByteString
-> Either Text (Base64 'UrlUnpadded StrictByteString)
-> Either Text (Base64 'UrlUnpadded ByteString)
forall a b. a -> Either Text b -> Either Text a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ StrictByteString
-> Either Text (Base64 'UrlUnpadded StrictByteString)
B64U.parseBase64Unpadded ([StrictByteString] -> StrictByteString
BS.concat ([StrictByteString] -> StrictByteString)
-> [StrictByteString] -> StrictByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> [StrictByteString]
toChunks ByteString
bs)
{-# INLINE parseBase64Unpadded #-}