! Copyright (c) 2008 Slava Pestov\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: accessors assocs namespaces kernel sequences sets\r
-destructors combinators\r
+destructors combinators fry\r
io.encodings.utf8 io.encodings.string io.binary random\r
checksums checksums.sha2\r
html.forms\r
http.server.dispatchers\r
furnace\r
furnace.actions\r
+furnace.redirection\r
furnace.boilerplate\r
furnace.auth.providers\r
furnace.auth.providers.db ;\r
\r
: define-capability ( word -- ) capabilities get adjoin ;\r
\r
-TUPLE: realm < dispatcher name users checksum ;\r
+TUPLE: realm < dispatcher name users checksum secure ;\r
\r
GENERIC: login-required* ( realm -- response )\r
\r
swap >>name\r
swap >>default\r
users-in-db >>users\r
- sha-256 >>checksum ; inline\r
+ sha-256 >>checksum\r
+ t >>secure ; inline\r
\r
: users ( -- provider )\r
realm get users>> ;\r
: check-login ( password username -- user/f )\r
users get-user dup [ [ valid-login? ] keep and ] [ 2drop f ] if ;\r
\r
+: if-secure-realm ( quot -- )\r
+ realm get secure>> [ if-secure ] [ call ] if ; inline\r
+\r
+TUPLE: secure-realm-only < filter-responder ;\r
+\r
+C: <secure-realm-only> secure-realm-only\r
+\r
+M: secure-realm-only call-responder*\r
+ '[ , , call-next-method ] if-secure-realm ;\r
+\r
TUPLE: protected < filter-responder description capabilities ;\r
\r
: <protected> ( responder -- protected )\r
} cond ;\r
\r
M: protected call-responder* ( path responder -- response )\r
- dup protected set\r
- dup logged-in-user get check-capabilities\r
- [ call-next-method ] [ 2drop realm get login-required* ] if ;\r
+ '[\r
+ , ,\r
+ dup protected set\r
+ dup logged-in-user get check-capabilities\r
+ [ call-next-method ] [ 2drop realm get login-required* ] if\r
+ ] if-secure-realm ;\r
\r
: <auth-boilerplate> ( responder -- responder' )\r
<boilerplate> { realm "boilerplate" } >>template ;\r
: <permit-cookie> ( -- cookie )\r
permit-id get realm get name>> permit-id-key <cookie>\r
"$login-realm" resolve-base-path >>path\r
- realm get timeout>> from-now >>expires\r
- realm get domain>> >>domain ;\r
+ realm get\r
+ [ timeout>> from-now >>expires ]\r
+ [ domain>> >>domain ]\r
+ [ secure>> >>secure ]\r
+ tri ;\r
\r
: put-permit-cookie ( response -- response' )\r
<permit-cookie> put-cookie ;\r
"password" value\r
"username" value check-login\r
[ successful-login ] [ login-failed ] if*\r
- ] >>submit ;\r
+ ] >>submit\r
+ <auth-boilerplate>\r
+ <secure-realm-only> ;\r
\r
: <logout-action> ( -- action )\r
<action>\r
\r
: <login-realm> ( responder name -- auth )\r
login-realm new-realm\r
- <login-action> <auth-boilerplate> "login" add-responder\r
+ <login-action> "login" add-responder\r
<logout-action> "logout" add-responder\r
20 minutes >>timeout ;\r
! Copyright (c) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel namespaces
+USING: accessors kernel math.order namespaces combinators.lib
html.forms
html.templates
html.templates.chloe
swap >>responder
[ ] >>init ;
+: wrap-boilerplate? ( response -- ? )
+ {
+ [ code>> { [ 200 = ] [ 400 499 between? ] } 1|| ]
+ [ content-type>> "text/html" = ]
+ } 1&& ;
+
M:: boilerplate call-responder* ( path responder -- )
begin-form
path responder call-next-method
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors combinators namespaces
+USING: kernel accessors combinators namespaces fry
io.servers.connection
-http http.server http.server.redirection
+http http.server http.server.redirection http.server.filters
furnace ;
IN: furnace.redirection
redirect-responder boa ;
M: redirect-responder call-responder* nip to>> <redirect> ;
+
+TUPLE: secure-only < filter-responder ;
+
+C: <secure-only> secure-only
+
+: if-secure ( quot -- )
+ >r request get url>> protocol>> "http" =
+ [ request get url>> <secure-redirect> ]
+ r> if ; inline
+
+M: secure-only call-responder*
+ '[ , , call-next-method ] if-secure ;