Fork me on GitHub
#datascript
<
2016-05-19
>
taylor.sando08:05:36

I think om next provides a good example of how to pass messages, and make requests. You can specify reads and mutations using the syntax. The datomic-style pull syntax can be parsed recursively, so that when you want a specific entity, it can potentially grab information from a separate service. For security in datomic, my approach has been to make sure that there is a model/type attribute that is tied to an enum. That way, every entity has a model type. For transactions, I have a transact pipeline. It will take a raw datomic transaction vector, and it will use d/with to make the transaction. The transaction is associated with a user token (from a cookie/header). It goes through the tx-report and categories the models and attrbutes as created/updated/removed. It then validates the domain of the tx, i.e. make sure what was created is a valid model, or what was updated still makes it a valid model. You then run it through a permissions function, which checks the new/updated/removed attributes and whether the user token specified is allowed to do what it did. It finally calls the post-tx functions, which are called so that they can either do more validation, or more likely add additional information to the transaction, such as adding uuid ids to the entities. On the read side, the specified user token can be used to determine the user's permissions, which can be used to build a filter function, which can be placed on the database. Then you can request whatever you want. I know they are talking about a data model layer in Arachne, so perhaps something will come out of that.

Dustin Getz14:05:15

@taylor.sando: Do you have a snippet of code anywhere that demos the transaction security enforcer, and also the filter function? I don’t have a mental picture of how to implement them, at least not in a way that doesn’t limit the security rules one can express

taylor.sando14:05:32

I define models like this:

taylor.sando14:05:35

(def model
  {:name :node
   :fields {: : 
            :prerequisite {:type :ref
                           :optional? true
                           :cardinality :many
                           :ref [:node]
                           :doc "The nodes that should be understood before this"}
            :uri/uri :uri
            :resource/eid :resource
            :tag/list :tag}})

taylor.sando14:05:11

(def model
  {:name :resource
   :fields {:eid {:type :uuid
                  :unique :identity
                  :optional? true
                  :doc "A unique external id that can be presented to the outside world"}}
   #?(:clj :post-tx-handlers) 
   #?(:clj
      {[:* :added] (fn [{:keys [db-id->tmp-id] :as tx-map} {:keys [new]}]
                     (when-not (= (:model/type new) :access-token/model)
                       [{:db/id (get db-id->tmp-id (:db/id new)) 
                         :resource/eid (d/squuid)}])
                     )})
   })

taylor.sando14:05:43

I tried to define models in a way that you could use them on datomic and datascript.

taylor.sando14:05:05

The complexity of security rules depends how much control you need to give the user's, especially if they are defining their own rules. You should be able to just use the datomic filter function, and check the entity/attr/value and see if you want to allow it or not, depending on who is requesting it.

Dustin Getz14:05:01

in larger systems, visibility rules are determined by dynamically adding a bunch of where clauses, its not clear to me how that can be encoded as a filter, you need to actually resolve datalog queries, am i looking at this wrong?

Dustin Getz14:05:58

you can’t look at a datom in isolation, you need to look at it in the context of a bunch of other entities

taylor.sando14:05:42

The datomic filter function gives you the database and the datom. You can use the database and the datom to look stuff up.

taylor.sando14:05:36

The query, or entity when looking at the filtered database is just passing potential datoms through the filter-db function before it returns anything. Either the datom is allowed, or it isn't allowed.

taylor.sando14:05:59

I mean you pass a filtered db to a datomic.api/q or datomic.api/enttiy

Dustin Getz14:05:33

are you saying that d/q can be (is) implemented in terms of filter-db?

taylor.sando14:05:03

Yes, d/q, d/entity and d/pull