Skip to content

Commit d3140dc

Browse files
author
Lloyd Watkin
committed
Move validation of <in-reply-to/> into the validator
1 parent 8e74436 commit d3140dc

4 files changed

Lines changed: 94 additions & 128 deletions

File tree

src/main/java/org/buddycloud/channelserver/channel/ValidateEntry.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@
66
import java.util.UUID;
77

88
import org.apache.log4j.Logger;
9+
import org.buddycloud.channelserver.db.exception.NodeStoreException;
10+
import org.buddycloud.channelserver.pubsub.model.NodeItem;
911
import org.dom4j.Element;
1012
import org.dom4j.dom.DOMElement;
1113
import org.xmpp.packet.JID;
14+
import org.xmpp.packet.PacketError;
1215

1316
public class ValidateEntry {
1417

1518
public static final String MISSING_CONTENT_ELEMENT = "content-element-required";
1619
public static final String MISSING_ENTRY_ELEMENT = "entry-element-required";
1720
public static final String UNSUPPORTED_CONTENT_TYPE = "unsupported-content-type";
21+
public static final String MAX_THREAD_DEPTH_EXCEEDED = "max-thread-depth-exceeded";
22+
public static final String PARENT_ITEM_NOT_FOUND = "parent-item-not-found";
1823

1924
public static final String CONTENT_TEXT = "text";
2025
public static final String CONTENT_XHTML = "xhtml";
@@ -32,7 +37,7 @@ public class ValidateEntry {
3237

3338
public static final String ACTIVITY_VERB_POST = "post";
3439

35-
private static Logger LOGGER = Logger.getLogger(ValidateEntry.class);
40+
private static Logger logger = Logger.getLogger(ValidateEntry.class);
3641

3742
private Element entry;
3843

@@ -44,6 +49,7 @@ public class ValidateEntry {
4449
private JID jid;
4550
private String channelServerDomain;
4651
private String node;
52+
private ChannelManager channelManager;
4753

4854
Map<String, String> params = new HashMap<String, String>();
4955

@@ -62,11 +68,17 @@ public void setEntry(Element entry) {
6268
public String getErrorMessage() {
6369
return this.errorMessage;
6470
}
71+
72+
public void setChannelManager(ChannelManager channelManager) {
73+
this.channelManager = channelManager;
74+
}
6575

6676
/**
6777
* This is a big hackety-hack.
78+
* @throws InterruptedException
79+
* @throws NodeStoreException
6880
*/
69-
public boolean isValid() {
81+
public boolean isValid() throws NodeStoreException {
7082
if (this.entry == null) {
7183
this.errorMessage = MISSING_ENTRY_ELEMENT;
7284
return false;
@@ -76,13 +88,13 @@ public boolean isValid() {
7688
if ((id == null) || (true == id.getText().isEmpty())) {
7789
if (null != id)
7890
id.detach();
79-
LOGGER.debug("ID of the entry was missing. We add a default one to it: 1");
91+
logger.debug("ID of the entry was missing. We add a default one to it: 1");
8092
this.entry.addElement("id").setText("1");
8193
}
8294

8395
Element title = this.entry.element("title");
8496
if (null == title) {
85-
LOGGER.debug("Title of the entry was missing. We add a default one to it: 'Post'.");
97+
logger.debug("Title of the entry was missing. We add a default one to it: 'Post'.");
8698
title = this.entry.addElement("title");
8799
title.setText("Post");
88100
}
@@ -109,20 +121,16 @@ public boolean isValid() {
109121
if (null == updated) {
110122

111123
String updateTime = Conf.formatDate(new Date());
112-
LOGGER.debug("Update of the entry was missing. We add a default one to it: '"
124+
logger.debug("Update of the entry was missing. We add a default one to it: '"
113125
+ updateTime + "'.");
114126
this.entry.addElement("updated").setText(updateTime);
115127
}
116128

117129
this.geoloc = this.entry.element("geoloc");
118130

119131
Element reply = this.entry.element("in-reply-to");
120-
if (null != reply) {
121-
inReplyTo = reply.attributeValue("ref");
122-
if (-1 != inReplyTo.indexOf(",")) {
123-
String[] tokens = inReplyTo.split(",");
124-
inReplyTo = tokens[2];
125-
}
132+
if ((null != reply) && (false == validateInReplyToElement(reply))) {
133+
return false;
126134
}
127135

128136
Element meta = this.entry.element("meta");
@@ -211,5 +219,30 @@ public void setNode(String node) {
211219
public void setTo(String channelServerDomain) {
212220
this.channelServerDomain = channelServerDomain;
213221
}
222+
223+
224+
private boolean validateInReplyToElement(Element reply) throws NodeStoreException {
225+
226+
inReplyTo = reply.attributeValue("ref");
227+
if (-1 != inReplyTo.indexOf(",")) {
228+
String[] tokens = inReplyTo.split(",");
229+
inReplyTo = tokens[2];
230+
}
231+
232+
String[] inReplyToParts = reply.attributeValue("ref").split(",");
233+
inReplyTo = inReplyToParts[inReplyToParts.length - 1];
234+
235+
NodeItem nodeItem = null;
236+
if (null == (nodeItem = channelManager.getNodeItem(node, inReplyTo))) {
237+
this.errorMessage = PARENT_ITEM_NOT_FOUND;
238+
return false;
239+
}
240+
if (null != nodeItem.getInReplyTo()) {
241+
logger.error("User is attempting to reply to a reply");
242+
this.errorMessage = MAX_THREAD_DEPTH_EXCEEDED;
243+
return false;
244+
}
245+
return true;
246+
}
214247

215248
}

src/main/java/org/buddycloud/channelserver/packetprocessor/iq/namespace/pubsub/set/Publish.java

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ public class Publish extends PubSubElementProcessorAbstract {
3434
public static final String MISSING_ITEM_ELEMENT = "item-required";
3535
public static final String NODE_ID_REQUIRED = "nodeid-required";
3636

37-
public static final String MAX_THREAD_DEPTH_EXCEEDED = "max-thread-depth-exceeded";
38-
3937
private Element entry;
4038
private String id;
4139
private JID publishersJID;
@@ -103,10 +101,6 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
103101
if (false == isRequestValid())
104102
return;
105103
extractItemDetails();
106-
if (false == determineExtensionDetails()) {
107-
return;
108-
}
109-
110104
saveNodeItem();
111105
sendResponseStanza();
112106
sendNotifications();
@@ -119,46 +113,12 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm)
119113

120114
}
121115

122-
private boolean determineExtensionDetails() throws Exception {
123-
if (false == determineInReplyToDetails()) {
124-
return false;
125-
}
126-
return true;
127-
}
128-
129116
private void saveNodeItem() throws NodeStoreException {
130117
// Let's store the new item.
131118
channelManager.addNodeItem(new NodeItemImpl(node, id, new Date(), entry
132119
.asXML(), inReplyTo));
133120
}
134121

135-
private boolean determineInReplyToDetails() throws NodeStoreException,
136-
InterruptedException {
137-
inReplyTo = null;
138-
Element reply;
139-
NodeItem nodeItem = null;
140-
141-
if (null == (reply = entry.element("in-reply-to"))) {
142-
return true;
143-
}
144-
145-
String[] inReplyToParts = reply.attributeValue("ref").split(",");
146-
inReplyTo = inReplyToParts[inReplyToParts.length - 1];
147-
148-
if (null == (nodeItem = channelManager.getNodeItem(node, inReplyTo))) {
149-
setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
150-
outQueue.put(response);
151-
return false;
152-
}
153-
if (null != nodeItem.getInReplyTo()) {
154-
logger.error("User is attempting to reply to a reply");
155-
createExtendedErrorReply(PacketError.Type.modify, PacketError.Condition.bad_request, MAX_THREAD_DEPTH_EXCEEDED);
156-
outQueue.put(response);
157-
return false;
158-
}
159-
return true;
160-
}
161-
162122
private void extractItemDetails() throws InterruptedException {
163123

164124
entry = entryContent.getPayload();

src/test/java/org/buddycloud/channelserver/channel/ValidateEntryTest.java

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.buddycloud.channelserver.channel;
22

3+
import java.util.Date;
34
import java.util.concurrent.LinkedBlockingQueue;
45

56
import org.junit.Before;
@@ -10,6 +11,8 @@
1011
import org.xmpp.packet.Packet;
1112
import org.buddycloud.channelserver.packetHandler.iq.TestHandler;
1213
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.get.RepliesGet;
14+
import org.buddycloud.channelserver.pubsub.model.NodeItem;
15+
import org.buddycloud.channelserver.pubsub.model.impl.NodeItemImpl;
1316
import org.dom4j.Element;
1417

1518
import junit.framework.Assert;
@@ -27,11 +30,12 @@
2730
*/
2831
public class ValidateEntryTest extends TestHandler {
2932

30-
ValidateEntry validateEntry;
31-
IQ publishRequest;
32-
Element publishEntry;
33-
IQ replyRequest;
34-
Element replyEntry;
33+
private ValidateEntry validateEntry;
34+
private IQ publishRequest;
35+
private Element publishEntry;
36+
private IQ replyRequest;
37+
private Element replyEntry;
38+
private ChannelManager channelManager;
3539

3640
JID jid = new JID("juliet@shakespeare.lit/balcony");
3741
String node = "/users/romeo@shakespeare.lit/posts";
@@ -45,13 +49,22 @@ public void setUp() throws Exception {
4549
replyRequest = readStanzaAsIq("/iq/pubsub/publish/reply.stanza");
4650
replyEntry = replyRequest.getChildElement().element("publish")
4751
.element("item").element("entry");
52+
53+
channelManager = Mockito.mock(ChannelManager.class);
54+
55+
NodeItem item = new NodeItemImpl(node, "1", new Date(), "<entry/>");
56+
Mockito.when(
57+
channelManager.getNodeItem(Mockito.eq(node),
58+
Mockito.anyString())).thenReturn(item);
59+
4860
}
49-
61+
5062
private ValidateEntry getEntryObject(Element entry) {
5163
ValidateEntry validate = new ValidateEntry(entry);
5264
validate.setNode(node);
5365
validate.setTo(server);
5466
validate.setUser(jid);
67+
validate.setChannelManager(channelManager);
5568
return validate;
5669
}
5770

@@ -63,7 +76,7 @@ public void notProvidingAnEntryReturnsError() throws Exception {
6376
Assert.assertEquals(ValidateEntry.MISSING_ENTRY_ELEMENT,
6477
validateEntry.getErrorMessage());
6578
}
66-
79+
6780
@Test
6881
public void missingIdAttributeGetsAdded() throws Exception {
6982

@@ -277,4 +290,34 @@ public void activityVerbIsAdded() throws Exception {
277290
entry.elementText("verb"));
278291
}
279292

293+
@Test
294+
public void replyParentItemNotFoundResultsInError() throws Exception {
295+
296+
Mockito.when(
297+
channelManager.getNodeItem(Mockito.eq(node),
298+
Mockito.anyString())).thenReturn(null);
299+
300+
Element entry = (Element) this.replyEntry.clone();
301+
validateEntry = getEntryObject(entry);
302+
303+
Assert.assertFalse(validateEntry.isValid());
304+
Assert.assertEquals(ValidateEntry.PARENT_ITEM_NOT_FOUND,
305+
validateEntry.getErrorMessage());
306+
}
307+
308+
@Test
309+
public void canNotReplyToAReply() throws Exception {
310+
311+
NodeItem item = new NodeItemImpl(node, "2", new Date(), "<entry/>", "1");
312+
Mockito.when(
313+
channelManager.getNodeItem(Mockito.eq(node),
314+
Mockito.anyString())).thenReturn(item);
315+
316+
Element entry = (Element) this.replyEntry.clone();
317+
validateEntry = getEntryObject(entry);
318+
319+
Assert.assertFalse(validateEntry.isValid());
320+
Assert.assertEquals(ValidateEntry.MAX_THREAD_DEPTH_EXCEEDED,
321+
validateEntry.getErrorMessage());
322+
}
280323
}

src/test/java/org/buddycloud/channelserver/packetprocessor/iq/namespace/pubsub/set/PublishTest.java

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
import java.util.Date;
55
import java.util.concurrent.BlockingQueue;
66
import java.util.concurrent.LinkedBlockingQueue;
7-
import java.util.concurrent.TimeUnit;
8-
9-
import javax.annotation.PreDestroy;
107

118
import junit.framework.Assert;
129

@@ -27,14 +24,12 @@
2724
import org.dom4j.tree.BaseElement;
2825
import org.junit.Before;
2926
import org.junit.Test;
30-
import org.mockito.Mock;
3127
import org.mockito.Mockito;
3228
import org.xmpp.packet.IQ;
3329
import org.xmpp.packet.JID;
3430
import org.xmpp.packet.Message;
3531
import org.xmpp.packet.Packet;
3632
import org.xmpp.packet.PacketError;
37-
import org.xmpp.resultsetmanagement.ResultSet;
3833
import org.xmpp.resultsetmanagement.ResultSetImpl;
3934

4035
public class PublishTest extends IQTestHandler {
@@ -396,69 +391,4 @@ public void sendsOutExpectedNotifications() throws Exception {
396391
Assert.assertEquals(new JID("user2@server1"), notification.getTo());
397392

398393
}
399-
400-
@Test
401-
public void errorsIfReplyingToAPostWhichDoesntExist() throws Exception {
402-
403-
IQ request = readStanzaAsIq("/iq/pubsub/publish/reply.stanza");
404-
405-
Mockito.when(
406-
channelManager.getNodeItem(Mockito.eq(node),
407-
Mockito.eq("fc362eb42085f017ed9ccd9c4004b095")))
408-
.thenReturn(null);
409-
410-
Element entry = request.getChildElement().element("publish").element("item")
411-
.element("entry").createCopy();
412-
413-
Mockito.when(
414-
validateEntry.getPayload()).thenReturn(
415-
entry);
416-
417-
publish.process(element, jid, request, null);
418-
419-
Assert.assertEquals(1, queue.size());
420-
421-
IQ response = (IQ) queue.poll();
422-
423-
Assert.assertEquals(IQ.Type.error, response.getType());
424-
425-
PacketError error = response.getError();
426-
Assert.assertNotNull(error);
427-
Assert.assertEquals(PacketError.Type.cancel, error.getType());
428-
Assert.assertEquals(PacketError.Condition.item_not_found,
429-
error.getCondition());
430-
}
431-
432-
@Test
433-
public void canNotReplyToAReply() throws Exception {
434-
IQ request = readStanzaAsIq("/iq/pubsub/publish/reply.stanza");
435-
436-
NodeItem item = new NodeItemImpl(node, "2", new Date(), "<entry/>", "1");
437-
Mockito.when(
438-
channelManager.getNodeItem(Mockito.eq(node),
439-
Mockito.eq("fc362eb42085f017ed9ccd9c4004b095")))
440-
.thenReturn(item);
441-
442-
Element entry = request.getChildElement().element("publish").element("item")
443-
.element("entry").createCopy();
444-
445-
Mockito.when(
446-
validateEntry.getPayload()).thenReturn(
447-
entry);
448-
449-
publish.process(element, jid, request, null);
450-
451-
Assert.assertEquals(1, queue.size());
452-
453-
IQ response = (IQ) queue.poll();
454-
455-
Assert.assertEquals(IQ.Type.error, response.getType());
456-
457-
PacketError error = response.getError();
458-
Assert.assertNotNull(error);
459-
Assert.assertEquals(PacketError.Type.modify, error.getType());
460-
Assert.assertEquals(PacketError.Condition.bad_request,
461-
error.getCondition());
462-
Assert.assertEquals(Publish.MAX_THREAD_DEPTH_EXCEEDED, error.getApplicationConditionName());
463-
}
464394
}

0 commit comments

Comments
 (0)