1:-module(login_box, [login_box//1]).    2
    3:- use_module(library(http/http_parameters)).    4:- use_module(library(http/http_client)).    5:- use_module(library(http/html_write)).    6:- use_module(library(http/http_session)).    7:- use_module(library(http/http_dispatch)).

Login Box Weblog Pattern

This module implements predicates related to the login pattern. Closely related to user_database, register_box, logout_box.

See also
- http://www.welie.com/patterns/showPattern.php?patternID=login
To be done
- https support
- openid support (check openid swipl library) */
 login_box(+Options) is det
A DCG producing a login box and implementing the basic functionality. Options is a list of options that modify the default behavior. The provided options are:
after_login(+Atom)
logout_box: Displays a logout_box instead of a login_box when a user is logged in. Default. logout_box(+Logout_Options): As logout_box but the logout_box is modified based on Logout_Options destroy: Nothing will be displayed when a user is logged in
register(+RegisterPage)
Give the option to register by redirecting the user to the register page. Deactivated by default
db_handler(+Database_Handler)
Provide a database of users (as described in the user_database module). If not given, login_box will assume an empty database
return(+SuccessPage, +FailPage)
After a succesful/failed login the user will be redirected to SuccessPage/FailPage If the atom 'referer' is given, login_box will attempt to return the user to the previous page using the HTTP_REFERER information (default behavior)
referer_check(+Check_Options)
A check to perform on the URL retrieved by HTTP_REFERER info before redirecting to it.

+Check_Option has the form of {+Atom, +Mode} Atom can be 'success', 'fail' or 'all' Mode can be: 'false': no check will be performed 'empty': if the HTTP_REFERER field is empty the user is redirected to the root empty(+ReturnPage): as 'empty' but the user is redirected to ReturnPage 'valid': the URL should appear to be a valid URL otherwise the user is redirected to the root (default) valid(+ReturnPage): as 'valid' but the user is redirected to ReturnPage predicate(:Check): a predicate to be called given the URL as an argument. If it fails, the user is redirected to the root predicate(:Check, +ReturnPage): as predicate(:Check) but the user is redirected to ReturnPage

   57login_box(_Options) --> 
   58	{http_set_session_options([create(noauto)]),
   59     http_handler('/user_login', login_request,[])},
   60	html([
   61	 form([action='/user_login',method='POST'],
   62	      [
   63	       p([], [
   64		      label([for=name],'Username:'),
   65		      input([name=name, type=textarea])
   66		     ]),
   67	       p([], [
   68		      label([for=pass],'Password:'),
   69		      input([name=pass, type=password])
   70		     ]),
   71	       p([], input([name=submit, type=submit, value='Submit'], []))
   72	      ])]).
   73
   74login_request(Request) :-
   75    member(referer(Referer),Request),
   76	http_read_data(Request, [name=Name,pass=Password|_], []),
   77	check_login(Name, Password, Details) ->
   78    succesful_login(Name, Referer, Request)
   79    ; failed_login(Details, Referer, Request).
   80
   81succesful_login(Name, Return, Request) :-
   82	http_open_session(_SessionID, _),
   83	http_session_assert(user(Name)),
   84    http_redirect(see_other, Return, Request).
   85/*
   86	phrase(
   87	       html(html(
   88			 [head(title('Yay')),
   89			  body([p(['Welcome ', Name, ' ', Return])])])),
   90		    	    TokenizedHtml,
   91	    []),
   92        format('Content-type: text/html~n~n'),
   93	print_html(TokenizedHtml).
   94  */
   95
   96failed_login(_Details, _Return, _Request) :-
   97	phrase(
   98	       html(html(
   99			 [head(title(':(')),
  100			  body([p('The username or password you entered is incorrect.')])])),
  101	       TokenizedHtml,
  102	       []),
  103        format('Content-type: text/html~n~n'),
  104	print_html(TokenizedHtml).
  105
  106check_login(Name, Password, true) :-
  107	% delay in each attempted login to reduce brute-force attack efficiency
  108	sleep(1),
  109	% retrieving account details (user table key = username)
  110	user_db(Name, UserPassword, Salt),
  111	% first hash
  112	sha_hash(Password, Hash1, [algorithm(sha512)]),
  113	hash_atom(Hash1, HashAtom1),
  114	% second hash with salt
  115	atom_concat(HashAtom1, Salt, Salted),
  116	sha_hash(Salted, Hash, [algorithm(sha512)]),
  117	hash_atom(Hash, UserPassword).
  118
  119user_db(thanosqr, '766286d68e742b693e7d712a434cab5b9775cb11bde8a7285a09642a220d269029c75df7d624c76bc76a972afce92e7427876cee650273ad9a02a04ff0d061a0', random).
  120user_db(annie, '94db72db39580e0559ad6224358e58791b4eeb2511750e759c8b1f24de79a52b2e8abda02ac43097587bee3a5b63f42f41beb236dad4193e7bb40f45259aa04a', iswear).
  121
  122% we never store the passwords in plaintext
  123% 42 42
  124% oops