...
 
Commits (2)
......@@ -6,6 +6,14 @@ http://smap.informatik.uni-kiel.de/
Installation directory: /var/www/smap
Install new version:
--------------------
- Login at lascombes and set SYSTEM to kics2 in Makefile
- > make deploy
- Login at smap.informatik.uni-kiel.de:
> sudo cp ~mh/public_html/smap/smap.cgi.bin /var/www/smap
Old installation:
-----------------
......
......@@ -66,6 +66,9 @@ deploy: checkdeploy
mkdir -p $(WEBSERVERDIR)/data # create private data dir
chmod 700 $(WEBSERVERDIR)/data
cp -p data/htaccess $(WEBSERVERDIR)/data/.htaccess # and make it private
mkdir -p $(WEBSERVERDIR)/sessiondata # create private data dir
chmod 700 $(WEBSERVERDIR)/sessiondata
cp -p data/htaccess $(WEBSERVERDIR)/sessiondata/.htaccess # and make it private
$(WEBSERVERDIR)/smap.cgi: src/*.curry src/*/*.curry
$(CPM) exec $(CURRY2CGI) --system="$(SYSTEM)" \
......
......@@ -26,13 +26,13 @@ import Controller.Static
import View.Admin
import System.SmapHtml
import HTML.Html5
import HTML.Session
import WUI
import System.Alerts
import System.Authorization
import System.AuthorizedOperations
import System.Controllers
import System.Session
import System.Url
--------------------------------------------------------------------------------
......@@ -89,7 +89,7 @@ langCreateForm =
--- The data stored for executing the "langCreate" WUI form.
langCreateStore :: Global (SessionStore (WuiStore (String,String,String)))
langCreateStore =
global emptySessionStore (Persistent (inDataDir "langCreateStore"))
global emptySessionStore (Persistent (inSessionDataDir "langCreateStore"))
------------------------------------------------------------------------------
-- Returns a controller that displays a WUI form to create a new system.
......@@ -122,7 +122,7 @@ sysCreateForm =
sysCreateStore ::
Global (SessionStore ([Language], WuiStore (String,String,Language)))
sysCreateStore =
global emptySessionStore (Persistent (inDataDir "sysCreateStore"))
global emptySessionStore (Persistent (inSessionDataDir "sysCreateStore"))
------------------------------------------------------------------------------
--- Shows a form to edit the given System entity.
......@@ -151,7 +151,7 @@ sysEditForm =
sysEditStore ::
Global (SessionStore ((System,Language,[Language]), WuiStore System))
sysEditStore =
global emptySessionStore (Persistent (inDataDir "sysEditStore"))
global emptySessionStore (Persistent (inSessionDataDir "sysEditStore"))
--- Persists modifications of a given System entity to the
--- database depending on the Boolean argument. If the Boolean argument
......
......@@ -14,6 +14,7 @@ module Controller.AuthN (
import Global
import Maybe ( isNothing )
import HTML.Session
import Mail ( sendMail )
import WUI
......@@ -26,7 +27,6 @@ import View.AuthN
import System.Controllers
import Controller.Static ( showLandingPage )
import View.Static
import System.Session
import System.Url
import Model.User
import Controller.Users
......@@ -96,7 +96,8 @@ signUpForm =
--- The data stored for executing the "signUp" WUI form.
signUpStore :: Global (SessionStore (WuiStore (String,String,String,String)))
signUpStore = global emptySessionStore (Persistent (inDataDir "signUpStore"))
signUpStore =
global emptySessionStore (Persistent (inSessionDataDir "signUpStore"))
--------------------------------------------------------------------------------
-- Signing in --
......@@ -127,7 +128,8 @@ signInForm =
--- The data stored for executing the "signIn" WUI form.
signInStore :: Global (SessionStore (Bool, WuiStore (String,String)))
signInStore = global emptySessionStore (Persistent (inDataDir "signInStore"))
signInStore =
global emptySessionStore (Persistent (inSessionDataDir "signInStore"))
-- Performs the sign in process and stores the authentication data in the
-- current session (see module `Authentication`). An error alert is displayed if
......@@ -183,7 +185,7 @@ forgotPasswordForm =
--- The data stored for executing the "forgotPassword" WUI form.
forgotPWStore :: Global (SessionStore (WuiStore String))
forgotPWStore =
global emptySessionStore (Persistent (inDataDir "forgotPWStore"))
global emptySessionStore (Persistent (inSessionDataDir "forgotPWStore"))
-- Takes an email address and sends a new password if the email address is
-- associated to an actual user account. Otherwise, an error alert is displayed.
......@@ -253,7 +255,7 @@ changePasswordForm =
--- The data stored for executing the "changePassword" WUI form.
changePWStore :: Global (SessionStore (User, WuiStore (String,String,String)))
changePWStore =
global emptySessionStore (Persistent (inDataDir "changePWStore"))
global emptySessionStore (Persistent (inSessionDataDir "changePWStore"))
doChangePasswdCtrl :: (String,String,String) -> User -> Controller
doChangePasswdCtrl (oldpass,newpass,newpass2) user = do
......
......@@ -23,6 +23,7 @@ import Sort
import Time
import HTML.Base ( HtmlFormDef, formDefWithID, formExp )
import HTML.Session
import Model.Comment
import Model.ExecEnv
......@@ -40,7 +41,6 @@ import System.Authorization
import System.AuthorizedOperations
import System.Controllers
import System.Models
import System.Session
import System.Url
import System.Views
......@@ -230,7 +230,8 @@ modifyProgramController (progKey,versNum) = getProgramByKey progKey >>=
--- The data stored for executing the "modifyProgram" form.
browserStore :: Global (SessionStore (Program,Int))
browserStore = global emptySessionStore (Persistent (inDataDir "browserStore"))
browserStore =
global emptySessionStore (Persistent (inSessionDataDir "browserStore"))
modifyProgramForm :: HtmlFormDef (Program,Int)
modifyProgramForm =
......
......@@ -16,6 +16,7 @@ import Global
import Maybe
import Time
import HTML.Base ( HtmlFormDef, formDefWithID, formExp, urlencoded2string )
import HTML.Session
import WUI
import Model.ExecEnv
......@@ -32,7 +33,6 @@ import System.Authorization
import System.AuthorizedOperations
import System.Controllers
import System.Execution
import System.Session
import System.Url
import System.SmapHtml
import System.Views
......@@ -159,7 +159,8 @@ type SmapIEData =
--- The data stored for executing the "smapIO" form.
smapIEStore :: Global (SessionStore SmapIEData)
smapIEStore = global emptySessionStore (Persistent (inDataDir "smapIEStore"))
smapIEStore =
global emptySessionStore (Persistent (inSessionDataDir "smapIEStore"))
smapIEForm :: HtmlFormDef SmapIEData
smapIEForm = formDefWithID "Controller.SmapIE.smapIEForm" readData formHTML
......@@ -209,7 +210,7 @@ pcCreateStore :: Global
(SessionStore ((ExecEnv,ExecResult,String,String),
WuiStore (String,String,Bool,Language,User,String,String)))
pcCreateStore =
global emptySessionStore (Persistent (inDataDir "pcCreateStore"))
global emptySessionStore (Persistent (inSessionDataDir "pcCreateStore"))
-- Returns a controller that displays a WUI form to create a new program if the
-- given code executes successfully with the choosen execution system.
......@@ -277,7 +278,7 @@ pvCreateStore ::
Global (SessionStore ((ExecEnv,ExecResult,String,String,Program),
WuiStore (Int,String,String,Program)))
pvCreateStore =
global emptySessionStore (Persistent (inDataDir "pvCreateStore"))
global emptySessionStore (Persistent (inSessionDataDir "pvCreateStore"))
-- Returns a controller that displays a WUI form to create a new version if the
-- given code executes successfully with the choosen execution system.
......
......@@ -4,7 +4,7 @@
--- alerts in views (alerts are comparable with Spicey's default page messages).
---
--- @author Lasse Kristopher Meyer (with changes by Michael Hanus)
--- @version July 2014
--- @version July 2020
--------------------------------------------------------------------------------
module System.Alerts (
......@@ -18,8 +18,8 @@ import Global
import HTML.Bootstrap3
import HTML.Html5
import HTML.Session
import System.Session
import System.SmapHtml
--------------------------------------------------------------------------------
......
......@@ -5,7 +5,7 @@
--- data in sessions.
---
--- @author Michael Hanus, Lasse Kristopher Meyer
--- @version February 2014
--- @version July 2020
--------------------------------------------------------------------------------
module System.Authentication (
......@@ -17,11 +17,10 @@ module System.Authentication (
import FilePath ( (</>) )
import Global
import HTML.Session
import Config.Smap ( smapDataDir )
import Model.User
import System.Crypto
import System.Session
--------------------------------------------------------------------------------
-- Authentication data storing --
......@@ -36,7 +35,7 @@ type AuthNData = (String,Bool)
-- Definition of the session state to store the authentication data.
sessionAuthNData :: Global (SessionStore AuthNData)
sessionAuthNData =
global emptySessionStore (Persistent (smapDataDir </> "sessionAuthData"))
global emptySessionStore (Persistent (inSessionDataDir "sessionAuthData"))
--- Gets the current authentication data from the session store.
getSessionAuthNData :: IO (Maybe AuthNData)
......
......@@ -5,7 +5,7 @@
--- also exports the general type synonym for controllers.
---
--- @author Lasse Kristopher Meyer
--- @version November 2018
--- @version July 2020
--------------------------------------------------------------------------------
module System.Controllers (
......@@ -20,10 +20,11 @@ module System.Controllers (
import KeyDatabase
import Prelude hiding (div)
import HTML.Session
import System.Alerts
import System.Authentication
import Model.ExecEnv
import System.Session
import System.SmapHtml
import System.Url
......
--------------------------------------------------------------------------
--- This module implements the management of sessions.
--- In particular, it defines a cookie that must be sent to the client
--- in order to enable the handling of sessions.
--- Based on sessions, this module also defines a session store
--- that can be used by various parts of the application in order
--- to hold some session-specific data.
--------------------------------------------------------------------------
module System.Session
( inDataDir
, sessionCookie, doesSessionExist, withSessionCookie, withSessionCookieInfo
, SessionStore, emptySessionStore
, getSessionMaybeData, getSessionData, putSessionData, removeSessionData
, updateSessionData
) where
import FilePath ( (</>) )
import Global
import List ( findIndex, replace )
import Maybe ( fromMaybe )
import Time ( ClockTime, addMinutes, clockTimeToInt, getClockTime )
import Config.Smap ( smapDataDir )
import HTML.Html5
import Crypto.Hash ( randomString )
--- Prefix a file name with the directory where session data,
--- e.g., cookie information, is stored during run time.
--- As a default, it is the CGI execution directory but this should
--- be adapted to a non-public readable directory for security reasons.
inDataDir :: String -> String
inDataDir filename = smapDataDir </> filename
--- The life span in minutes to store data in sessions.
--- Thus, older data is deleted by a clean up that is initiated
--- whenever new data is stored in a session.
sessionLifespan :: Int
sessionLifespan = 60
--- The name of the persistent global where the last session id is stored.
sessionCookieName :: String
sessionCookieName = "spiceySessionId"
--- This global value saves time and last session id.
lastId :: Global (Int, Int)
lastId = global (0, 0) (Persistent (inDataDir sessionCookieName))
--- The abstract type to represent session identifiers.
data SessionId = SessionId String
deriving Eq
getId :: SessionId -> String
getId (SessionId i) = i
--- Creates a new unused session id.
getUnusedId :: IO SessionId
getUnusedId = do
(ltime,lsid) <- safeReadGlobal lastId (0,0)
clockTime <- getClockTime
if clockTimeToInt clockTime /= ltime
then writeGlobal lastId (clockTimeToInt clockTime, 0)
else writeGlobal lastId (clockTimeToInt clockTime, lsid+1)
rans <- randomString 30
return (SessionId (show (clockTimeToInt clockTime) ++ show (lsid+1) ++ rans))
--- Checks whether the current user session is initialized,
--- i.e., whether a session cookie has been already set.
doesSessionExist :: IO Bool
doesSessionExist = do
cookies <- getCookies
return $ maybe False (const True) (lookup sessionCookieName cookies)
--- Gets the id of the current user session.
--- If this is a new session, a new id is created and returned.
getSessionId :: IO SessionId
getSessionId = do
cookies <- getCookies
case (lookup sessionCookieName cookies) of
Just sessionCookieValue -> return (SessionId sessionCookieValue)
Nothing -> getUnusedId
--- Creates a cookie to hold the current session id.
--- This cookie should be sent to the client together with every HTML page.
sessionCookie :: IO PageParam
sessionCookie = do
sessionId <- getSessionId
clockTime <- getClockTime
return $ PageCookie sessionCookieName (getId (sessionId))
[CookiePath "/",
CookieExpire (addMinutes sessionLifespan clockTime)]
--- Decorates an HTML page with session cookie.
withSessionCookie :: HtmlPage -> IO HtmlPage
withSessionCookie p = do
cookie <- sessionCookie
return $ (p `addPageParam` cookie)
--- Decorates an HTML page with session cookie and shows an information
--- page when the session cookie is not set.
withSessionCookieInfo :: HtmlPage -> IO HtmlPage
withSessionCookieInfo p = do
hassession <- doesSessionExist
if hassession then withSessionCookie p
else cookieInfoPage
-- Returns HTML page with information about the use of cookies.
cookieInfoPage :: IO HtmlPage
cookieInfoPage = do
urlparam <- getUrlParameter
withSessionCookie $ standardPage "Cookie Info"
[ par [ htxt $ "This web site uses cookies for navigation and user " ++
"inputs and preferences. In order to proceed, "
, bold [a [href ('?' : urlparam)] [text "please click here."]]]]
----------------------------------------------------------------------------
-- Implementation of session stores.
--- The type of a session store that holds particular data used in a session.
--- A session store consists of a list of data items for each session in the
--- system together with the clock time of the last access.
--- The clock time is used to remove old data in the store.
data SessionStore a = SessionStore [(SessionId, Int, a)]
--- An initial value for the empty session store.
emptySessionStore :: SessionStore _
emptySessionStore = SessionStore []
--- Retrieves data for the current user session stored in a session store.
--- Returns `Nothing` if there is no data for the current session.
getSessionMaybeData :: Global (SessionStore a) -> IO (Maybe a)
getSessionMaybeData sessionData = do
sid <- getSessionId
SessionStore sdata <- safeReadGlobal sessionData emptySessionStore
return (findInSession sid sdata)
where
findInSession si ((id, _, storedData):rest) =
if getId id == getId si
then Just storedData
else findInSession si rest
findInSession _ [] = Nothing
--- Retrieves data for the current user session stored in a session store
--- where the second argument is returned if there is no data
--- for the current session.
getSessionData :: Global (SessionStore a) -> a -> IO a
getSessionData sessionData defaultdata =
getSessionMaybeData sessionData >>= return . fromMaybe defaultdata
--- Stores data related to the current user session in a session store.
putSessionData :: Global (SessionStore a) -> a -> IO ()
putSessionData sessionData newData = do
sid <- getSessionId
SessionStore sdata <- safeReadGlobal sessionData emptySessionStore
currentTime <- getClockTime
case findIndex (\ (id, _, _) -> id == sid) sdata of
Just i ->
writeGlobal sessionData
(SessionStore (replace (sid, clockTimeToInt currentTime, newData) i
(cleanup currentTime sdata)))
Nothing ->
writeGlobal sessionData
(SessionStore ((sid, clockTimeToInt currentTime, newData)
: cleanup currentTime sdata))
--- Updates the data of the current user session.
updateSessionData :: Global (SessionStore a) -> a -> (a -> a) -> IO ()
updateSessionData sessiondata defaultdata upd = do
sd <- getSessionData sessiondata defaultdata
putSessionData sessiondata (upd sd)
--- Removes data related to the current user session from a session store.
removeSessionData :: Global (SessionStore a) -> IO ()
removeSessionData sessionData = do
sid <- getSessionId
SessionStore sdata <- safeReadGlobal sessionData emptySessionStore
currentTime <- getClockTime
writeGlobal sessionData
(SessionStore (filter (\ (id, _, _) -> id /= sid)
(cleanup currentTime sdata)))
-- expects that clockTimeToInt converts time into ascending integers!
-- we should write our own conversion-function
cleanup :: ClockTime -> [(SessionId, Int, a)] -> [(SessionId, Int, a)]
cleanup currentTime sessionData =
filter (\ (_, time, _) ->
time > clockTimeToInt (addMinutes (0-sessionLifespan) currentTime))
sessionData
--------------------------------------------------------------------------------
......@@ -7,7 +7,7 @@
--- [this web page](http://www.informatik.uni-kiel.de/~pakcs/WUI).
---
--- @author Michael Hanus
--- @version October 2019
--- @version July 2020
------------------------------------------------------------------------------
{-# OPTIONS_CYMAKE -Wno-incomplete-patterns #-}
......@@ -48,7 +48,7 @@ import Read(readNat)
import ReadShowTerm
import HTML.Base
import System.Session
import HTML.Session
infixl 0 `withRendering`
infixl 0 `withErrorRendering`
......