dev:web: refactor permission checking

This commit is contained in:
Simon Michael 2023-10-25 12:51:08 +01:00
parent 24ce9b5be1
commit 2ba321885d
8 changed files with 45 additions and 36 deletions

View File

@ -16,7 +16,7 @@
module Hledger.Web.Foundation where module Hledger.Web.Foundation where
import Control.Applicative ((<|>)) import Control.Applicative ((<|>))
import Control.Monad (join, when) import Control.Monad (join, when, unless)
-- import Control.Monad.Except (runExceptT) -- now re-exported by Hledger -- import Control.Monad.Except (runExceptT) -- now re-exported by Hledger
import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Char8 as BC
import Data.Traversable (for) import Data.Traversable (for)
@ -283,3 +283,11 @@ getCurrentJournal jref opts d = do
liftIO . writeIORef jref $ filterJournalTransactions depthlessinitialq j' liftIO . writeIORef jref $ filterJournalTransactions depthlessinitialq j'
return (j',Nothing) return (j',Nothing)
Right (_, False) -> return (j, Nothing) Right (_, False) -> return (j, Nothing)
-- | In a request handler, check for the given permission
-- and fail with a message if it's not present.
require :: Permission -> Handler ()
require p = do
VD{perms} <- getViewData
unless (p `elem` perms) $ permissionDenied $
"Missing the '" <> T.pack (showPermission p) <> "' permission"

View File

@ -30,8 +30,8 @@ getAddR = do
postAddR :: Handler () postAddR :: Handler ()
postAddR = do postAddR = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD{perms, j, today} <- getViewData VD{j, today} <- getViewData
when (AddPermission `notElem` perms) (permissionDenied "Missing the 'add' permission") require AddPermission
((res, view), enctype) <- runFormPost $ addForm j today ((res, view), enctype) <- runFormPost $ addForm j today
case res of case res of
@ -59,8 +59,8 @@ postAddR = do
-- The web form handler above should probably use PUT as well. -- The web form handler above should probably use PUT as well.
putAddR :: Handler RepJson putAddR :: Handler RepJson
putAddR = do putAddR = do
VD{perms, j, opts} <- getViewData VD{j, opts} <- getViewData
when (AddPermission `notElem` perms) (permissionDenied "Missing the 'add' permission") require AddPermission
(r :: Result Transaction) <- parseCheckJsonBody (r :: Result Transaction) <- parseCheckJsonBody
case r of case r of

View File

@ -31,8 +31,8 @@ getEditR f = do
postEditR :: FilePath -> Handler () postEditR :: FilePath -> Handler ()
postEditR f = do postEditR f = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD {perms, j} <- getViewData VD {j} <- getViewData
when (EditPermission `notElem` perms) (permissionDenied "Missing the 'edit' permission") require EditPermission
(f', txt) <- journalFile404 f j (f', txt) <- journalFile404 f j
((res, view), enctype) <- runFormPost (editForm f' txt) ((res, view), enctype) <- runFormPost (editForm f' txt)

View File

@ -21,7 +21,7 @@ getJournalR :: Handler Html
getJournalR = do getJournalR = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD{perms, j, q, opts, qparam, qopts, today} <- getViewData VD{perms, j, q, opts, qparam, qopts, today} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
let title = case inAccount qopts of let title = case inAccount qopts of
Nothing -> "General Journal" Nothing -> "General Journal"
Just (a, inclsubs) -> "Transactions in " <> a <> if inclsubs then "" else " (excluding subaccounts)" Just (a, inclsubs) -> "Transactions in " <> a <> if inclsubs then "" else " (excluding subaccounts)"

View File

