group admin, leave-group action

This commit is contained in:
michaelr 2016-03-11 16:59:20 +02:00
parent cf52d8ddf4
commit 4e9c22c9fc
6 changed files with 161 additions and 77 deletions

View File

@ -12,13 +12,17 @@
get-keypair
get-peer-identities
get-identities
save-identities]]
save-identities
save-group-admin
group-admin?
remove-group-data]]
[syng-im.protocol.delivery :refer [start-delivery-loop]]
[syng-im.protocol.web3 :refer [listen
make-msg
post-msg
make-web3
new-identity]]
new-identity
stop-listener]]
[syng-im.protocol.handler :refer [handle-incoming-whisper-msg]]
[syng-im.protocol.user-handler :refer [invoke-user-handler]]
[syng-im.utils.encryption :refer [new-keypair]]
@ -27,7 +31,8 @@
group-add-participant-msg
group-remove-participant-msg
removed-from-group-msg]]
[syng-im.protocol.defaults :refer [default-content-type]])
[syng-im.protocol.defaults :refer [default-content-type]]
[syng-im.utils.logging :as log])
(:require-macros [cljs.core.async.macros :refer [go]]))
(defn create-connection [ethereum-rpc-url]
@ -49,7 +54,7 @@
:event-type can be:
:new-msg - [from payload]
:new-group-msg [from payload]
:new-group-msg [from group-id payload]
:error - [error-msg details]
:msg-acked [msg-id from]
:delivery-failed [msg-id]
@ -58,6 +63,7 @@
:group-new-participant [identity group-id]
:group-removed-participant [from identity group-id]
:removed-from-group [from group-id]
:participant-left-group [from group-id]
:initialized [identity]
:new-msg, new-group-msg, msg-acked should be handled idempotently (may be called multiple times for the same msg-id)
@ -93,7 +99,8 @@
:payload {:content content
:content-type default-content-type}}))
(defn start-group-chat [identities]
(defn start-group-chat
[identities]
(let [group-topic (random/id)
keypair (new-keypair)
store (storage)
@ -103,6 +110,7 @@
(conj my-identity))]
(save-keypair store group-topic keypair)
(save-identities store group-topic identities)
(save-group-admin store group-topic my-identity)
(listen connection handle-incoming-whisper-msg {:topics [group-topic]})
(doseq [ident identities :when (not (= ident my-identity))]
(let [{:keys [msg-id msg]} (init-group-chat-msg ident group-topic identities keypair)]
@ -110,37 +118,56 @@
(post-msg connection msg)))
group-topic))
(defn group-add-participant [group-id new-peer-identity]
(let [store (storage)
connection (connection)
identities (-> (get-identities store group-id)
(conj new-peer-identity))
keypair (get-keypair store group-id)]
(save-identities store group-id identities)
(let [{:keys [msg-id msg]} (group-add-participant-msg new-peer-identity group-id identities keypair)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg))
(send-group-msg {:group-id group-id
:type :group-new-participant
:payload {:identity new-peer-identity}
:internal? true})))
(defn group-remove-participant [group-id identity-to-remove]
(defn group-add-participant
"Only call if you are the group-admin"
[group-id new-peer-identity]
(let [store (storage)
connection (connection)
identities (-> (get-identities store group-id)
(disj identity-to-remove))
keypair (new-keypair)
my-identity (my-identity)]
(save-identities store group-id identities)
(save-keypair store group-id keypair)
(doseq [ident identities :when (not (= ident my-identity))]
(let [{:keys [msg-id msg]} (group-remove-participant-msg ident group-id keypair identity-to-remove)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg)))
(let [{:keys [msg-id msg]} (removed-from-group-msg group-id identity-to-remove)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg))))
(if-not (group-admin? store group-id my-identity)
(log/error "Called group-add-participant but not group admin, group-id:" group-id "my-identity:" my-identity)
(let [connection (connection)
identities (-> (get-identities store group-id)
(conj new-peer-identity))
keypair (get-keypair store group-id)]
(save-identities store group-id identities)
(let [{:keys [msg-id msg]} (group-add-participant-msg new-peer-identity group-id identities keypair)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg))
(send-group-msg {:group-id group-id
:type :group-new-participant
:payload {:identity new-peer-identity}
:internal? true})))))
(defn group-remove-participant
"Only call if you are the group-admin"
[group-id identity-to-remove]
(let [store (storage)
my-identity (my-identity)]
(if-not (group-admin? store group-id my-identity)
(log/error "Called group-remove-participant but not group admin, group-id:" group-id "my-identity:" my-identity)
(let [connection (connection)
identities (-> (get-identities store group-id)
(disj identity-to-remove))
keypair (new-keypair)]
(save-identities store group-id identities)
(save-keypair store group-id keypair)
(doseq [ident identities :when (not (= ident my-identity))]
(let [{:keys [msg-id msg]} (group-remove-participant-msg ident group-id keypair identity-to-remove)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg)))
(let [{:keys [msg-id msg]} (removed-from-group-msg group-id identity-to-remove)]
(add-pending-message msg-id msg {:internal? true})
(post-msg connection msg))))))
(defn leave-group-chat [group-id]
(let [store (storage)
my-identity (my-identity)]
(send-group-msg {:group-id group-id
:type :left-group
:payload {:identity my-identity}
:internal? true})
(remove-group-data store group-id)
(stop-listener group-id)))
(defn current-connection []
(connection))

