         out (chan)
         local-users {"user@mail.com" "P4ssw0rd"
                      "eve@mail.com" "lisp"
-                     "john" "satan"}
+                     "john" "haskell"}
         input-users {"user@mail.com" "P4ssw0rd"
                      "eve@mail.com" "lispo"
-                     "john" "satan"}
+                     "john" "haskell"}
         [new-in new-out] (auth (<!! (new-mem-store (atom
                                                     {"john" {42 {:id 42
                                                                  :causal-order {1 []}

;;     The user is now logged in, and doesn’t have to repeat this process again until their token expires or they want to authenticate on a new device.

(defn- meta-published [pub-ch store trusted-hosts sessions [new-in out]]
  (go-loop [{:keys [metas] :as p} (<! pub-ch)]
    (let [nc (<! (new-commits! store metas))]
      (<! (go-loop [counter 0]
            (let [not-auth (filter #(not (@sessions (:user %))) nc)]
              (if (empty? not-auth)
                (do
                  (>! new-in (assoc p ::authed true :users (set (keys @sessions))))
                  ) ;; annotate authenticated user(s)
                (do
                  (>! out {:topic ::auth-required :users (set (map :user not-auth))})
                  (<! (go-loop [p (<! pub-ch)]
                        (if (= (:topic p) ::authed)
                          (do
                            (println "AUTHED" p)
                            (swap! sessions (fn [old new] (apply assoc old new)) (:users p)))
                          (recur (<! pub-ch)))))
                  (if (> counter 5)
                    (do
                      (println "AUTH-FAILED" (set (map :user not-auth)))
                      (>! out {:topic ::auth-failed :users (set (map :user not-auth)) :sessions @sessions}))
                    (recur (inc counter)))))))))
    (recur (<! pub-ch))))


(defn- auth-required [auth-req-ch auth-fn out]
  (go-loop [{:keys [users] :as a} (<! auth-req-ch)]
    (when a
      (println "AUTH-REQ" a)
      (>! out
        {:topic ::auth
         :users (<! (auth-fn users))})
      (recur (<! auth-req-ch)))))


(defn- authenticated [auth-ch credential-fn out]
  (go-loop [a (<! auth-ch)]
    (when a
      (println "AUTH" a)
      (>! out
        {:topic
         ::authed
         :users
         (->> (:users a)
              (map
               (fn [[k v]]
                 (vec [k
                       (if (credential-fn {:username k :password v})
                         (-> {(uuid) (java.util.Date.)})
                         nil)])))
              flatten)})
      (recur (<! auth-ch)))))



                                  :branches {"master" #{2}}
                                  :schema {:type :geschichte
                                           :version 1}}}}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "häskell"}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "häskell"}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "häskell"}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "häskell"}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "häskell"}})
      (println "OUT" (<! out))
      (>! in {:topic :meta-pub,
              :peer "STAGE",
              :metas {"john" {42 {:id 42
                                  :causal-order {1 []
                                                 2 [1]}
                                  :last-update (java.util.Date. 0)
                                  :description "Bookmark collection."
                                  :head "master"
                                  :branches {"master" #{2}}
                                  :schema {:type :geschichte
                                           :version 1}}}}})
      (println "OUT" (<! out))
      (>! in {:topic ::auth :users {"john" "haskell"}})
      (println "OUT" (<! out))
      ))


  (println "\n")


