-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | IFC enforcing web platform framework -- -- Hails is a framework for building multi-app web platforms. This module -- exports a library for building Hails platforms. @package hails @version 0.1.1 -- | This module re-exports Data.Time wrapped in LIO. It is -- important to note that this module is only safe with the latest -- version of LIO, where toLabeled has been removed and -- timing attacked have been addressed. In similar vain, when executing a -- piece of code that you do not trust, it is important that the time -- primitives not be directly available. module LIO.Data.Time -- | Get the current UTC time from the system clock. getCurrentTime :: LabelState l p s => LIO l p s UTCTime -- | Get the local time together with a TimeZone. getZonedTime :: LabelState l p s => LIO l p s ZonedTime -- | Convert UTC time to local time with TimzeZone utcToLocalZonedTime :: LabelState l p s => UTCTime -> LIO l p s ZonedTime -- | This module exports various cryptographic primitives. module Hails.Crypto -- | This module exports various authentication methods. module Hails.HttpServer.Auth -- | Authentication function type AuthFunction m s = HttpReq s -> m (Either (HttpResp m) (HttpReq s)) -- | Perform basic authentication basicAuth :: Monad m => (HttpReq s -> m Bool) -> AuthFunction m s -- | Basic authentication, that always succeeds. The function uses the -- username in the cookie (as in externalAuth), if it is set. If -- the cookie is not set, bsicAuth is used. basicNoAuth :: Monad m => AuthFunction m s -- | Use an external authentication service that sets a cookie. The cookie -- name is _hails_user, and its contents contain a string of the -- form user-name:HMAC-SHA1(user-name). This function simply -- checks that the cookie exits and the MAC'd user name is correct. If -- this is the case, it returns a request with the cookie removed. -- Otherwise it retuns a redirect (to the provided url) response. externalAuth :: L -> String -> AuthFunction DC s module Hails.IterIO.Conversions -- | Lift the underlying monad of an Iter from IO to -- LIO. iterIOtoIterLIO :: (LabelState l p s, ChunkData t) => Iter t IO a -> Iter t (LIO l p s) a -- | Lift the underlying monad of an IterR from IO to -- LIO. ioIterRtoLIO :: (LabelState l p s, ChunkData t) => IterR t IO a -> IterR t (LIO l p s) a -- | Lift the underlying monad of an Inum from IO to -- LIO. onumIOtoOnumLIO :: LabelState l p s => Onum L IO L -> Onum L (LIO l p s) a inumIOtoInumLIO :: (ChunkData tIn, ChunkData tOut) => Inum tIn tOut IO a -> LIOstate DCLabel TCBPriv () -> Inum tIn tOut DC a -- | Exports basic HTTP client functions inside the DC Monad. -- Computations are allowed to communicate over HTTP as long as they can -- read and write to a labeled origin. An origin is associated with two -- labels. When writing, the origin has a label of the form < -- {["scheme://authority"]}, True >, where scheme is -- either 'http' or 'https', and authority is the domain name or -- IP address used in the request and port number of the connection. In -- other words, the secrecy component contains the origin information, -- while the integrity component is the same as that of public data. When -- reading, the origin has a label of the form < True, -- {["scheme://authority"]} >. -- -- This means that LIO (specifically, DC) computations can -- export data if the current label is not higher than that of the -- labeled origin, and read data that is no more trustworthy than that of -- the origin. Practically, this means that untrusted computation can -- export data so long as the they have not observed any data more -- sensitive than the label of the target domain. Reading (which also -- occurs on every request/write) further raises the current label to the -- join of the current label and origin. -- -- For example, suppose some piece of data, myLoc, has the -- label: -- --
-- aliceLocL = newDC ("alice" ./\. "http://maps.googleapis.com:80") (<>)
--
--
-- created as:
--
-- -- myLoc <- labelP alicePriv aliceLocL "3101 24th Street, San Francisco, CA" ---- -- Then, untrusted code (with initial label set to public) running on -- behalf of "alice" , may perform the following operation: -- --
-- let mapBase = "http://maps.googleapis.com/maps/api/geocode/json?sensor=false" -- aliceLoc <- urlEncode <$> (unlabelP alicePriv myLoc) -- resp <- simpleGetHttp $ mapBase ++ "&address=" ++ aliceLoc ---- -- In this case the unlabelP will raise the current label to the -- label: -- --
-- < {["http://maps.googleapis.com:80"]}, True >
--
--
-- by exercising "alice"s privilges. Directly, the simpleHttp will
-- be permitted. However, if
--
-- -- let mapBase = "http://maps.evilalternatives.org/geocode/json?sensor=false" ---- -- an exception will be thrown since the current label does not flow to -- the label of mapBase. module Hails.IterIO.HttpClient -- | A HTTP response, containing the status, headers, and parsed body. data HttpRespDC HttpRespDC :: !HttpStatus -> ![(S, S)] -> DC (Onum L DC ()) -> HttpRespDC -- | Response status respStatusDC :: HttpRespDC -> !HttpStatus -- | Response headers respHeadersDC :: HttpRespDC -> ![(S, S)] -- | Response body respBodyDC :: HttpRespDC -> DC (Onum L DC ()) -- | Perform a simple HTTP request, given the the request header, body and -- SSL context, if any. Note that that request must have the scheme, host -- fields set. simpleHttp :: HttpReq () -> L -> DC HttpRespDC -- | Same as simpleHttp, but uses privileges. simpleHttpP :: DCPrivTCB -> HttpReq () -> L -> DC HttpRespDC -- | Simple HTTP GET request. simpleGetHttp :: String -> DC HttpRespDC -- | Simple HTTP GET request. simpleGetHttpP :: DCPrivTCB -> String -> DC HttpRespDC -- | Simple HTTP HEAD request. simpleHeadHttp :: String -> DC HttpRespDC -- | Simple HTTP HEAD request. simpleHeadHttpP :: DCPrivTCB -> String -> DC HttpRespDC -- | Extract body from response extractBody :: HttpRespDC -> DC L -- | An HTTP client that reuses a connection to perform multiple requests. -- Note that a wguard is only performed at the connection -- establishment. multiHttp :: (HttpReq (), L) -> DCHttpResponseHandler -> DC () -- | An HTTP response handler in the DC monad. type DCHttpResponseHandler = HttpRespDC -> Iter L DC (Maybe (HttpReq (), L)) -- | Create a simple HEAD request. The url must be an -- absoluteURI. headRequest :: String -> HttpReq () -- | Create a simple GET request. The url must be an -- absoluteURI. getRequest :: String -> HttpReq () -- | Given a URL, Content-Type, and message body, perform a simple POST -- request. Note: message body must be properly encoded (e.g., -- URL-encoded if the Content-Type is -- "application/x-www-form-urlencoded"). postRequest :: String -> String -> L -> HttpReq () module Hails.IterIO.Mime -- | Given a file extension (e.g., "hs") return its MIME type (e.g., -- "text/x-haskell"). If there is no recognized MIME type (or none of the -- default paths exist), this function returns "application/octet-stream" systemMimeMap :: String -> ByteString module Hails.TCB.Types -- | Application name type AppName = String -- | Application configuration. data AppConf AppConf :: !Principal -> !AppName -> !TCBPriv -> HttpReq () -> AppConf -- | User the app is running on behalf of appUser :: AppConf -> !Principal -- | The app's name appName :: AppConf -> !AppName -- | The app's privileges. appPriv :: AppConf -> !TCBPriv -- | The request message appReq :: AppConf -> HttpReq () -- | Application handler. type AppReqHandler = HttpReq () -> DCLabeled L -> DC (HttpResp DC) -- | Application route. type AppRoute = HttpRoute DC () module Hails.IterIO.HailsRoute routeFileSys :: LabelState l p st => (String -> ByteString) -> (FilePath -> HttpRoute (LIO l p st) s) -> FilePath -> HttpRoute (LIO l p st) s module Hails.HttpServer -- | Return a server, given a port number and app. secureHttpServer :: AuthFunction DC () -> PortNumber -> AppReqHandler -> TCPServer L DC module Hails.App -- | Application handler. type AppReqHandler = HttpReq () -> DCLabeled L -> DC (HttpResp DC) -- | Application route. type AppRoute = HttpRoute DC () -- | Get the user the app is running on behalf of getHailsUser :: Action t b DC String -- | Get the app the app is running on behalf of getHailsApp :: Action t b DC String -- | This module exports an interface for LBSON (Labeled BSON) object. An -- LBSON object is either a BSON object (see Bson) with the added -- support for labeled Values. More specifically, a LBSON document -- is a list of Fields (which are 'Key'-'Value' pairs), where the -- Value of a Field can either be a standard Value -- type or a Labeled Value type. module Hails.Data.LBson.TCB -- | A LBSON document is a list of Fields type Document l = [Field l] -- | A labeled Document type LabeledDocument l = Labeled l (Document l) -- | Value of field in document, or fail (Nothing) if field not found look :: (Monad m, Label l) => Key -> Document l -> m (Value l) -- | Lookup value of field in document and cast to expected type. Fail -- (Nothing) if field not found or value not of expected type. lookup :: (Val l v, Monad m, Label l) => Key -> Document l -> m v -- | Value of field in document. Error if missing. valueAt :: Label l => Key -> [Field l] -> Value l -- | Typed value of field in document. Error if missing or wrong type. at :: (Val l v, Label l) => Key -> Document l -> v -- | Only include fields of document in key list include :: Label l => [Key] -> Document l -> Document l -- | Exclude fields from document in key list exclude :: Label l => [Key] -> Document l -> Document l -- | Merge documents with preference given to first one when both have the -- same key. I.e. for every (k := v) in first argument, if k exists in -- second argument then replace its value with v, otherwise add (k := v) -- to second argument. merge :: Label l => Document l -> Document l -> Document l -- | A Field is a 'Key'-'Value' pair. data Field l (:=) :: !Key -> Value l -> Field l key :: Field l -> !Key value :: Field l -> Value l -- | Field with given label and typed value (=:) :: (Val l v, Label l) => Key -> v -> Field l -- | If Just value then return one field document, otherwise -- return empty document (=?) :: (Val l a, Label l) => Key -> Maybe a -> Document l -- | A Key, or attribute is a BSON label. type Key = Label -- | This prefix is reserved for HAILS keys. It should not be used by -- arbitrary code. hailsInternalKeyPrefix :: Key -- | Check if a key is unsafe. isUnsafeKey :: Key -> Bool -- | A Value is either a standard BSON value, a labeled value, or -- a policy-labeled value. data Value l -- | Unlabeled BSON value BsonVal :: Value -> Value l -- | Labeled (LBSON) value LabeledVal :: (Labeled l Value) -> Value l -- | Policy labeled (LBSON) value PolicyLabeledVal :: (PolicyLabeled l Value) -> Value l -- | Haskell types of this class correspond to LBSON value types. class (Typeable a, Show a, Eq a, Label l) => Val l a val :: Val l a => a -> Value l cast' :: Val l a => Value l -> Maybe a -- | Convert Value to expected type, or fail (Nothing) if not of that type cast :: (Label l, Val l a, Monad m) => Value l -> m a -- | Convert Value to expected type. Error if not that type. typed :: (Val l a, Label l) => Value l -> a -- | Simple sum type used to denote a policy-labeled type. A -- PolicyLabeled type can be either labeled (policy applied), or -- unabled (policy not yet applied). data PolicyLabeled l a -- | Policy was not applied PU :: a -> PolicyLabeled l a -- | Policy applied PL :: (Labeled l a) -> PolicyLabeled l a -- | Wrap an unlabeled value by PolicyLabeled. pu :: (Label l, Val a) => a -> PolicyLabeled l a -- | Wrap an already-labeled value by PolicyLabeled. pl :: (Label l, Val a) => Labeled l a -> PolicyLabeled l a newtype Binary :: * Binary :: ByteString -> Binary newtype Function :: * Function :: ByteString -> Function newtype UUID :: * UUID :: ByteString -> UUID newtype MD5 :: * MD5 :: ByteString -> MD5 newtype UserDefined :: * UserDefined :: ByteString -> UserDefined -- | The first string is the regex pattern, the second is the regex options -- string. Options are identified by characters, which must be listed in -- alphabetical order. Valid options are *i* for case insensitive -- matching, *m* for multiline matching, *x* for verbose mode, *l* to -- make \w, \W, etc. locale dependent, *s* for dotall mode ("." matches -- everything), and *u* to make \w, \W, etc. match unicode. data Regex :: * Regex :: UString -> UString -> Regex -- | Javascript code with possibly empty environment mapping variables to -- values that the code may reference data Javascript :: * Javascript :: Document -> UString -> Javascript newtype Symbol :: * Symbol :: UString -> Symbol newtype MongoStamp :: * MongoStamp :: Int64 -> MongoStamp data MinMaxKey :: * MinKey :: MinMaxKey MaxKey :: MinMaxKey -- | A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp -- (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a -- 3-byte counter. Note that the timestamp and counter fields must be -- stored big endian unlike the rest of BSON. This is because they are -- compared byte-by-byte and we want to ensure a mostly increasing order. data ObjectId :: * Oid :: Word32 -> Word64 -> ObjectId -- | Time when objectId was created timestamp :: ObjectId -> UTCTime -- | Generate fresh ObjectId. genObjectId :: LabelState l p s => LIO l p s ObjectId -- | Export Value type BsonValue = Value -- | Safely convert from a Value to a BsonValue. safeToBsonValue :: Label l => Value l -> Maybe BsonValue -- | Safely convert from a BsonValue to a Value. safeFromBsonValue :: (Serialize l, Label l) => BsonValue -> Maybe (Value l) -- | Export Document type BsonDocument = Document -- | Safe version of toBsonDoc. safeToBsonDoc :: (Serialize l, Label l) => Document l -> Maybe BsonDocument -- | Safe version of fromBsonDoc. safeFromBsonDoc :: (Serialize l, Label l) => BsonDocument -> Maybe (Document l) -- | Encodea document encodeDoc :: BsonDocSerialize doc => doc -> ByteString -- | Decode a document decodeDoc :: BsonDocSerialize doc => ByteString -> doc -- | Convert a Document to a Bson Document. It is an error -- to call this function with malformed Documents (i.e., those for -- which a policy has not been applied. toBsonDoc :: (Serialize l, Label l) => Document l -> Document -- | Convert a Bson Document to a Document. This -- implementation is relaxed and omits any fields that were not -- converted. Use the fromBsonDocStrict for a strict conversion. fromBsonDoc :: (Serialize l, Label l) => Document -> Document l -- | Same as fromBsonDoc, but fails (returns Nothing) if -- any of the field values failed to be serialized. fromBsonDocStrict :: (Serialize l, Label l) => Document -> Maybe (Document l) -- | If value is a document, remove any fields that have -- hailsInternalKeyPrefix as a prefix, otherwise return the value -- unchanged. This is equivilant to exceptInternal except it -- operates on BSON values as opposed to Hails Documents. sanitizeBsonValue :: Value -> Value instance [overlap ok] Typeable2 PolicyLabeled instance [overlap ok] Typeable1 Value instance [overlap ok] Typeable1 Field instance [overlap ok] Label l => Eq (Field l) instance [overlap ok] (Serialize l, Label l) => BsonDocSerialize (Document l) instance [overlap ok] BsonDocSerialize BsonDocument instance [overlap ok] Label l => Eq (PolicyLabeled l a) instance [overlap ok] (Show a, Label l) => Show (PolicyLabeled l a) instance [overlap ok] Label l => Eq (Labeled l a) instance [overlap ok] (Show a, Label l) => Show (Labeled l a) instance [overlap ok] (Val a, Label l) => Val l (PolicyLabeled l a) instance [overlap ok] (Val a, Label l) => Val l (Labeled l a) instance [overlap ok] Label l => Val l (Value l) instance [overlap ok] (Val a, Label l) => Val l a instance [overlap ok] Label l => Eq (Value l) instance [overlap ok] Label l => Show (Value l) instance [overlap ok] Label l => Show (Field l) module Hails.Database.MongoDB.TCB.Types -- | Name of collection type CollectionName = Collection -- | A labeled Collection map. type CollectionMap l = Labeled l (Map CollectionName (CollectionPolicy l)) -- | Labels and policies associated with a collection. See -- Collection. data CollectionPolicy l CollectionPolicy :: l -> l -> RawPolicy l -> CollectionPolicy l -- | Collection label colLabel :: CollectionPolicy l -> l -- | Collection clearance colClear :: CollectionPolicy l -> l -- | Collection labeling policy colPolicy :: CollectionPolicy l -> RawPolicy l -- | A collection policy is is a label, clearance and labeling policy. The -- label specifies who can write to a collection (i.e., only computatoin -- whose current label flows to the label of the collection). The -- clearance limits the sensitivity of the data written to the collection -- (i.e., the labels of all data in the collection must flow to the -- clearance). Note that the collection label does not impose a -- restriction on the data (i.e., data can have high integrity). The -- collection policy specifies the policies for labeling documents and -- fields of documents. data Collection l Collection :: CollectionName -> CollectionPolicy l -> Collection l -- | Collection name colIntern :: Collection l -> CollectionName -- | Collection secutiry policies: access control and labeling policies colSec :: Collection l -> CollectionPolicy l -- | Create a collection given a collection name, label, clearance, and -- policy. Note that the collection label and clearance must be above the -- current label and below the current clearance. collection :: LabelState l p s => CollectionName -> l -> l -> RawPolicy l -> LIO l p s (Collection l) -- | Same as collection, but uses privileges when comparing the -- collection label and clearance with the current label and clearance. collectionP :: LabelState l p s => p -> CollectionName -> l -> l -> RawPolicy l -> LIO l p s (Collection l) -- | Same as collection, but ignores IFC. collectionTCB :: LabelState l p s => CollectionName -> l -> l -> RawPolicy l -> LIO l p s (Collection l) -- | Name of database type DatabaseName = Database -- | A database has a label, which is used for controlling access to the -- database, an internal identifier corresponding to the underlying -- MongoDB database, and a set of Collections protected by a -- label. data Database l Database :: DatabaseName -> l -> CollectionMap l -> Database l -- | Actual MongoDB dbIntern :: Database l -> DatabaseName -- | Label of database dbLabel :: Database l -> l -- | Collections associated with databsae dbColPolicies :: Database l -> CollectionMap l -- | Same as databaseP, but does not use privileges when comparing -- the current label (and clearance) with the supplied database label. database :: LabelState l p s => DatabaseName -> l -> CollectionMap l -> LIO l p s (Database l) -- | Create a Database. Given a set of privileges, the name of the -- database, the database label, and set of collections, create a -- database. Note that this does not restrict an application from -- creating arbitrary databases and collections---this should be handled -- by a shim layer. databaseP :: LabelState l p s => p -> DatabaseName -> l -> CollectionMap l -> LIO l p s (Database l) -- | Sameas databaseP, but ignores IFC checks. databaseTCB :: LabelState l p s => DatabaseName -> l -> CollectionMap l -> LIO l p s (Database l) -- | Same as assocCollectionP, but does not use privileges when -- writing to database collection map. assocCollection :: LabelState l p s => Collection l -> Database l -> LIO l p s (Database l) -- | Associate a collection with the underlying database. assocCollectionP :: LabelState l p s => p -> Collection l -> Database l -> LIO l p s (Database l) -- | Same as assocCollectionP, but ignores IFC. assocCollectionTCB :: LabelState l p s => Collection l -> Database l -> LIO l p s (Database l) -- | A RawPolicy encodes a document policy, and all field -- policies. It is required that all fields of type PolicyLabled -- have a field/column policy -- if using only this low-level interface a -- runtime-error will occur if this is not satisfied. data RawPolicy l RawPolicy :: (Document l -> l) -> [(Key, FieldPolicy l)] -> RawPolicy l -- | A row (document) policy is a function from a Document to a -- Label. rawDocPolicy :: RawPolicy l -> Document l -> l -- | A column (field) policy is a function from a Document to a -- Label, for each field of type PolicyLabeled. rawFieldPolicies :: RawPolicy l -> [(Key, FieldPolicy l)] -- | A FieldPolicy specifies the policy-generated label of a -- field. SearchabelField specifies that the field can be -- referenced in the selection clause of a Query, and therefore -- the document label does not apply to it. data FieldPolicy l SearchableField :: FieldPolicy l FieldPolicy :: (Document l -> l) -> FieldPolicy l -- | Returns True if the policy is for a searchable field isSearchableField :: FieldPolicy l -> Bool -- | Returns a list of the SearchableFields speicified in a -- RawPolicy searchableFields :: RawPolicy l -> [Key] -- | Field/column policies are required for every PolicyLabled -- value in a document. data PolicyError -- | Policy for field not specified NoFieldPolicy :: PolicyError -- | Policy application invalid InvalidPolicy :: PolicyError -- | Policy for Collection not specified NoColPolicy :: PolicyError -- | Field with associated policy is not of PolicyLabeled type InvalidFieldPolicyType :: PolicyError -- | Searchable fields cannot contain labeled values InvalidSearchableType :: PolicyError -- | Policy has been violated PolicyViolation :: PolicyError data NoSuchDatabaseError NoSuchDatabase :: NoSuchDatabaseError -- | Since it would be a security violation to make LIO an instance -- of MonadIO, we create a Mongo-specific, wrapper for -- LIO that is instance of MonadIO. -- -- NOTE: IT IS IMPORTANT THAT UnsafeLIO NEVER BE EXPOSED BY -- MODULES THAT ARE NOT Unsafe. newtype UnsafeLIO l p s a UnsafeLIO :: LIO l p s a -> UnsafeLIO l p s a unUnsafeLIO :: UnsafeLIO l p s a -> LIO l p s a -- | An LIO action with MongoDB access. newtype LIOAction l p s a LIOAction :: Action (UnsafeLIO l p s) a -> LIOAction l p s a unLIOAction :: LIOAction l p s a -> Action (UnsafeLIO l p s) a newtype Action l p s a Action :: (ReaderT (Database l) (LIOAction l p s) a) -> Action l p s a -- | Lift a MongoDB action into Action monad. liftAction :: LabelState l p s => Action (UnsafeLIO l p s) a -> Action l p s a -- | Get underlying database. getDatabase :: Action l p s (Database l) -- | A labeled cursor. The cursor is labeled with the join of the database -- and collection it reads from. data Cursor l Cursor :: l -> Cursor -> Projector -> CollectionPolicy l -> Cursor l -- | Cursorlabel curLabel :: Cursor l -> l -- | Actual cursor curIntern :: Cursor l -> Cursor -- | Projector from query curProject :: Cursor l -> Projector -- | Collection policy curPolicy :: Cursor l -> CollectionPolicy l -- | A connection failure, or a read or write exception like cursor expired -- or inserting a duplicate key. Note, unexpected data from the server is -- not a Failure, rather it is a programming error (you should call -- error in this case) because the client and server are -- incompatible and requires a programming change. data Failure :: * instance Typeable PolicyError instance Typeable NoSuchDatabaseError instance Functor (UnsafeLIO l p s) instance Applicative (UnsafeLIO l p s) instance Monad (UnsafeLIO l p s) instance Functor (LIOAction l p s) instance Applicative (LIOAction l p s) instance Monad (LIOAction l p s) instance Functor (Action l p s) instance Applicative (Action l p s) instance Monad (Action l p s) instance LabelState l p s => MonadLIO (Action l p s) l p s instance LabelState l p s => MonadLIO (LIOAction l p s) l p s instance LabelState l p s => MonadLIO (UnsafeLIO l p s) l p s instance LabelState l p s => MonadBaseControl IO (UnsafeLIO l p s) instance LabelState l p s => MonadBase IO (UnsafeLIO l p s) instance LabelState l p s => MonadIO (UnsafeLIO l p s) instance Exception NoSuchDatabaseError instance Show NoSuchDatabaseError instance Exception PolicyError instance Show PolicyError module Hails.Database.MongoDB.TCB.Convert -- | Trusted transformer that takes a Labeled tuple with -- HttpReq and the request body as a ByteString and returns -- a Labeled Document with keys and values corresponding to -- the form fields from the request. The label on the Labeled -- result is the same as input. Arguments values are parsed in to BSON -- Strings except if the key is of the form "key_name[]" in which case -- all such arguments will be combined into an array of Strings. labeledDocI :: LabelState l p s => HttpReq a -> Labeled l ByteString -> LIO l p s (Labeled l (Document l)) module Hails.Database.MongoDB.TCB.Access -- | Apply a raw field/column policy to all the fields of type -- PolicyLabeled, and then apply the raw document/row policy. It -- must be that every labeled value in the document (including the -- document itself) have a label that is below the clearance of the -- collection. However, this is not checked by applyRawPolicyP. -- Instead insert (and similar operators) performs this check. applyRawPolicyP :: LabelState l p s => p -> CollectionPolicy l -> Document l -> LIO l p s (LabeledDocument l) -- | Same as applyRawPolicy, but ignores the current label and -- clearance when applying policies. applyRawPolicyTCB :: LabelState l p s => CollectionPolicy l -> Document l -> LIO l p s (LabeledDocument l) -- | Run action against database on server at other end of pipe. Use access -- mode for any reads and writes. Return Left on connection -- failure or read/write failure. The current label is raised to the the -- join of the database label and current label. accessTCB :: LabelState l p s => Pipe -> AccessMode -> Database l -> Action l p s a -> LIO l p s (Either Failure a) module Hails.Database.MongoDB.TCB.Query -- | Insert document into collection and return its _id value, -- which is created automatically if not supplied. It is required that -- the current label flow to the label of the collection and database -- (and vice versa). Additionally, the document must be well-formed with -- respect to the collection policy. In other words, all the labeled -- values must be below the collection clearance and the policy be -- applied successfully. insert :: Insert l p s doc => CollectionName -> doc -> Action l p s (Value l) -- | Same as insert except it does not return _id insert_ :: Insert l p s doc => CollectionName -> doc -> Action l p s () -- | Same as insert, but uses privileges when applying the -- collection policies, and doing label comparisons. insertP :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s (Value l) -- | Same as insertP except it does not return _id insertP_ :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s () -- | Update a document based on the _id value. The IFC -- requirements subsume those of insert. Specifically, in addition -- to being able to apply all the policies and requiring that the current -- label flow to the label of the collection and database save -- requires that the current label flow to the label of the existing -- database record. save :: Insert l p s doc => CollectionName -> doc -> Action l p s () -- | Like save, but uses privileges when performing label -- comparisons. saveP :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s () -- | Given a query, delete first object in selection. In addition to being -- able to read the object, write to the database and collection, it must -- be that the current label flow to the label of the existing document. deleteOne :: (LabelState l p s, Serialize l) => Selection l -> Action l p s () -- | Same as deleteOne, but uses privileges when performing label -- comparisons. deleteOneP :: (LabelState l p s, Serialize l) => p -> Selection l -> Action l p s () -- | Fetch documents satisfying query. A labeled Cursor is returned, -- which can be used to retrieve the actual Documents. Current -- label is raised to the join of the collection, database, and -- ccollection-policy label. find :: (Serialize l, LabelState l p s) => Query l -> Action l p s (Cursor l) -- | Same as find, but uses privileges when raising the current -- label findP :: (Serialize l, LabelState l p s) => p -> Query l -> Action l p s (Cursor l) -- | Fetch the first document satisfying query, or Nothing if not -- documents matched the query. findOne :: (LabelState l p s, Serialize l) => Query l -> Action l p s (Maybe (LabeledDocument l)) -- | Same as findOne, but uses privileges when performing label -- comparisons. findOneP :: (LabelState l p s, Serialize l) => p -> Query l -> Action l p s (Maybe (LabeledDocument l)) -- | Return next document in query result, or Nothing if finished. -- The current label is raised to join of the current label and -- Cursor label. The document is labeled according to the -- underlying 'Collection'\'s policies. next :: (LabelState l p s, Serialize l) => Cursor l -> Action l p s (Maybe (LabeledDocument l)) -- | Same as next, but usess privileges raising the current label. nextP :: (LabelState l p s, Serialize l) => p -> Cursor l -> Action l p s (Maybe (LabeledDocument l)) -- | Use select to create a basic query with defaults, then modify if -- desired. Example: (select sel col) {limit =: 10}. Note that -- unlike MongoDB's query functionality, our queries do not allow for -- projections (since policies may need a field that is not projects). -- Both the selection and sorting are restricted to searchable fields. -- -- TODO: add snapshot. data Query l Query :: [QueryOption] -> Selection l -> Word32 -> Limit -> Order l -> BatchSize -> Order l -> Query l -- | Query options, default []. options :: Query l -> [QueryOption] -- | WHERE clause,default []. selection :: Query l -> Selection l -- | Number of documents to skip, default 0. skip :: Query l -> Word32 -- | Max number of documents to return. Default, 0, means no limit. limit :: Query l -> Limit -- | Sort result by given order, default []. sort :: Query l -> Order l -- | The number of document to return in each batch response from the -- server. 0 means Mongo default. batchSize :: Query l -> BatchSize -- | Force mongoDB to use this index (must be only searchable fields). -- Default [], no hint. hint :: Query l -> Order l -- | Selects documents in specified collection that match the selector. data Selection l Selection :: Selector l -> CollectionName -> Selection l -- | Selector selector :: Selection l -> Selector l -- | Collection operaing coll :: Selection l -> CollectionName -- | Filter for a query, analogous to the WHERE clause in SQL. -- [] matches all documents in collection. [x =: a, -- y =: b] is analogous to WHERE x = a AND y = b in -- SQL. -- -- Note: all labeld (including policy-labeled) values are removed -- from the Selector. type Selector l = Document l -- | Query or Selection that selects documents in collection -- that match selector. The choice of end type depends on use, for -- example, in find select sel col is a Query, but -- in delete it is a Selection. select :: (Select selectionOrQuery, Label l) => Selector l -> CollectionName -> selectionOrQuery l instance (LabelState l p s, Serialize l, Insert l p s (Document l)) => Insert l p s (Labeled l (Document l)) instance (LabelState l p s, Serialize l) => Insert l p s (Document l) instance Select Query instance Select Selection -- | Rexports Data.Bson module Hails.Data.LBson.Rexports.Bson -- | Moduule rexport Bson Value value-constructors module Hails.Data.LBson.Rexports -- | A BSON value is one of the following types of values data Value :: * Float :: Double -> Value String :: UString -> Value Doc :: Document -> Value Array :: [Value] -> Value Bin :: Binary -> Value Fun :: Function -> Value Uuid :: UUID -> Value Md5 :: MD5 -> Value UserDef :: UserDefined -> Value ObjId :: ObjectId -> Value Bool :: Bool -> Value UTC :: UTCTime -> Value Null :: Value RegEx :: Regex -> Value JavaScr :: Javascript -> Value Sym :: Symbol -> Value Int32 :: Int32 -> Value Int64 :: Int64 -> Value Stamp :: MongoStamp -> Value MinMax :: MinMaxKey -> Value -- | This module exports a safe subset of the labeled BSON (LBSON) module. -- See Hails.Data.LBson.TCB for documentation. module Hails.Data.LBson.Safe -- | A LBSON document is a list of Fields type Document l = [Field l] -- | A labeled Document type LabeledDocument l = Labeled l (Document l) -- | Value of field in document, or fail (Nothing) if field not found look :: (Monad m, Label l) => Key -> Document l -> m (Value l) -- | Lookup value of field in document and cast to expected type. Fail -- (Nothing) if field not found or value not of expected type. lookup :: (Val l v, Monad m, Label l) => Key -> Document l -> m v -- | Value of field in document. Error if missing. valueAt :: Label l => Key -> [Field l] -> Value l -- | Typed value of field in document. Error if missing or wrong type. at :: (Val l v, Label l) => Key -> Document l -> v -- | Only include fields of document in key list include :: Label l => [Key] -> Document l -> Document l -- | Exclude fields from document in key list exclude :: Label l => [Key] -> Document l -> Document l -- | Merge documents with preference given to first one when both have the -- same key. I.e. for every (k := v) in first argument, if k exists in -- second argument then replace its value with v, otherwise add (k := v) -- to second argument. merge :: Label l => Document l -> Document l -> Document l -- | A Field is a 'Key'-'Value' pair. data Field l (:=) :: !Key -> Value l -> Field l key :: Field l -> !Key value :: Field l -> Value l -- | Field with given label and typed value (=:) :: (Val l v, Label l) => Key -> v -> Field l -- | If Just value then return one field document, otherwise -- return empty document (=?) :: (Val l a, Label l) => Key -> Maybe a -> Document l -- | A Key, or attribute is a BSON label. type Key = Label -- | This prefix is reserved for HAILS keys. It should not be used by -- arbitrary code. hailsInternalKeyPrefix :: Key -- | A Value is either a standard BSON value, a labeled value, or -- a policy-labeled value. data Value l -- | Haskell types of this class correspond to LBSON value types. class (Typeable a, Show a, Eq a, Label l) => Val l a val :: Val l a => a -> Value l cast' :: Val l a => Value l -> Maybe a -- | Convert Value to expected type, or fail (Nothing) if not of that type cast :: (Label l, Val l a, Monad m) => Value l -> m a -- | Convert Value to expected type. Error if not that type. typed :: (Val l a, Label l) => Value l -> a -- | Wrap an unlabeled value by PolicyLabeled. pu :: (Label l, Val a) => a -> PolicyLabeled l a -- | Wrap an already-labeled value by PolicyLabeled. pl :: (Label l, Val a) => Labeled l a -> PolicyLabeled l a newtype Binary :: * Binary :: ByteString -> Binary newtype Function :: * Function :: ByteString -> Function newtype UUID :: * UUID :: ByteString -> UUID newtype MD5 :: * MD5 :: ByteString -> MD5 newtype UserDefined :: * UserDefined :: ByteString -> UserDefined -- | The first string is the regex pattern, the second is the regex options -- string. Options are identified by characters, which must be listed in -- alphabetical order. Valid options are *i* for case insensitive -- matching, *m* for multiline matching, *x* for verbose mode, *l* to -- make \w, \W, etc. locale dependent, *s* for dotall mode ("." matches -- everything), and *u* to make \w, \W, etc. match unicode. data Regex :: * Regex :: UString -> UString -> Regex -- | Javascript code with possibly empty environment mapping variables to -- values that the code may reference data Javascript :: * Javascript :: Document -> UString -> Javascript newtype Symbol :: * Symbol :: UString -> Symbol newtype MongoStamp :: * MongoStamp :: Int64 -> MongoStamp data MinMaxKey :: * MinKey :: MinMaxKey MaxKey :: MinMaxKey -- | A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp -- (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a -- 3-byte counter. Note that the timestamp and counter fields must be -- stored big endian unlike the rest of BSON. This is because they are -- compared byte-by-byte and we want to ensure a mostly increasing order. data ObjectId :: * Oid :: Word32 -> Word64 -> ObjectId -- | Time when objectId was created timestamp :: ObjectId -> UTCTime -- | Generate fresh ObjectId. genObjectId :: LabelState l p s => LIO l p s ObjectId -- | Export Value type BsonValue = Value -- | Safely convert from a Value to a BsonValue. safeToBsonValue :: Label l => Value l -> Maybe BsonValue -- | Safely convert from a BsonValue to a Value. safeFromBsonValue :: (Serialize l, Label l) => BsonValue -> Maybe (Value l) -- | Export Document type BsonDocument = Document -- | Safe version of toBsonDoc. safeToBsonDoc :: (Serialize l, Label l) => Document l -> Maybe BsonDocument -- | Safe version of fromBsonDoc. safeFromBsonDoc :: (Serialize l, Label l) => BsonDocument -> Maybe (Document l) -- | Encodea document encodeDoc :: BsonDocSerialize doc => doc -> ByteString -- | Decode a document decodeDoc :: BsonDocSerialize doc => ByteString -> doc module Hails.Data.LBson module Hails.Database.MongoDB.TCB.DCAccess -- | Database configuration, used to invoke withDB data DBConf DBConf :: DatabaseName -> DCPrivTCB -> DBConf dbConfName :: DBConf -> DatabaseName dbConfPriv :: DBConf -> DCPrivTCB type DCAction = Action DCLabel DCPrivTCB () -- | Open a pipe to a supplied server, or localhost. TODO: add -- support for connecting to replicas. dcAccess :: Database DCLabel -> DCAction a -> DC (Either Failure a) -- | The withDB functions should use this function to label their -- databases. TODO (DS/AL(: make every searchable field indexable. labelDatabase :: DBConf -> DCLabel -> DCLabel -> DC (Database DCLabel) -- | Policy modules are instances of this class. In particular, when an -- application accesses a database, the runtime invokes -- createDatabasePolicy in the appropriate policy module. class DatabasePolicy dbp createDatabasePolicy :: DatabasePolicy dbp => DBConf -> DCPrivTCB -> DC dbp policyDB :: DatabasePolicy dbp => dbp -> Database DCLabel -- | Class used to define groups in a policy-specific manner. class DatabasePolicy dbp => PolicyGroup dbp where expandGroup _ princ = return [princ] relabelGroups _ = return expandGroup :: PolicyGroup dbp => dbp -> Principal -> DCAction [Principal] relabelGroups :: PolicyGroup dbp => dbp -> DCLabeled a -> DC (DCLabeled a) -- | Looks for disjuctions the privilege is able to downgrade and rewrites -- them by invoking expandGroup on each principle in the -- disjuction. Using the result, the function relabels the Labeled -- value. Clients should not call this directly, instead clients should -- call relabelGroups which policies may implement by wrapping -- this function. relabelGroupsP :: PolicyGroup dbp => dbp -> DCPrivTCB -> Labeled DCLabel a -> DC (DCLabeled a) -- | A wrapper around relabelGroups that drops the current -- privileges and restores them after getting a result from -- relabelGroups. relabelGroupsSafe :: PolicyGroup dbp => dbp -> Labeled DCLabel a -> DC (DCLabeled a) -- | Class used to define policy-specifi privilege granting gate. class DatabasePolicy dbp => PrivilegeGrantGate dbp grantPriv :: PrivilegeGrantGate dbp => dbp -> Principal -> DC (DCGate DCPrivTCB) -- | Given a set of privileges, a desired label and action. Lower the -- current label as close tothe desired label as possible, execute the -- action and raise the current label. withLabel :: DCPrivTCB -> DCLabel -> DC a -> DC a -- | Given a set of privileges, a labeled document and computaiton on the -- (unlabeled version of the) documnet, downgrade the current label with -- the supplied privileges execute (only integrity), unlabel the document -- and apply the computation to it. The result is then labeled with the -- current label and the current label is reset to the original (if -- possible). gateToLabeled :: DCPrivTCB -> DCLabeled (Document DCLabel) -> (Document DCLabel -> DC a) -> DC (DCLabeled a) instance Show DBConf module Hails.Database -- | Create a DatabasePolicy with the appropriate underline -- databse name and privileges, determined by the actual instance -- requested. mkPolicy :: (DatabasePolicy dbp, Typeable dbp) => DC dbp -- | Given a database name and a database action, execute the action on the -- database. withDB :: DatabasePolicy dbp => dbp -> DCAction a -> DC (Either Failure a) module Hails.Database.MongoDB -- | Name of collection type CollectionName = Collection -- | Labels and policies associated with a collection. See -- Collection. data CollectionPolicy l -- | A collection policy is is a label, clearance and labeling policy. The -- label specifies who can write to a collection (i.e., only computatoin -- whose current label flows to the label of the collection). The -- clearance limits the sensitivity of the data written to the collection -- (i.e., the labels of all data in the collection must flow to the -- clearance). Note that the collection label does not impose a -- restriction on the data (i.e., data can have high integrity). The -- collection policy specifies the policies for labeling documents and -- fields of documents. data Collection l -- | A labeled Collection map. type CollectionMap l = Labeled l (Map CollectionName (CollectionPolicy l)) -- | Create a collection given a collection name, label, clearance, and -- policy. Note that the collection label and clearance must be above the -- current label and below the current clearance. collection :: LabelState l p s => CollectionName -> l -> l -> RawPolicy l -> LIO l p s (Collection l) -- | Same as collection, but uses privileges when comparing the -- collection label and clearance with the current label and clearance. collectionP :: LabelState l p s => p -> CollectionName -> l -> l -> RawPolicy l -> LIO l p s (Collection l) -- | Name of database type DatabaseName = Database -- | A database has a label, which is used for controlling access to the -- database, an internal identifier corresponding to the underlying -- MongoDB database, and a set of Collections protected by a -- label. data Database l -- | Same as assocCollectionP, but does not use privileges when -- writing to database collection map. assocCollection :: LabelState l p s => Collection l -> Database l -> LIO l p s (Database l) -- | Associate a collection with the underlying database. assocCollectionP :: LabelState l p s => p -> Collection l -> Database l -> LIO l p s (Database l) -- | A RawPolicy encodes a document policy, and all field -- policies. It is required that all fields of type PolicyLabled -- have a field/column policy -- if using only this low-level interface a -- runtime-error will occur if this is not satisfied. data RawPolicy l RawPolicy :: (Document l -> l) -> [(Key, FieldPolicy l)] -> RawPolicy l -- | A row (document) policy is a function from a Document to a -- Label. rawDocPolicy :: RawPolicy l -> Document l -> l -- | A column (field) policy is a function from a Document to a -- Label, for each field of type PolicyLabeled. rawFieldPolicies :: RawPolicy l -> [(Key, FieldPolicy l)] -- | A FieldPolicy specifies the policy-generated label of a -- field. SearchabelField specifies that the field can be -- referenced in the selection clause of a Query, and therefore -- the document label does not apply to it. data FieldPolicy l SearchableField :: FieldPolicy l FieldPolicy :: (Document l -> l) -> FieldPolicy l -- | Returns True if the policy is for a searchable field isSearchableField :: FieldPolicy l -> Bool -- | Field/column policies are required for every PolicyLabled -- value in a document. data PolicyError -- | Policy for field not specified NoFieldPolicy :: PolicyError -- | Policy application invalid InvalidPolicy :: PolicyError -- | Policy for Collection not specified NoColPolicy :: PolicyError -- | Field with associated policy is not of PolicyLabeled type InvalidFieldPolicyType :: PolicyError -- | Searchable fields cannot contain labeled values InvalidSearchableType :: PolicyError -- | Policy has been violated PolicyViolation :: PolicyError data Action l p s a -- | Get underlying database. getDatabase :: Action l p s (Database l) -- | Selects documents in specified collection that match the selector. data Selection l Selection :: Selector l -> CollectionName -> Selection l -- | Selector selector :: Selection l -> Selector l -- | Collection operaing coll :: Selection l -> CollectionName -- | Use select to create a basic query with defaults, then modify if -- desired. Example: (select sel col) {limit =: 10}. Note that -- unlike MongoDB's query functionality, our queries do not allow for -- projections (since policies may need a field that is not projects). -- Both the selection and sorting are restricted to searchable fields. -- -- TODO: add snapshot. data Query l Query :: [QueryOption] -> Selection l -> Word32 -> Limit -> Order l -> BatchSize -> Order l -> Query l -- | Query options, default []. options :: Query l -> [QueryOption] -- | WHERE clause,default []. selection :: Query l -> Selection l -- | Number of documents to skip, default 0. skip :: Query l -> Word32 -- | Max number of documents to return. Default, 0, means no limit. limit :: Query l -> Limit -- | Sort result by given order, default []. sort :: Query l -> Order l -- | The number of document to return in each batch response from the -- server. 0 means Mongo default. batchSize :: Query l -> BatchSize -- | Force mongoDB to use this index (must be only searchable fields). -- Default [], no hint. hint :: Query l -> Order l -- | A labeled cursor. The cursor is labeled with the join of the database -- and collection it reads from. data Cursor l -- | Database configuration, used to invoke withDB data DBConf type DCAction = Action DCLabel DCPrivTCB () -- | Open a pipe to a supplied server, or localhost. TODO: add -- support for connecting to replicas. dcAccess :: Database DCLabel -> DCAction a -> DC (Either Failure a) -- | The withDB functions should use this function to label their -- databases. TODO (DS/AL(: make every searchable field indexable. labelDatabase :: DBConf -> DCLabel -> DCLabel -> DC (Database DCLabel) -- | Policy modules are instances of this class. In particular, when an -- application accesses a database, the runtime invokes -- createDatabasePolicy in the appropriate policy module. class DatabasePolicy dbp createDatabasePolicy :: DatabasePolicy dbp => DBConf -> DCPrivTCB -> DC dbp policyDB :: DatabasePolicy dbp => dbp -> Database DCLabel -- | Class used to define groups in a policy-specific manner. class DatabasePolicy dbp => PolicyGroup dbp where expandGroup _ princ = return [princ] relabelGroups _ = return expandGroup :: PolicyGroup dbp => dbp -> Principal -> DCAction [Principal] relabelGroups :: PolicyGroup dbp => dbp -> DCLabeled a -> DC (DCLabeled a) -- | Looks for disjuctions the privilege is able to downgrade and rewrites -- them by invoking expandGroup on each principle in the -- disjuction. Using the result, the function relabels the Labeled -- value. Clients should not call this directly, instead clients should -- call relabelGroups which policies may implement by wrapping -- this function. relabelGroupsP :: PolicyGroup dbp => dbp -> DCPrivTCB -> Labeled DCLabel a -> DC (DCLabeled a) -- | A wrapper around relabelGroups that drops the current -- privileges and restores them after getting a result from -- relabelGroups. relabelGroupsSafe :: PolicyGroup dbp => dbp -> Labeled DCLabel a -> DC (DCLabeled a) -- | Class used to define policy-specifi privilege granting gate. class DatabasePolicy dbp => PrivilegeGrantGate dbp grantPriv :: PrivilegeGrantGate dbp => dbp -> Principal -> DC (DCGate DCPrivTCB) -- | Given a set of privileges, a desired label and action. Lower the -- current label as close tothe desired label as possible, execute the -- action and raise the current label. withLabel :: DCPrivTCB -> DCLabel -> DC a -> DC a -- | Given a set of privileges, a labeled document and computaiton on the -- (unlabeled version of the) documnet, downgrade the current label with -- the supplied privileges execute (only integrity), unlabel the document -- and apply the computation to it. The result is then labeled with the -- current label and the current label is reset to the original (if -- possible). gateToLabeled :: DCPrivTCB -> DCLabeled (Document DCLabel) -> (Document DCLabel -> DC a) -> DC (DCLabeled a) -- | Insert document into collection and return its _id value, -- which is created automatically if not supplied. It is required that -- the current label flow to the label of the collection and database -- (and vice versa). Additionally, the document must be well-formed with -- respect to the collection policy. In other words, all the labeled -- values must be below the collection clearance and the policy be -- applied successfully. insert :: Insert l p s doc => CollectionName -> doc -> Action l p s (Value l) -- | Same as insert except it does not return _id insert_ :: Insert l p s doc => CollectionName -> doc -> Action l p s () -- | Same as insert, but uses privileges when applying the -- collection policies, and doing label comparisons. insertP :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s (Value l) -- | Same as insertP except it does not return _id insertP_ :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s () -- | Update a document based on the _id value. The IFC -- requirements subsume those of insert. Specifically, in addition -- to being able to apply all the policies and requiring that the current -- label flow to the label of the collection and database save -- requires that the current label flow to the label of the existing -- database record. save :: Insert l p s doc => CollectionName -> doc -> Action l p s () -- | Like save, but uses privileges when performing label -- comparisons. saveP :: Insert l p s doc => p -> CollectionName -> doc -> Action l p s () -- | Given a query, delete first object in selection. In addition to being -- able to read the object, write to the database and collection, it must -- be that the current label flow to the label of the existing document. deleteOne :: (LabelState l p s, Serialize l) => Selection l -> Action l p s () -- | Same as deleteOne, but uses privileges when performing label -- comparisons. deleteOneP :: (LabelState l p s, Serialize l) => p -> Selection l -> Action l p s () -- | Fetch documents satisfying query. A labeled Cursor is returned, -- which can be used to retrieve the actual Documents. Current -- label is raised to the join of the collection, database, and -- ccollection-policy label. find :: (Serialize l, LabelState l p s) => Query l -> Action l p s (Cursor l) -- | Same as find, but uses privileges when raising the current -- label findP :: (Serialize l, LabelState l p s) => p -> Query l -> Action l p s (Cursor l) -- | Fetch the first document satisfying query, or Nothing if not -- documents matched the query. findOne :: (LabelState l p s, Serialize l) => Query l -> Action l p s (Maybe (LabeledDocument l)) -- | Same as findOne, but uses privileges when performing label -- comparisons. findOneP :: (LabelState l p s, Serialize l) => p -> Query l -> Action l p s (Maybe (LabeledDocument l)) -- | Return next document in query result, or Nothing if finished. -- The current label is raised to join of the current label and -- Cursor label. The document is labeled according to the -- underlying 'Collection'\'s policies. next :: (LabelState l p s, Serialize l) => Cursor l -> Action l p s (Maybe (LabeledDocument l)) -- | Same as next, but usess privileges raising the current label. nextP :: (LabelState l p s, Serialize l) => p -> Cursor l -> Action l p s (Maybe (LabeledDocument l)) -- | Query or Selection that selects documents in collection -- that match selector. The choice of end type depends on use, for -- example, in find select sel col is a Query, but -- in delete it is a Selection. select :: (Select selectionOrQuery, Label l) => Selector l -> CollectionName -> selectionOrQuery l -- | A connection failure, or a read or write exception like cursor expired -- or inserting a duplicate key. Note, unexpected data from the server is -- not a Failure, rather it is a programming error (you should call -- error in this case) because the client and server are -- incompatible and requires a programming change. data Failure :: * -- | Trusted transformer that takes a Labeled tuple with -- HttpReq and the request body as a ByteString and returns -- a Labeled Document with keys and values corresponding to -- the form fields from the request. The label on the Labeled -- result is the same as input. Arguments values are parsed in to BSON -- Strings except if the key is of the form "key_name[]" in which case -- all such arguments will be combined into an array of Strings. labeledDocI :: LabelState l p s => HttpReq a -> Labeled l ByteString -> LIO l p s (Labeled l (Document l)) module Hails.Policy module Hails.Database.MongoDB.Structured -- | Class for converting from "structured" records to documents (and vice -- versa). class DCRecord a where findBy = findByP noPrivs findWhere = findWhereP noPrivs insertRecord = insertRecordP noPrivs saveRecord = saveRecordP noPrivs deleteBy = deleteByP noPrivs deleteWhere = deleteWhereP noPrivs insertRecordP p policy record = do { let colName = collectionName record; p' <- getPrivileges; withDB policy $ insertP (p' `mappend` p) colName $ toDocument record } saveRecordP p policy record = do { let colName = collectionName record; p' <- getPrivileges; withDB policy $ saveP (p' `mappend` p) colName $ toDocument record } findByP p policy colName k v = findWhereP p policy (select [k =: v] colName) findWhereP p policy query = do { result <- withDB policy $ findOneP p query; c <- getClearance; case result of { Right (Just r) | leqp p (labelOf r) c -> fromDocument `liftM` unlabelP p r _ -> return Nothing } } deleteByP p policy colName k v = deleteWhereP p policy (select [k =: v] colName) deleteWhereP p policy sel = do { mdoc <- findWhereP p policy $ select (selector sel) (coll sel); p' <- getPrivileges; res <- withDB policy $ deleteOneP (p' `mappend` p) sel; case res of { Right _ -> return mdoc _ -> return Nothing } } fromDocument :: (DCRecord a, Monad m) => Document DCLabel -> m a toDocument :: DCRecord a => a -> Document DCLabel collectionName :: DCRecord a => a -> CollectionName findBy :: (DCRecord a, Val DCLabel v, DatabasePolicy p) => p -> CollectionName -> Key -> v -> DC (Maybe a) findWhere :: (DCRecord a, DatabasePolicy p) => p -> Query DCLabel -> DC (Maybe a) insertRecord :: (DCRecord a, DatabasePolicy p) => p -> a -> DC (Either Failure (Value DCLabel)) saveRecord :: (DCRecord a, DatabasePolicy p) => p -> a -> DC (Either Failure ()) deleteBy :: (DCRecord a, Val DCLabel v, DatabasePolicy p) => p -> CollectionName -> Key -> v -> DC (Maybe a) deleteWhere :: (DCRecord a, DatabasePolicy p) => p -> Selection DCLabel -> DC (Maybe a) findByP :: (DCRecord a, Val DCLabel v, DatabasePolicy p) => DCPrivTCB -> p -> CollectionName -> Key -> v -> DC (Maybe a) findWhereP :: (DCRecord a, DatabasePolicy p) => DCPrivTCB -> p -> Query DCLabel -> DC (Maybe a) insertRecordP :: (DCRecord a, DatabasePolicy p) => DCPrivTCB -> p -> a -> DC (Either Failure (Value DCLabel)) saveRecordP :: (DCRecord a, DatabasePolicy p) => DCPrivTCB -> p -> a -> DC (Either Failure ()) deleteByP :: (DCRecord a, Val DCLabel v, DatabasePolicy p) => DCPrivTCB -> p -> CollectionName -> Key -> v -> DC (Maybe a) deleteWhereP :: (DCRecord a, DatabasePolicy p) => DCPrivTCB -> p -> Selection DCLabel -> DC (Maybe a) -- | Class for inserting and saving labeled records. class DCRecord a => DCLabeledRecord a where insertLabeledRecord = insertLabeledRecordP noPrivs saveLabeledRecord = saveLabeledRecordP noPrivs insertLabeledRecordP p policy lrecord = do { let colName = collectionName (forceType lrecord); p' <- getPrivileges; ldoc <- mkToLabeledDocument policy lrecord; withDB policy $ insertP (p' `mappend` p) colName ldoc } saveLabeledRecordP p policy lrecord = do { let colName = collectionName (forceType lrecord); p' <- getPrivileges; ldoc <- mkToLabeledDocument policy lrecord; withDB policy $ saveP (p' `mappend` p) colName ldoc } insertLabeledRecord :: (DCLabeledRecord a, MkToLabeledDocument p) => p -> DCLabeled a -> DC (Either Failure (Value DCLabel)) saveLabeledRecord :: (DCLabeledRecord a, MkToLabeledDocument p) => p -> DCLabeled a -> DC (Either Failure ()) insertLabeledRecordP :: (DCLabeledRecord a, MkToLabeledDocument p) => DCPrivTCB -> p -> DCLabeled a -> DC (Either Failure (Value DCLabel)) saveLabeledRecordP :: (DCLabeledRecord a, MkToLabeledDocument p) => DCPrivTCB -> p -> DCLabeled a -> DC (Either Failure ()) -- | Classe used by a database policy to translate a labeled record to a -- labeled document. class DatabasePolicy p => MkToLabeledDocument p mkToLabeledDocument :: (MkToLabeledDocument p, DCRecord a) => p -> DCLabeled a -> DC (DCLabeled (Document DCLabel)) -- | Same as toDocument but for uses the policy's privileges to -- convert a labeled record to a labeled document. toDocumentP :: DCRecord a => DCPrivTCB -> DCLabeled a -> DC (DCLabeled (Document DCLabel))