View File

@ -13,8 +13,8 @@
:encrypt? true
:public-key public-key
:payload payload
:clear-info {:group-id group-id
:type type}}))
:clear-info {:group-topic group-id
:type type}}))
(defn send-group-msg [{:keys [group-id payload type internal?] :or {internal? false}}]
(let [store (storage)

View File

@ -11,7 +11,11 @@
chat-exists?
get-keypair
add-identity
remove-group-data]]
remove-group-data
save-group-admin
group-admin?
remove-identity
group-member?]]
[syng-im.protocol.web3 :refer [to-ascii
make-msg
post-msg
@ -57,65 +61,82 @@
(listen web3 handle-incoming-whisper-msg {:topics [group-topic]})
(save-keypair store group-topic keypair)
(save-identities store group-topic identities)
(save-group-admin store group-topic from)
(invoke-user-handler :new-group-chat {:from from
:identities identities
:group-id group-topic}))))
(defn decrypt-group-msg [group-id encrypted-payload]
(defn decrypt-group-msg [group-topic encrypted-payload]
(let [store (storage)
{private-key :private} (get-keypair store group-id)]
{private-key :private} (get-keypair store group-topic)]
(-> (decrypt private-key encrypted-payload)
(read-string)
(assoc :group-id group-id))))
(assoc :group-topic group-topic))))
(defn handle-group-user-msg [web3 from {:keys [enc-payload group-id]}]
(let [{:keys [msg-id] :as payload} (decrypt-group-msg group-id enc-payload)]
(send-ack web3 from msg-id)
(invoke-user-handler :new-group-msg {:from from
:payload payload})))
(defn handle-group-user-msg [web3 from {:keys [msg-id group-topic] :as payload}]
(send-ack web3 from msg-id)
(invoke-user-handler :new-group-msg {:from from
:group-id group-topic
:payload payload}))
(defn handle-group-new-participant [web3 from {:keys [enc-payload group-id]}]
(let [store (storage)
{:keys [msg-id identity]} (decrypt-group-msg group-id enc-payload)]
(send-ack web3 from msg-id)
(add-identity store group-id identity)
(invoke-user-handler :group-new-participant {:identity identity
:group-id group-id
:from from})))
(defn handle-group-new-participant [web3 from {:keys [msg-id identity group-topic]}]
(let [store (storage)]
(if (group-admin? store group-topic from)
(do
(send-ack web3 from msg-id)
(when-not (group-member? store group-topic identity)
(add-identity store group-topic identity)
(invoke-user-handler :group-new-participant {:identity identity
:group-id group-topic
:from from})))
(log/warn "Ignoring group-new-participant for group" group-topic "from a non group-admin user" from))))
(defn handle-group-removed-participant [web3 from {:keys [keypair group-topic msg-id removed-identity]}]
(let [store (storage)
identities (get-identities store group-topic)]
(if (get identities from)
(let [store (storage)]
(if (group-admin? store group-topic from)
(do
(send-ack web3 from msg-id)
(save-keypair store group-topic keypair)
(->> (disj identities removed-identity)
(save-identities store group-topic))
(invoke-user-handler :group-removed-participant {:identity removed-identity
:group-id group-topic
:from from}))
(log/warn "Got group-removed-participant message from" from "who is not part the group" group-topic))))
(when (group-member? store group-topic removed-identity)
(save-keypair store group-topic keypair)
(remove-identity store group-topic removed-identity)
(invoke-user-handler :group-removed-participant {:identity removed-identity
:group-id group-topic
:from from})))
(log/warn "Ignoring group-removed-participant for group" group-topic "from a non group-admin user" from))))
(defn handle-removed-from-group [web3 from {:keys [group-topic msg-id]}]
(let [store (storage)
identities (get-identities store group-topic)]
(if (get identities from)
(let [store (storage)]
(if (group-admin? store group-topic from)
(do
(send-ack web3 from msg-id)
(remove-group-data store group-topic)
(stop-listener group-topic)
(invoke-user-handler :removed-from-group {:group-id group-topic
:from from}))
(log/warn "Got removed-from-group message from" from "who is not part the group" group-topic))))
(when (group-member? store group-topic (state/my-identity))
(remove-group-data store group-topic)
(stop-listener group-topic)
(invoke-user-handler :removed-from-group {:group-id group-topic
:from from})))
(log/warn "Ignoring removed-from-group for group" group-topic "from a non group-admin user" from))))
(defn handle-participant-left-group [web3 from {:keys [group-topic msg-id]}]
(let [store (storage)]
(send-ack web3 from msg-id)
(when (group-member? store group-topic from)
(remove-identity store group-topic from)
(invoke-user-handler :participant-left-group {:group-id group-topic
:from from}))))
(defn handle-group-msg [web3 msg-type from {:keys [enc-payload group-topic]}]
(let [payload (decrypt-group-msg group-topic enc-payload)]
(case msg-type
:group-user-msg (handle-group-user-msg web3 from payload)
:group-new-participant (handle-group-new-participant web3 from payload)
:left-group (handle-participant-left-group web3 from payload))))
(defn handle-incoming-whisper-msg [web3 msg]
(log/info "Got whisper message:" msg)
(let [{from :from
to :to
topics :topics ;; always empty (bug in go-ethereum?)
payload :payload
:as msg} (js->clj msg :keywordize-keys true)]
payload :payload} (js->clj msg :keywordize-keys true)]
(if (or (= to "0x0")
(= to (state/my-identity)))
(let [{msg-type :type :as payload} (->> (to-ascii payload)
@ -124,8 +145,9 @@
:ack (handle-ack from payload)
:user-msg (handle-user-msg web3 from payload)
:init-group-chat (handle-new-group-chat web3 from payload)
:group-user-msg (handle-group-user-msg web3 from payload)
:group-new-participant (handle-group-new-participant web3 from payload)
:group-removed-participant (handle-group-removed-participant web3 from payload)
:removed-from-group (handle-removed-from-group web3 from payload)))
:removed-from-group (handle-removed-from-group web3 from payload)
:group-user-msg (handle-group-msg web3 msg-type from payload)
:group-new-participant (handle-group-msg web3 msg-type from payload)
:left-group (handle-group-msg web3 msg-type from payload)))
(log/warn "My identity:" (state/my-identity) "Message To:" to "Message is encrypted for someone else, ignoring"))))

