Secure API, part 2: Access control on NodeAPI

parent 09de17bd
...@@ -60,7 +60,7 @@ import Gargantext.Database.Facet (FacetDoc, OrderBy(..)) ...@@ -60,7 +60,7 @@ import Gargantext.Database.Facet (FacetDoc, OrderBy(..))
import Gargantext.Database.Node.Children (getChildren) import Gargantext.Database.Node.Children (getChildren)
import Gargantext.Database.Schema.Node ( getNodesWithParentId, getNode, getNode', deleteNode, deleteNodes, mkNodeWithParent, JSONB, HasNodeError(..)) import Gargantext.Database.Schema.Node ( getNodesWithParentId, getNode, getNode', deleteNode, deleteNodes, mkNodeWithParent, JSONB, HasNodeError(..))
import Gargantext.Database.Schema.NodeNode (nodeNodesCategory) import Gargantext.Database.Schema.NodeNode (nodeNodesCategory)
import Gargantext.Database.Tree (treeDB) import Gargantext.Database.Tree (treeDB, isDescendantOf)
import Gargantext.Database.Types.Node import Gargantext.Database.Types.Node
import Gargantext.Database.Utils -- (Cmd, CmdM) import Gargantext.Database.Utils -- (Cmd, CmdM)
import Gargantext.Prelude import Gargantext.Prelude
...@@ -158,11 +158,20 @@ type ChildrenApi a = Summary " Summary children" ...@@ -158,11 +158,20 @@ type ChildrenApi a = Summary " Summary children"
:> QueryParam "offset" Int :> QueryParam "offset" Int
:> QueryParam "limit" Int :> QueryParam "limit" Int
:> Get '[JSON] [Node a] :> Get '[JSON] [Node a]
withAccess :: (CmdM env err m, HasServerError err) => UserId -> NodeId -> m a -> m a
withAccess uId id m = do
d <- id `isDescendantOf` NodeId uId
printDebug "withAccess" (uId, id, d)
if d then m else serverError err401
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- TODO: make the NodeId type indexed by `a`, then we no longer need the proxy. -- TODO: make the NodeId type indexed by `a`, then we no longer need the proxy.
nodeAPI :: JSONB a => proxy a -> UserId -> NodeId -> GargServer (NodeAPI a) nodeAPI :: forall proxy a. (JSONB a, ToJSON a) => proxy a -> UserId -> NodeId -> GargServer (NodeAPI a)
nodeAPI p uId id nodeAPI p uId id = hoistServer (Proxy :: Proxy (NodeAPI a)) (withAccess uId id) nodeAPI'
= getNode id p where
nodeAPI' :: GargServer (NodeAPI a)
nodeAPI' = getNode id p
:<|> rename id :<|> rename id
:<|> postNode uId id :<|> postNode uId id
:<|> putNode id :<|> putNode id
...@@ -174,18 +183,18 @@ nodeAPI p uId id ...@@ -174,18 +183,18 @@ nodeAPI p uId id
:<|> apiNgramsTableCorpus id :<|> apiNgramsTableCorpus id
:<|> getPairing id :<|> getPairing id
-- :<|> getTableNgramsDoc id -- :<|> getTableNgramsDoc id
:<|> catApi id :<|> catApi id
:<|> searchDocs id :<|> searchDocs id
:<|> getScatter id :<|> getScatter id
:<|> getChart id :<|> getChart id
:<|> getPie id :<|> getPie id
:<|> getTree id :<|> getTree id
:<|> phyloAPI id uId :<|> phyloAPI id uId
:<|> postUpload id :<|> postUpload id
where
deleteNodeApi id' = do deleteNodeApi id' = do
node <- getNode' id' node <- getNode' id'
if _node_typename node == nodeTypeId NodeUser if _node_typename node == nodeTypeId NodeUser
......
...@@ -16,7 +16,15 @@ Let a Root Node, return the Tree of the Node as a directed acyclic graph ...@@ -16,7 +16,15 @@ Let a Root Node, return the Tree of the Node as a directed acyclic graph
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
module Gargantext.Database.Tree (treeDB, TreeError(..), HasTreeError(..), dbTree, toNodeTree, DbTreeNode) where module Gargantext.Database.Tree
( treeDB
, TreeError(..)
, HasTreeError(..)
, dbTree
, toNodeTree
, DbTreeNode
, isDescendantOf
) where
import Control.Lens (Prism', (#), (^..), at, each, _Just, to) import Control.Lens (Prism', (#), (^..), at, each, _Just, to)
import Control.Monad.Error.Class (MonadError(throwError)) import Control.Monad.Error.Class (MonadError(throwError))
...@@ -103,7 +111,21 @@ dbTree rootId = map (\(nId, tId, pId, n) -> DbTreeNode nId tId pId n) <$> runPGS ...@@ -103,7 +111,21 @@ dbTree rootId = map (\(nId, tId, pId, n) -> DbTreeNode nId tId pId n) <$> runPGS
SELECT * from tree; SELECT * from tree;
|] (Only rootId) |] (Only rootId)
isDescendantOf :: NodeId -> RootId -> Cmd err Bool
isDescendantOf childId rootId = (== [Only True]) <$> runPGSQuery [sql|
WITH RECURSIVE
tree (id, parent_id) AS
(
SELECT c.id, c.parent_id
FROM nodes AS c
WHERE c.id = ?
UNION
SELECT p.id, p.parent_id
FROM nodes AS p
INNER JOIN tree AS t ON t.parent_id = p.id
)
SELECT COUNT(*) = 1 from tree AS t
WHERE t.id = ?;
|] (childId, rootId)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment