{-# LANGUAGE GADTs,RankNTypes,DeriveFunctor,DeriveDataTypeable #-} module Data.Faceted.Internal( Label, Faceted(Raw,Faceted), PC, Branch(Private,Public), View, FIO(FIO), pcF, project, visibleTo ) where import Control.Applicative import Control.Monad import Data.IORef import Data.List import System.IO import Data.Dynamic -- | A security label is any string. -- Labels need not be secrets; they -- may be readable strings. Information flow security is ensured by a -- combination of the type system and dynamic checks. type Label = String -- | A _view_ is any set of labels. -- In enforcing information flow security Each view may see a different value. type View = [Label] -- | Type 'Faceted a' represents (possibly) faceted values. -- -- ====> Faceted k x y data Faceted a = Raw a | Faceted Label (Faceted a) (Faceted a) deriving (Show, Eq, Typeable) -- | Functor: For when the function is pure but the argument has facets. instance Functor Faceted where fmap f (Raw v) = Raw (f v) fmap f (Faceted k priv pub) = Faceted k (fmap f priv) (fmap f pub) -- | Applicative: For when the function and argument both have facets. instance Applicative Faceted where pure x = Raw x (Raw f) <*> x = fmap f x (Faceted k priv pub) <*> x = Faceted k (priv <*> x) (pub <*> x) -- | Monad: Like applicative, but even more powerful. 'Faceted' the free monad -- over the function 'Facets a = F Label a a'. instance Monad Faceted where return x = Raw x (Raw x) >>= f = f x (Faceted k priv pub) >>= f = Faceted k (priv >>= f) (pub >>= f) -- | A Branch is a principal or its negatives, and a pc is a set of branches. data Branch = Public Label | Private Label deriving (Eq, Show) type PC = [Branch] -- | << pc ? x : y >> =====> pcF pc x y pcF :: PC -> Faceted a -> Faceted a -> Faceted a pcF [] x _ = x pcF (Private k : branches) x y = Faceted k (pcF branches x y) y pcF (Public k : branches) x y = Faceted k y (pcF branches x y) -- Private project :: View -> Faceted a -> a project view (Raw v) = v project view (Faceted k priv pub) | k `elem` view = project view priv | k `notElem` view = project view pub -- Private visibleTo :: PC -> View -> Bool visibleTo pc view = all consistent pc where consistent (Private k) = k `elem` view consistent (Public k) = k `notElem` view -- | Faceted IO data FIO a = FIO { runFIO :: PC -> IO a } -- | Monad is straightforward instance Monad FIO where return x = FIO (\pc -> return x) x >>= f = FIO (\pc -> do v <- runFIO x pc runFIO (f v) pc)