@ -38,8 +38,8 @@ getRootR = do
getManageR :: Handler Html getManageR :: Handler Html
getManageR = do getManageR = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD{perms, j} <- getViewData VD{j} <- getViewData
when (EditPermission `notElem` perms) (permissionDenied "Missing the 'edit' permission") require EditPermission
defaultLayout $ do defaultLayout $ do
setTitle "Edit journal" setTitle "Edit journal"
$(widgetFile "manage") $(widgetFile "manage")
@ -47,8 +47,8 @@ getManageR = do
getDownloadR :: FilePath -> Handler TypedContent getDownloadR :: FilePath -> Handler TypedContent
getDownloadR f = do getDownloadR f = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD{perms, j} <- getViewData VD{j} <- getViewData
when (EditPermission `notElem` perms) (permissionDenied "Missing the 'edit' permission") require EditPermission
(f', txt) <- journalFile404 f j (f', txt) <- journalFile404 f j
addHeader "Content-Disposition" ("attachment; filename=\"" <> T.pack f' <> "\"") addHeader "Content-Disposition" ("attachment; filename=\"" <> T.pack f' <> "\"")
sendResponse ("text/plain" :: ByteString, toContent txt) sendResponse ("text/plain" :: ByteString, toContent txt)
@ -57,50 +57,46 @@ getDownloadR f = do
getVersionR :: Handler TypedContent getVersionR :: Handler TypedContent
getVersionR = do getVersionR = do
VD{perms} <- getViewData require ViewPermission
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") selectRep $ provideJson $ packageversion
selectRep $ do
provideJson $ packageversion
getAccountnamesR :: Handler TypedContent getAccountnamesR :: Handler TypedContent
getAccountnamesR = do getAccountnamesR = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
selectRep $ do selectRep $ provideJson $ journalAccountNames j
provideJson $ journalAccountNames j
getTransactionsR :: Handler TypedContent getTransactionsR :: Handler TypedContent
getTransactionsR = do getTransactionsR = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
selectRep $ do selectRep $ provideJson $ jtxns j
provideJson $ jtxns j
getPricesR :: Handler TypedContent getPricesR :: Handler TypedContent
getPricesR = do getPricesR = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
selectRep $ do selectRep $
provideJson $ map priceDirectiveToMarketPrice $ jpricedirectives j provideJson $ map priceDirectiveToMarketPrice $ jpricedirectives j
getCommoditiesR :: Handler TypedContent getCommoditiesR :: Handler TypedContent
getCommoditiesR = do getCommoditiesR = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
selectRep $ do selectRep $ do
provideJson $ (M.keys . jinferredcommodities) j provideJson $ (M.keys . jinferredcommodities) j
getAccountsR :: Handler TypedContent getAccountsR :: Handler TypedContent
getAccountsR = do getAccountsR = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
selectRep $ do selectRep $ do
provideJson $ flattenAccounts $ mapAccounts (accountSetDeclarationInfo j) $ ledgerRootAccount $ ledgerFromJournal Any j provideJson $ flattenAccounts $ mapAccounts (accountSetDeclarationInfo j) $ ledgerRootAccount $ ledgerFromJournal Any j
getAccounttransactionsR :: Text -> Handler TypedContent getAccounttransactionsR :: Text -> Handler TypedContent
getAccounttransactionsR a = do getAccounttransactionsR a = do
VD{perms, j} <- getViewData VD{j} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
let let
rspec = defreportspec rspec = defreportspec
thisacctq = Acct $ accountNameToAccountRegex a -- includes subs thisacctq = Acct $ accountNameToAccountRegex a -- includes subs

View File

@ -27,7 +27,7 @@ getRegisterR :: Handler Html
getRegisterR = do getRegisterR = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD{perms, j, q, opts, qparam, qopts, today} <- getViewData VD{perms, j, q, opts, qparam, qopts, today} <- getViewData
when (ViewPermission `notElem` perms) (permissionDenied "Missing the 'view' permission") require ViewPermission
let (a,inclsubs) = fromMaybe ("all accounts",True) $ inAccount qopts let (a,inclsubs) = fromMaybe ("all accounts",True) $ inAccount qopts
s1 = if inclsubs then "" else " (excluding subaccounts)" s1 = if inclsubs then "" else " (excluding subaccounts)"

View File

@ -35,8 +35,8 @@ getUploadR f = do
postUploadR :: FilePath -> Handler () postUploadR :: FilePath -> Handler ()
postUploadR f = do postUploadR f = do
checkServerSideUiEnabled checkServerSideUiEnabled
VD {perms, j} <- getViewData VD {j} <- getViewData
when (EditPermission `notElem` perms) (permissionDenied "Missing the 'edit' permission") require EditPermission
(f', _) <- journalFile404 f j (f', _) <- journalFile404 f j
((res, view), enctype) <- runFormPost (uploadForm f') ((res, view), enctype) <- runFormPost (uploadForm f')

View File

@ -17,6 +17,7 @@ import Safe (lastMay)
import Hledger.Cli hiding (packageversion, progname, prognameandversion) import Hledger.Cli hiding (packageversion, progname, prognameandversion)
import Hledger.Web.Settings (defhost, defport, defbaseurl) import Hledger.Web.Settings (defhost, defport, defbaseurl)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Char (toLower)
-- cf Hledger.Cli.Version -- cf Hledger.Cli.Version
@ -193,6 +194,10 @@ parsePermission "add" = Right AddPermission
parsePermission "edit" = Right EditPermission parsePermission "edit" = Right EditPermission
parsePermission x = Left $ T.pack $ BC.unpack x parsePermission x = Left $ T.pack $ BC.unpack x
-- | Convert to the lower case permission name.
showPermission :: Permission -> String
showPermission p = map toLower $ reverse $ drop 10 $ reverse $ show p
-- | For the --allow option: how much access to allow to hledger-web users ? -- | For the --allow option: how much access to allow to hledger-web users ?
data AccessLevel = data AccessLevel =
ViewAccess -- ^ view permission only ViewAccess -- ^ view permission only