/
BasicAuth.purs
95 lines (89 loc) · 2.97 KB
/
BasicAuth.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module Hyper.Node.BasicAuth where
import Data.StrMap as StrMap
import Node.Buffer as Buffer
import Control.IxMonad (ibind, ipure)
import Control.Monad (class Monad, (>>=))
import Control.Monad.Eff.Class (liftEff, class MonadEff)
import Data.Functor ((<$>))
import Data.Maybe (Maybe(Nothing, Just))
import Data.Monoid ((<>))
import Data.String (Pattern(Pattern), split)
import Data.Tuple (Tuple(Tuple))
import Data.Unit (Unit)
import Hyper.Authentication (setAuthentication)
import Hyper.Conn (Conn)
import Hyper.Middleware (Middleware, lift')
import Hyper.Middleware.Class (getConn, modifyConn)
import Hyper.Request (class Request, getRequestData)
import Hyper.Response (class ResponseWritable, respond, class Response, ResponseEnded, StatusLineOpen, closeHeaders, writeHeader, writeStatus)
import Hyper.Status (statusUnauthorized)
import Node.Buffer (BUFFER)
import Node.Encoding (Encoding(ASCII, Base64))
type Realm = String
decodeBase64 ∷ ∀ m e c
. MonadEff (buffer ∷ BUFFER | e) m
=> String
→ Middleware m c c String
decodeBase64 encoded =
liftEff (Buffer.fromString encoded Base64 >>= Buffer.toString ASCII)
withAuthentication
:: forall m e req res c t
. MonadEff (buffer :: BUFFER | e) m
=> Request req m
=> (Tuple String String -> m (Maybe t))
-> Middleware
m
(Conn req res { authentication :: Unit | c })
(Conn req res { authentication :: Maybe t | c })
Unit
withAuthentication mapper = do
auth <- getAuth
modifyConn (setAuthentication auth)
where
splitPair s =
case split (Pattern ":") s of
[username, password] -> Just (Tuple username password)
_ -> Nothing
getAuth = do
{ headers } <- getRequestData
case StrMap.lookup "authorization" headers of
Nothing -> ipure Nothing
Just header -> do
case split (Pattern " ") header of
["Basic", encoded] -> do
decoded <- splitPair <$> decodeBase64 encoded
case decoded of
Just auth -> lift' (mapper auth)
Nothing -> ipure Nothing
parts -> ipure Nothing
bind = ibind
authenticated
:: forall m req res c b t
. Monad m
=> ResponseWritable b m String
=> Response res m b
=> Realm
-> Middleware
m
(Conn req (res StatusLineOpen) { authentication :: t | c })
(Conn req (res ResponseEnded) { authentication :: t | c })
Unit
-> Middleware
m
(Conn req (res StatusLineOpen) { authentication :: Maybe t | c })
(Conn req (res ResponseEnded) { authentication :: Maybe t | c })
Unit
authenticated realm mw = do
conn ← getConn
case conn.components.authentication of
Nothing -> do
_ <- writeStatus statusUnauthorized
_ <- writeHeader (Tuple "WWW-Authenticate" ("Basic realm=\"" <> realm <> "\""))
_ <- closeHeaders
respond "Please authenticate."
Just auth -> do
_ <- modifyConn (setAuthentication auth)
_ <- mw
modifyConn (setAuthentication (Just auth))
where
bind = ibind