View File

@ -8,6 +8,9 @@
(defn topic-identities-key [topic]
(str "group-chat.topic-identities." topic))
(defn topic-admin-ident-key [topic]
(str "group-chat.topic-admin-ident." topic))
(defn save-keypair [storage topic keypair]
(let [key (topic-keypair-key topic)]
(s/put storage key keypair)))
@ -26,6 +29,16 @@
(->> (conj identities identity)
(save-identities storage topic)))))
(defn remove-identity [storage topic identity]
(let [identities (get-identities storage topic)]
(when (contains? identities identity)
(->> (disj identities identity)
(save-identities storage topic)))))
(defn group-member? [storage topic identity]
(let [identities (get-identities storage topic)]
(contains? identities identity)))
(defn get-peer-identities [storage topic]
(-> (get-identities storage topic)
(disj (state/my-identity))))
@ -42,4 +55,12 @@
(let [keypair-key (topic-keypair-key topic)
identities-key (topic-identities-key topic)]
(s/delete storage keypair-key)
(s/delete storage identities-key)))
(s/delete storage identities-key)))
(defn save-group-admin [storage topic identity]
(let [key (topic-admin-ident-key topic)]
(s/put storage key identity)))
(defn group-admin? [storage topic identity]
(let [key (topic-admin-ident-key topic)]
(= identity (s/get storage key))))

View File

@ -74,6 +74,9 @@
<button id="add-peer-button">Add Participant</button>
<button id="remove-peer-button">Remove Participant</button>
</div>
<div>
<button id="leave-group-button">Leave Group</button>
</div>
</div>
<script src="js/compiled/syng_im.js" type="text/javascript"></script>
</body>

View File

@ -107,6 +107,8 @@
(remove-identity-from-group-list identity))
:removed-from-group (let [{:keys [group-id from]} event]
(add-to-chat "group-chat" ":" (str (shorten from) " removed you from group chat")))
:participant-left-group (let [{:keys [group-id from]} event]
(add-to-chat "group-chat" ":" (str (shorten from) " left group chat")))
(add-to-chat "chat" ":" (str "Don't know how to handle " event-type))))})
(e/listen (-> (g/getElement "msg")
(goog.events.KeyHandler.))
@ -153,6 +155,10 @@
(remove-identity-from-group-list removed-identity)
(p/group-remove-participant group-id removed-identity)))
(defn leave-group []
(let [group-id (:group-id @state)]
(p/leave-group-chat group-id)))
(let [button (g/getElement "connect-button")]
(e/listen button EventType/CLICK
(fn [e]
@ -176,6 +182,11 @@
(fn [e]
(remove-peer-from-group))))
(let [button (g/getElement "leave-group-button")]
(e/listen button EventType/CLICK
(fn [e]
(leave-group))))
(comment
(p/init-protocol {:ethereum-rpc-url "http://localhost:4546"