{-# LANGUAGE
- UnicodeSyntax
+ OverloadedStrings
+ , UnicodeSyntax
#-}
{-# OPTIONS_HADDOCK prune #-}
, UserID
, Password
+ , printAuthChallenge
, authCredentialP -- private
)
where
import Data.Ascii (Ascii)
import qualified Data.Ascii as A
+import Data.Attoparsec.Char8
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as C8
+import Data.Maybe
+import Data.Monoid.Unicode
import Network.HTTP.Lucu.Parser.Http
import Network.HTTP.Lucu.Utils
import Prelude.Unicode
-- letters.
type Password = Ascii
--- FIXME: Don't use String for network output.
-instance Show AuthChallenge where
- show (BasicAuthChallenge realm)
- = "Basic realm=" ⧺ quoteStr realm
+-- |Convert an 'AuthChallenge' to 'Ascii'.
+printAuthChallenge ∷ AuthChallenge → Ascii
+printAuthChallenge (BasicAuthChallenge realm)
+ = A.fromAsciiBuilder $
+ A.toAsciiBuilder "Basic realm=" ⊕ quoteStr realm
authCredentialP ∷ Parser AuthCredential
authCredentialP
- = allowEOF $!
- do _ ← string "Basic"
- _ ← many1 lws
- b64 ← many1
- $ satisfy (\c → (c ≥ 'a' ∧ c ≤ 'z') ∨
- (c ≥ 'A' ∧ c ≤ 'Z') ∨
- (c ≥ '0' ∧ c ≤ '9') ∨
- c ≡ '+' ∨
- c ≡ '/' ∨
- c ≡ '=')
- case break (≡ ':') (decode b64) of
- (uid, ':' : password)
- → return (BasicAuthCredential uid password)
- _ → failP
+ = try $
+ do _ ← string "Basic"
+ skipMany1 lws
+ b64 ← takeWhile1 base64
+ case C8.break (≡ ':') (B64.decodeLenient b64) of
+ (user, cPassword)
+ | C8.null cPassword
+ → fail "no colons in the basic auth credential"
+ | otherwise
+ → let u = fromJust $ A.fromByteString user
+ p = fromJust $ A.fromByteString (C8.tail cPassword)
+ in
+ return (BasicAuthCredential u p)
where
- decode ∷ String → String
- decode = C8.unpack ∘ B64.decodeLenient ∘ C8.pack
+ base64 ∷ Char → Bool
+ base64 = inClass "a-zA-Z0-9+/="