From bf98fa0c016387165726ac79963f0ceb0556a219 Mon Sep 17 00:00:00 2001 From: Eric Cestari Date: Tue, 7 Sep 2010 14:35:40 +0200 Subject: [PATCH] Added node creation with configure form Added deletion Better behavior in case of a crash (returns 500) --- doc/http_post.md | 42 +++++++++++++++++++--- src/mod_pubsub/mod_pubsub.erl | 1 + src/web/pshb_http.erl | 68 ++++++++++++++++++++++++----------- 3 files changed, 86 insertions(+), 25 deletions(-) diff --git a/doc/http_post.md b/doc/http_post.md index 90242e9b9..cbddb4d5c 100644 --- a/doc/http_post.md +++ b/doc/http_post.md @@ -13,33 +13,67 @@ Also, in the ejabberd_http handler configuration, add the identified line. {request_handlers, [{["pshb"], pshb_http}]} % this should be added ]} +## Important notice ## + +In the current version of the code, some security checks are not done : + + * read operations can all be done without authentication + + * node creation uses the default `all` access_createnode acl, not checking for the actual configuration. + ## Usage example with cURL ## ### Getting the service document ### No authentication necessary. All nodes are listed. - curl -i http://:/pshb// + curl -i http://host:port/pshb/domain/ ### Getting items from a node ### No authentication done, and all nodes are accessible. - curl -i http://:/pshb/// + curl -i http://host:port/pshb/domain/node/ ### Posting a new item ### - curl -u : -i -X POST -d @entry.atom http://:/pshb// + curl -u jid:password -i -X POST -d @entry.atom http://post:port/pshb/domain/node User ability to post is based on node configuration. ### Creating a new node ### -An instant node can be created : +An instant node can be created if server configuration allows: curl -X POST -u cstar@localhost:encore -d "" http://localhost:5280/pshb/localhost + +or + + curl -X POST -u cstar@localhost:encore -d "" http://localhost:5280/pshb/localhost + +configure element (as per XEP-60) can be passed in the pubsub body. + + $ cat createnode.xml + + + + http://jabber.org/protocol/pubsub#node_config + + Princely Musings (Atom) + 1028 + Atom + + + + $ curl -X POST -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost + +### Deleting a node ### + +A node is deleted by: + + curl -X DELETE -u cstar@localhost:encore http://localhost:5280/pshb/localhost/princely_musings diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a9293212d..2d95b1fac 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -78,6 +78,7 @@ %% exports for console debug manual use -export([create_node/5, + create_node/7, delete_node/3, subscribe_node/5, unsubscribe_node/5, diff --git a/src/web/pshb_http.erl b/src/web/pshb_http.erl index f9f9e886e..89eea479e 100644 --- a/src/web/pshb_http.erl +++ b/src/web/pshb_http.erl @@ -48,35 +48,36 @@ process(LocalPath, #request{auth = Auth} = Request)-> ?DEBUG("LocalPath = ~p", [LocalPath]), - case get_auth(Auth) of - %%make sure user belongs to pubsub domain - {User, Domain} -> - out(Request, Request#request.method, LocalPath,{User, Domain}); - _ -> - out(Request, Request#request.method, LocalPath, undefined) - end. + UD = get_auth(Auth), + case catch out(Request, Request#request.method, LocalPath,UD) of + {'EXIT', Error} -> + ?ERROR_MSG("Error while processing ~p : ~n~p", [LocalPath, Error]), + error(500); + Result -> + Result + end. get_auth(Auth) -> case Auth of {SJID, P} -> case jlib:string_to_jid(SJID) of error -> - unauthorized; + undefined; #jid{user = U, server = S} -> case ejabberd_auth:check_password(U, S, P) of true -> {U, S}; false -> - unauthorized + undefined end end; _ -> - unauthorized + undefined end. out(Args, 'GET', [Domain,Node]=Uri, _User) -> case mod_pubsub:tree_action(get_host(Uri), get_node, [get_host(Uri),get_collection(Uri)]) of - {error, _} -> error(404); + {error, Error} -> error(Error); _ -> Items = lists:sort(fun(X,Y)-> {DateX, _} = X#pubsub_item.modification, @@ -135,7 +136,7 @@ out(Args, 'GET', [Domain]=Uri, From)-> case mod_pubsub:tree_action(Host, get_subnodes, [Host, <<>>, From ]) of [] -> ?DEBUG("Error getting URI ~p : ~p",[Uri, From]), - error(404); + error(?ERR_ITEM_NOT_FOUND); Collections -> {200, [{"Content-Type", "application/atomsvc+xml"}], "" ++ xml:element_to_string(service(Args,Domain, Collections))} @@ -143,18 +144,37 @@ out(Args, 'GET', [Domain]=Uri, From)-> out(Args, 'POST', [Domain]=Uri, {User, UDomain})-> Host = get_host(Uri), - case mod_pubsub:create_node(Host, Domain, <<>>, {User, UDomain}, "default") of + Payload = xml_stream:parse_element(Args#request.data), + {Node, Type} = case xml:get_subtag(Payload, "create") of + false -> {<<>>,"flat"}; + E -> + {list_to_binary(get_tag_attr_or_default("node", E,"")), + get_tag_attr_or_default("type", E,"flat")} + + end, + ConfigureElement = case xml:get_subtag(Payload, "configure") of + false ->[]; + {xmlelement, _, _, SubEls}->SubEls + end, + Jid = jlib:make_jid({User, UDomain, ""}), + case mod_pubsub:create_node(Host, Domain, Node, Jid, Type, all, ConfigureElement) of {error, Error} -> ?ERROR_MSG("Error create node via HTTP : ~p",[Error]), - error(Error); % will probably detail more - {result, [Node]} -> + {result, [Result]} -> {200, [{"Content-Type", "application/xml"}], "" - ++ xml:element_to_string(Node)} + ++ xml:element_to_string(Result)} + end; + +out(Args, 'DELETE', [Domain, Node] = Uri, {User, UDomain})-> + Host = get_host(Uri), + Jid = jlib:make_jid({User, UDomain, ""}), + BinNode = list_to_binary(Node), + case mod_pubsub:delete_node(Host, BinNode, Jid) of + {error, Error} -> error(Error); + {result, []} -> + {200, [],[]} end; - -out(Args, 'POST', [Domain]=Uri, undefined) -> - error(403); @@ -178,7 +198,7 @@ out(Args, 'GET', [Domain, Node, _Item]=URI, _) -> out(_,Method,Uri,undefined) -> ?DEBUG("Error, ~p not authorized for ~p : ~p",[ Method,Uri]), - error(403). + error(?ERR_FORBIDDEN). get_item(Uri, Failure, Success)-> ?DEBUG(" mod_pubsub:get_item(~p, ~p,~p)", [get_host(Uri), get_collection(Uri), get_member(Uri)]), @@ -341,4 +361,10 @@ i2l(I) when is_integer(I) -> integer_to_list(I); i2l(L) when is_list(L) -> L. b2l(B) when is_binary(B) -> binary_to_list(B); -b2l(L) when is_list(L) -> L. \ No newline at end of file +b2l(L) when is_list(L) -> L. + +get_tag_attr_or_default(AttrName, Element, Default)-> + case xml:get_tag_attr_s(AttrName, Element) of + "" -> Default; + Val -> Val + end. \ No newline at end of file