protect against spoofing in syndie with a per-jvm-instance nonce (which should prevent the spurious "are you being spoofed" things)

fixed the syndie previewing
This commit is contained in:
jrandom
2005-11-13 14:15:26 +00:00
committed by zzz
parent 16fd46db2b
commit ddd438de35
9 changed files with 157 additions and 38 deletions

View File

@ -749,6 +749,8 @@ public class BlogManager {
int split = line.indexOf('=');
int split2 = line.indexOf(':');
if ( (split < 0) || ( (split2 > 0) && (split2 < split) ) ) split = split2;
if ( (split < 0) && (split2 < 0) )
continue;
String key = line.substring(0,split).trim();
String val = line.substring(split+1).trim();
raw.append(key).append(": ").append(val).append('\n');

View File

@ -17,6 +17,7 @@ import net.i2p.util.Log;
public class ThreadedHTMLRenderer extends HTMLRenderer {
private Log _log;
private String _baseURI;
private boolean _inlineReply;
public ThreadedHTMLRenderer(I2PAppContext ctx) {
super(ctx);
@ -118,8 +119,11 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
private static final boolean empty(String val) { return (val == null) || (val.trim().length() <= 0); }
/**
* @param replyHiddenFields HTML of hidden input fields necessary for the reply form to be honored
*/
public void render(User user, Writer out, Archive archive, BlogURI post,
boolean inlineReply, ThreadIndex index, String baseURI,
boolean inlineReply, ThreadIndex index, String baseURI, String replyHiddenFields,
String offset, String requestTags, String filteredAuthor) throws IOException {
EntryContainer entry = archive.getEntry(post);
if (entry == null) return;
@ -131,6 +135,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
_archive = archive;
_cutBody = false;
_showImages = true;
_inlineReply = inlineReply;
_headers = new HashMap();
_bodyBuffer = new StringBuffer(1024);
_postBodyBuffer = new StringBuffer(1024);
@ -192,6 +197,30 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
out.write("\n<a href=\"");
out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags, filteredAuthor));
out.write("\" title=\"Select a shareable link directly to this post\">permalink</a>\n");
if (!inlineReply) {
String refuseReply = (String)_headers.get(HEADER_REFUSE_REPLIES);
boolean allowReply = false;
if ( (refuseReply != null) && (Boolean.valueOf(refuseReply).booleanValue()) ) {
if (_entry == null )
allowReply = false;
else if ( (_user == null) || (_user.getBlog() == null) )
allowReply = false;
else if (_entry.getURI().getKeyHash().equals(_user.getBlog()))
allowReply = true;
else
allowReply = false;
} else {
allowReply = true;
}
if (allowReply && (_entry != null) ) {
out.write("<a href=\"post.jsp?");
out.write(PostServlet.PARAM_PARENT + '=' +
Base64.encode(_entry.getURI().getKeyHash().toBase64() + '/' + _entry.getURI().getEntryId()));
out.write("\" title=\"Reply to the current post\" >Reply</a><br />\n");
}
}
out.write("</td>\n</tr>\n");
out.write("<!-- body meta end -->\n");
@ -229,6 +258,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
(refuseReplies == null) || (!Boolean.valueOf(refuseReplies).booleanValue()) ) {
out.write("<!-- body reply begin -->\n");
out.write("<form action=\"post.jsp\" method=\"POST\" enctype=\"multipart/form-data\">\n");
out.write(replyHiddenFields);
out.write("<input type=\"hidden\" name=\"" + PostServlet.PARAM_PARENT + "\" value=\"");
out.write(Base64.encode(post.toString()));
out.write("\" />");

View File

@ -96,6 +96,7 @@ public class AddressesServlet extends BaseServlet {
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_BLOG + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\">");
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName() + "\" />" + pn.getName() + " ");
@ -120,6 +121,7 @@ public class AddressesServlet extends BaseServlet {
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_BLOG + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -156,6 +158,7 @@ public class AddressesServlet extends BaseServlet {
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
PetName pn = db.getByName((String)iter.next());
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_ARCHIVE + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -177,6 +180,7 @@ public class AddressesServlet extends BaseServlet {
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_ARCHIVE + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -208,6 +212,7 @@ public class AddressesServlet extends BaseServlet {
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
PetName pn = db.getByName((String)iter.next());
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_I2PHEX + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -222,6 +227,7 @@ public class AddressesServlet extends BaseServlet {
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_I2PHEX + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -248,6 +254,7 @@ public class AddressesServlet extends BaseServlet {
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
PetName pn = db.getByName((String)iter.next());
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_EEPSITE + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -262,6 +269,7 @@ public class AddressesServlet extends BaseServlet {
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_EEPSITE + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_I2P + "\" />");
out.write("<tr><td colspan=\"3\">");
@ -288,6 +296,7 @@ public class AddressesServlet extends BaseServlet {
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
PetName pn = db.getByName((String)iter.next());
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\">");
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
out.write("Network: <input type=\"text\" name=\"" + PARAM_NET + "\" value=\"" + pn.getNetwork() + "\" /> ");
@ -302,6 +311,7 @@ public class AddressesServlet extends BaseServlet {
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\">");
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "") + " />\n");
@ -372,4 +382,6 @@ public class AddressesServlet extends BaseServlet {
return proto.equals(reqProto);
}
}
protected String getTitle() { return "Syndie :: Addressbook"; }
}

View File

@ -31,6 +31,7 @@ public class AdminServlet extends BaseServlet {
private void displayForm(User user, HttpServletRequest req, PrintWriter out) throws IOException {
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">\n");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\">");
out.write("<em class=\"b_adminField\">Single user?</em> <input type=\"checkbox\" class=\"b_adminField\" name=\"singleuser\" ");
@ -71,4 +72,6 @@ public class AdminServlet extends BaseServlet {
out.write("</td></tr>\n");
out.write("</form>\n");
}
protected String getTitle() { return "Syndie :: Configuration"; }
}

View File

@ -20,6 +20,53 @@ import net.i2p.syndie.sml.*;
*
*/
public abstract class BaseServlet extends HttpServlet {
protected static final String PARAM_AUTH_ACTION = "syndie.auth";
private static long _authNonce;
public void init() throws ServletException {
super.init();
_authNonce = I2PAppContext.getGlobalContext().random().nextLong();
}
protected boolean authAction(HttpServletRequest req) {
return authAction(req.getParameter(PARAM_AUTH_ACTION));
}
protected boolean authAction(String auth) {
if (auth == null) {
return false;
} else {
try {
boolean rv = (Long.valueOf(auth).longValue() == _authNonce);
return rv;
} catch (NumberFormatException nfe) {
return false;
}
}
}
/**
* write out hidden fields for params that need to be tacked onto an http request that updates
* data, to prevent spoofing
*/
protected void writeAuthActionFields(Writer out) throws IOException {
out.write("<input type=\"hidden\" name=\"" + PARAM_AUTH_ACTION + "\" value=\"" + _authNonce + "\" />");
}
protected String getAuthActionFields() throws IOException {
return "<input type=\"hidden\" name=\"" + PARAM_AUTH_ACTION + "\" value=\"" + _authNonce + "\" />";
}
/**
* key=value& of params that need to be tacked onto an http request that updates data, to
* prevent spoofing
*/
protected String getAuthActionParams() { return PARAM_AUTH_ACTION + '=' + _authNonce + '&'; }
/**
* key=value& of params that need to be tacked onto an http request that updates data, to
* prevent spoofing
*/
protected void addAuthActionParams(StringBuffer buf) {
buf.append(PARAM_AUTH_ACTION).append('=').append(_authNonce).append('&');
}
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
@ -30,12 +77,15 @@ public abstract class BaseServlet extends HttpServlet {
String pass = req.getParameter("password");
String action = req.getParameter("action");
boolean forceNewIndex = false;
boolean authAction = authAction(req);
if (req.getParameter("regenerateIndex") != null)
forceNewIndex = true;
User oldUser = user;
user = handleRegister(user, req);
if (authAction)
user = handleRegister(user, req);
if (oldUser != user)
forceNewIndex = true;
@ -48,23 +98,25 @@ public abstract class BaseServlet extends HttpServlet {
user = BlogManager.instance().getDefaultUser();
}
forceNewIndex = true;
} else if ("Login".equals(action)) {
} else if (authAction && "Login".equals(action)) {
user = BlogManager.instance().login(login, pass); // ignore failures - user will just be unauthorized
if (!user.getAuthenticated())
user = BlogManager.instance().getDefaultUser();
forceNewIndex = true;
} else if ("Logout".equals(action)) {
} else if (authAction && "Logout".equals(action)) {
user = BlogManager.instance().getDefaultUser();
forceNewIndex = true;
}
req.getSession().setAttribute("user", user);
handleAdmin(user, req);
if (authAction) {
handleAdmin(user, req);
forceNewIndex = handleAddressbook(user, req) || forceNewIndex;
forceNewIndex = handleBookmarking(user, req) || forceNewIndex;
handleUpdateProfile(user, req);
forceNewIndex = handleAddressbook(user, req) || forceNewIndex;
forceNewIndex = handleBookmarking(user, req) || forceNewIndex;
handleUpdateProfile(user, req);
}
FilteredThreadIndex index = (FilteredThreadIndex)req.getSession().getAttribute("threadIndex");
@ -677,6 +729,7 @@ public abstract class BaseServlet extends HttpServlet {
if (!empty(filteredAuthor))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(filteredAuthor).append('&');
addAuthActionParams(buf);
return buf.toString();
}
protected String getRemoveFromGroupLink(User user, String name, String group, String uri, String visible,
@ -703,6 +756,7 @@ public abstract class BaseServlet extends HttpServlet {
if (!empty(filteredAuthor))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(filteredAuthor).append('&');
addAuthActionParams(buf);
return buf.toString();
}
protected String getViewPostLink(HttpServletRequest req, ThreadNode node, User user, boolean isPermalink) {

View File

@ -60,6 +60,13 @@ public class PostServlet extends BaseServlet {
}
private void previewPostedData(User user, HttpServletRequest rawRequest, Archive archive, String contentType, PostBean post, PrintWriter out) throws IOException {
MultiPartRequest req = new MultiPartRequest(rawRequest);
if (!authAction(req.getString(PARAM_AUTH_ACTION))) {
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgErro\">Invalid form submission... stale data?</span></td></tr>");
return;
}
// not confirmed but they posted stuff... gobble up what they give
// and display it as a prview (then we show the confirm form
@ -68,8 +75,6 @@ public class PostServlet extends BaseServlet {
post.reinitialize();
post.setUser(user);
MultiPartRequest req = new MultiPartRequest(rawRequest);
boolean inNewThread = getInNewThread(req.getString(PARAM_IN_NEW_THREAD));
boolean refuseReplies = getRefuseReplies(req.getString(PARAM_REFUSE_REPLIES));
@ -86,8 +91,8 @@ public class PostServlet extends BaseServlet {
if ( (replyTo != null) && (replyTo.trim().length() > 0) ) {
byte r[] = Base64.decode(replyTo);
if (r != null) {
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": " + new String(r, "UTF-8");
if (entryHeaders == null) entryHeaders = HTMLRenderer.HEADER_IN_REPLY_TO + ": entry://" + new String(r, "UTF-8");
else entryHeaders = entryHeaders + '\n' + HTMLRenderer.HEADER_IN_REPLY_TO + ": entry://" + new String(r, "UTF-8");
} else {
replyTo = null;
}
@ -137,6 +142,7 @@ public class PostServlet extends BaseServlet {
post.renderPreview(out);
out.write("<hr /><span class=\"b_postConfirm\"><form action=\"" + getPostURI() + "\" method=\"POST\">\n");
writeAuthActionFields(out);
out.write("Please confirm that the above is ok");
if (BlogManager.instance().authorizeRemote(user)) {
out.write(", and select what additional archives you want the post transmitted to.");
@ -166,6 +172,10 @@ public class PostServlet extends BaseServlet {
}
private void postEntry(User user, HttpServletRequest req, Archive archive, PostBean post, PrintWriter out) throws IOException {
if (!authAction(req)) {
out.write("<tr><td colspan=\"3\"><span class=\"b_postMsgErro\">Invalid form submission... stale data?</span></td></tr>");
return;
}
String remArchive = req.getParameter(PARAM_REMOTE_ARCHIVE);
post.setArchive(remArchive);
BlogURI uri = post.postEntry();
@ -185,6 +195,7 @@ public class PostServlet extends BaseServlet {
post.setUser(user);
out.write("<form action=\"" + getPostURI() + "\" method=\"POST\" enctype=\"multipart/form-data\">\n");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\">\n");
out.write("<span class=\"b_postField\">Post subject:</span> ");
out.write("<input type=\"text\" class=\"b_postSubject\" size=\"80\" name=\"" + PARAM_SUBJECT
@ -203,7 +214,7 @@ public class PostServlet extends BaseServlet {
String parentURI = req.getParameter(PARAM_PARENT);
if ( (parentURI != null) && (parentURI.trim().length() > 0) )
out.write("<input type=\"hidden\" name=\"" + PARAM_PARENT + " value=\"" + parentURI + "\" />\n");
out.write("<input type=\"hidden\" name=\"" + PARAM_PARENT + "\" value=\"" + parentURI + "\" />\n");
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" />\n");
@ -223,7 +234,8 @@ public class PostServlet extends BaseServlet {
if (parentURI != null) {
out.write("<hr /><span id=\"parentText\" class=\"b_postParent\">");
post.renderReplyPreview(out, DataHelper.getUTF8(Base64.decode(parentURI)));
String decoded = DataHelper.getUTF8(Base64.decode(parentURI));
post.renderReplyPreview(out, "entry://" + decoded);
out.write("</span><hr/>\n");
}
@ -273,4 +285,5 @@ public class PostServlet extends BaseServlet {
+ "<span class=\"b_postField\">Attachment 2:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile2\" /><br />"
+ "<span class=\"b_postField\">Attachment 3:</span> <input class=\"b_postField\" type=\"file\" name=\"entryfile3\" /><br />\n";
protected String getTitle() { return "Syndie :: Post new content"; }
}

View File

@ -57,6 +57,7 @@ public class ProfileServlet extends BaseServlet {
out.write("<!-- " + info.toString() + "-->\n");
out.write("<form action=\"" + baseURI + "\" method=\"POST\">\n");
writeAuthActionFields(out);
// now add the form to update
out.write("<tr><td colspan=\"3\">Your profile</td></tr>\n");
out.write("<tr><td colspan=\"3\">Name: <input type=\"text\" name=\""
@ -214,6 +215,8 @@ public class ProfileServlet extends BaseServlet {
}
}
}
protected String getTitle() { return "Syndie :: View profile"; }
private static final String INVALID_PROFILE = "<tr><td colspan=\"3\">The profile requested is invalid</td></tr>\n";
}

View File

@ -19,30 +19,31 @@ import net.i2p.syndie.sml.*;
* Login/register form
*
*/
public class SwitchServlet extends BaseServlet {
private final String FORM = "<form action=\"" + getControlTarget() + "\" method=\"POST\">\n" +
"<tr><td colspan=\"3\"><b>Log in to an existing account</b></td></tr>\n" +
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Login\" />\n" +
"<input type=\"submit\" name=\"action\" value=\"Cancel\" />\n" +
"<input type=\"submit\" name=\"action\" value=\"Logout\" /></td></tr>\n" +
"</form>\n" +
"<tr><td colspan=\"3\"><hr /></td></tr>\n" +
"<form action=\"" + ThreadedHTMLRenderer.buildProfileURL(null) + "\" method=\"POST\">\n" +
"<tr><td colspan=\"3\"><b>Register a new account</b></td></tr>\n" +
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /> (only known locally)</td></tr>\n" +
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Public name: <input type=\"text\" name=\"accountName\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Description: <input type=\"text\" name=\"description\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Contact URL: <input type=\"text\" name=\"contactURL\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Registration password: <input type=\"password\" name=\"registrationPass\" />" +
" (only necessary if the Syndie administrator requires it)</td></tr>\n" +
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Register\" /></td></tr>\n" +
"</form>\n";
public class SwitchServlet extends BaseServlet {
protected String getTitle() { return "Syndie :: Login/Register"; }
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
out.write(FORM);
out.write("<form action=\"" + getControlTarget() + "\" method=\"POST\">\n");
writeAuthActionFields(out);
out.write("<tr><td colspan=\"3\"><b>Log in to an existing account</b></td></tr>\n" +
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Login\" />\n" +
"<input type=\"submit\" name=\"action\" value=\"Cancel\" />\n" +
"<input type=\"submit\" name=\"action\" value=\"Logout\" /></td></tr>\n" +
"</form>\n" +
"<tr><td colspan=\"3\"><hr /></td></tr>\n" +
"<form action=\"" + ThreadedHTMLRenderer.buildProfileURL(null) + "\" method=\"POST\">\n" +
"<tr><td colspan=\"3\"><b>Register a new account</b></td></tr>\n" +
"<tr><td colspan=\"3\">Login: <input type=\"text\" name=\"login\" /> (only known locally)</td></tr>\n" +
"<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Public name: <input type=\"text\" name=\"accountName\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Description: <input type=\"text\" name=\"description\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Contact URL: <input type=\"text\" name=\"contactURL\" /></td></tr>\n" +
"<tr><td colspan=\"3\">Registration password: <input type=\"password\" name=\"registrationPass\" />" +
" (only necessary if the Syndie administrator requires it)</td></tr>\n" +
"<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Register\" /></td></tr>\n" +
"</form>\n");
}
}

View File

@ -40,7 +40,7 @@ public class ViewThreadedServlet extends BaseServlet {
for (int i = 0; i < posts.size(); i++) {
BlogURI post = (BlogURI)posts.get(i);
renderer.render(user, out, archive, post, posts.size() == 1, index, uri, off, tags, author);
renderer.render(user, out, archive, post, posts.size() == 1, index, uri, getAuthActionFields(), off, tags, author);
}
}
@ -136,7 +136,7 @@ public class ViewThreadedServlet extends BaseServlet {
int written = 0;
for (int curRoot = threadOffset; curRoot < numThreads + threadOffset; curRoot++) {
ThreadNode node = index.getRoot(curRoot);
out.write("<!-- thread begin node=" + node + " curRoot=" + curRoot + " threadOffset=" + threadOffset + " -->\n");
out.write("<!-- thread begin curRoot=" + curRoot + " threadOffset=" + threadOffset + " -->\n");
renderThread(user, out, index, archive, req, node, 0, visibleEntry, state);
out.write("<!-- thread end -->\n");
written++;
@ -302,4 +302,5 @@ public class ViewThreadedServlet extends BaseServlet {
return "&nbsp;";
}
protected String getTitle() { return "Syndie :: View threads"; }
}