diff options
author | Holger Weiss <holger@zedat.fu-berlin.de> | 2018-04-16 23:18:03 +0200 |
---|---|---|
committer | Holger Weiss <holger@zedat.fu-berlin.de> | 2018-04-16 23:18:03 +0200 |
commit | de7dc4affa6c6996bed838b5d4b0b53511962ef0 (patch) | |
tree | fdf6face73b13b9af6eaa9fc1153332dc48680d6 /src | |
parent | mod_http_upload*: Remove empty lines after specs (diff) |
mod_push: Optionally include message sender/body
Add 'include_sender' and 'include_body' options. If one or both of them
are set to 'true', a urn:xmpp:push:summary form with the enabled
field(s) is included in push notifications that are generated for
messages with a body.
The 'include_body' option can instead be set to a static text. In this
case, the specified text will be included in place of the actual message
body. This can be useful to signal the push service whether the
notification was triggered by a message with body (as opposed to other
types of traffic) without leaking actual message contents.
Diffstat (limited to 'src')
-rw-r--r-- | src/mod_push.erl | 113 | ||||
-rw-r--r-- | src/mod_push_keepalive.erl | 4 |
2 files changed, 100 insertions, 17 deletions
diff --git a/src/mod_push.erl b/src/mod_push.erl index 40cfaa625..dd16e87fa 100644 --- a/src/mod_push.erl +++ b/src/mod_push.erl @@ -44,7 +44,7 @@ -export([get_commands_spec/0, delete_old_sessions/1]). %% API (used by mod_push_keepalive). --export([notify/1, notify/3, notify/5]). +-export([notify/2, notify/4, notify/6]). %% For IQ callbacks -export([delete_session/3]). @@ -125,6 +125,12 @@ depends(_Host, _Opts) -> []. -spec mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()]. +mod_opt_type(include_sender) -> + fun (B) when is_boolean(B) -> B end; +mod_opt_type(include_body) -> + fun (B) when is_boolean(B) -> B; + (S) -> iolist_to_binary(S) + end; mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(O) when O == cache_life_time; O == cache_size -> @@ -136,7 +142,9 @@ mod_opt_type(O) when O == use_cache; O == cache_missed -> -spec mod_options(binary()) -> [{atom(), any()}]. mod_options(Host) -> - [{db_type, ejabberd_config:default_db(Host, ?MODULE)}, + [{include_sender, false}, + {include_body, false}, + {db_type, ejabberd_config:default_db(Host, ?MODULE)}, {use_cache, ejabberd_config:use_cache(Host)}, {cache_size, ejabberd_config:cache_size(Host)}, {cache_missed, ejabberd_config:cache_missed(Host)}, @@ -336,9 +344,9 @@ disable(#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID, c2s_stanza(State, #stream_error{}, _SendResult) -> State; c2s_stanza(#{push_enabled := true, mgmt_state := pending} = State, - _Pkt, _SendResult) -> + Pkt, _SendResult) -> ?DEBUG("Notifying client of stanza", []), - notify(State), + notify(State, Pkt), State; c2s_stanza(State, _Pkt, _SendResult) -> State. @@ -351,7 +359,7 @@ mam_message(#message{} = Pkt, LUser, LServer, _Peer, chat, _Dir) -> case drop_online_sessions(LUser, LServer, Clients) of [_|_] = Clients1 -> ?DEBUG("Notifying ~s@~s of MAM message", [LUser, LServer]), - notify(LUser, LServer, Clients1); + notify(LUser, LServer, Clients1, Pkt); [] -> ok end; @@ -369,7 +377,7 @@ offline_message(#message{to = #jid{luser = LUser, lserver = LServer}} = Pkt) -> case lookup_sessions(LUser, LServer) of {ok, [_|_] = Clients} -> ?DEBUG("Notifying ~s@~s of offline message", [LUser, LServer]), - notify(LUser, LServer, Clients); + notify(LUser, LServer, Clients, Pkt); _ -> ok end, @@ -380,7 +388,8 @@ c2s_session_pending(#{push_enabled := true, mgmt_queue := Queue} = State) -> case p1_queue:len(Queue) of Len when Len > 0 -> ?DEBUG("Notifying client of unacknowledged stanza(s)", []), - notify(State), + Pkt = queue_find(fun is_message_with_body/1, Queue), + notify(State, Pkt), State; 0 -> State @@ -412,17 +421,18 @@ remove_user(LUser, LServer) -> %%-------------------------------------------------------------------- %% Generate push notifications. %%-------------------------------------------------------------------- --spec notify(c2s_state()) -> ok. -notify(#{jid := #jid{luser = LUser, lserver = LServer}, sid := {TS, _}}) -> +-spec notify(c2s_state(), xmpp_element() | xmlel() | none) -> ok. +notify(#{jid := #jid{luser = LUser, lserver = LServer}, sid := {TS, _}}, Pkt) -> case lookup_session(LUser, LServer, TS) of {ok, Client} -> - notify(LUser, LServer, [Client]); + notify(LUser, LServer, [Client], Pkt); _Err -> ok end. --spec notify(binary(), binary(), [push_session()]) -> ok. -notify(LUser, LServer, Clients) -> +-spec notify(binary(), binary(), [push_session()], + xmpp_element() | xmlel() | none) -> ok. +notify(LUser, LServer, Clients, Pkt) -> lists:foreach( fun({TS, PushLJID, Node, XData}) -> HandleResponse = fun(#iq{type = result}) -> @@ -433,14 +443,16 @@ notify(LUser, LServer, Clients) -> (timeout) -> ok % Hmm. end, - notify(LServer, PushLJID, Node, XData, HandleResponse) + notify(LServer, PushLJID, Node, XData, Pkt, HandleResponse) end, Clients). -spec notify(binary(), ljid(), binary(), xdata(), + xmpp_element() | xmlel() | none, fun((iq() | timeout) -> any())) -> ok. -notify(LServer, PushLJID, Node, XData, HandleResponse) -> +notify(LServer, PushLJID, Node, XData, Pkt, HandleResponse) -> From = jid:make(LServer), - Item = #ps_item{sub_els = [#push_notification{}]}, + Summary = make_summary(LServer, Pkt), + Item = #ps_item{sub_els = [#push_notification{xdata = Summary}]}, PubSub = #pubsub{publish = #ps_publish{node = Node, items = [Item]}, publish_options = XData}, IQ = #iq{type = set, @@ -571,6 +583,77 @@ drop_online_sessions(LUser, LServer, Clients) -> [Client || {TS, _, _, _} = Client <- Clients, lists:keyfind(TS, 1, SessIDs) == false]. +-spec queue_find(fun((stanza()) -> boolean()), p1_queue:queue()) + -> stanza() | none. +queue_find(Pred, Queue) -> + case p1_queue:out(Queue) of + {{value, {_, _, Pkt}}, Queue1} -> + case Pred(Pkt) of + true -> + Pkt; + false -> + queue_find(Pred, Queue1) + end; + {empty, _Queue1} -> + none + end. + +-spec make_summary(binary(), xmpp_element() | xmlel() | none) + -> xdata() | undefined. +make_summary(Host, #message{from = From} = Pkt) -> + case {gen_mod:get_module_opt(Host, ?MODULE, include_sender), + gen_mod:get_module_opt(Host, ?MODULE, include_body)} of + {false, false} -> + undefined; + {IncludeSender, IncludeBody} -> + case get_body_text(Pkt) of + none -> + undefined; + Text -> + Fields1 = case IncludeBody of + StaticText when is_binary(StaticText) -> + [{'last-message-body', StaticText}]; + true -> + [{'last-message-body', Text}]; + false -> + [] + end, + Fields2 = case IncludeSender of + true -> + [{'last-message-sender', From} | Fields1]; + false -> + Fields1 + end, + #xdata{type = submit, fields = push_summary:encode(Fields2)} + end + end; +make_summary(_Host, _Pkt) -> + undefined. + +-spec is_message_with_body(stanza()) -> boolean(). +is_message_with_body(#message{} = Msg) -> + get_body_text(Msg) /= none; +is_message_with_body(_Stanza) -> + false. + +-spec get_body_text(message()) -> binary() | none. +get_body_text(#message{body = Body} = Msg) -> + case xmpp:get_text(Body) of + Text when byte_size(Text) > 0 -> + Text; + <<>> -> + case body_is_encrypted(Msg) of + true -> + <<"(encrypted)">>; + false -> + none + end + end. + +-spec body_is_encrypted(message()) -> boolean(). +body_is_encrypted(#message{sub_els = SubEls}) -> + lists:keyfind(<<"encrypted">>, #xmlel.name, SubEls) /= false. + %%-------------------------------------------------------------------- %% Caching. %%-------------------------------------------------------------------- diff --git a/src/mod_push_keepalive.erl b/src/mod_push_keepalive.erl index 750427ee1..7c1815c02 100644 --- a/src/mod_push_keepalive.erl +++ b/src/mod_push_keepalive.erl @@ -184,7 +184,7 @@ c2s_handle_cast(State, _Msg) -> c2s_handle_info(#{push_enabled := true, mgmt_state := pending, jid := JID} = State, {timeout, _, push_keepalive}) -> ?INFO_MSG("Waking ~s before session times out", [jid:encode(JID)]), - mod_push:notify(State), + mod_push:notify(State, none), {stop, State}; c2s_handle_info(State, _) -> State. @@ -229,7 +229,7 @@ wake_all(LServer) -> IgnoreResponse = fun(_) -> ok end, lists:foreach(fun({_, PushLJID, Node, XData}) -> mod_push:notify(LServer, PushLJID, Node, - XData, IgnoreResponse) + XData, none, IgnoreResponse) end, Sessions); error -> error |