Skip to content

Commit c222265

Browse files
committed
Allow injecting activities for debugging purposes
#245
1 parent b594b7b commit c222265

File tree

7 files changed

+77
-11
lines changed

7 files changed

+77
-11
lines changed

src/main/java/smithereen/SmithereenApplication.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
import smithereen.routes.WellKnownRoutes;
9393
import smithereen.routes.admin.AdminAnnouncementsRoutes;
9494
import smithereen.routes.admin.AdminCustomCSSRoutes;
95+
import smithereen.routes.admin.AdminDebugRoutes;
9596
import smithereen.routes.admin.AdminEmailRulesRoutes;
9697
import smithereen.routes.admin.AdminFaspRoutes;
9798
import smithereen.routes.admin.AdminFederationRoutes;
@@ -535,6 +536,13 @@ public static void main(String[] args){
535536
postRequiringPermissionWithCSRF("/update", UserRole.Permission.MANAGE_ANNOUNCEMENTS, AdminAnnouncementsRoutes::updateAnnouncement);
536537
});
537538
});
539+
540+
if(Config.DEBUG){
541+
path("/debug", ()->{
542+
getRequiringPermission("/injectActivity", UserRole.Permission.MANAGE_SERVER_SETTINGS, AdminDebugRoutes::injectActivity);
543+
postRequiringPermissionWithCSRF("/injectActivity", UserRole.Permission.MANAGE_SERVER_SETTINGS, AdminDebugRoutes::doInjectActivity);
544+
});
545+
}
538546
});
539547
});
540548

src/main/java/smithereen/routes/ActivityPubRoutes.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -830,14 +830,18 @@ public static Object undoLikeObject(Request req, Response resp){
830830
return undo;
831831
}
832832

833-
private static Object inbox(Request req, Response resp, Actor owner) throws SQLException{
834-
ApplicationContext ctx=context(req);
833+
private static Object inbox(Request req, Response resp, Actor owner){
835834
if(req.headers("digest")!=null){
836835
if(!verifyHttpDigest(req.headers("digest"), req.bodyAsBytes())){
837836
throw new BadRequestException("Digest verification failed");
838837
}
839838
}
840839
String body=req.body();
840+
return dispatchActivity(body, req, resp, true);
841+
}
842+
843+
public static Object dispatchActivity(String body, Request req, Response resp, boolean verifySignatures){
844+
ApplicationContext ctx=context(req);
841845
LOG.debug("Incoming activity: {}", body);
842846
JsonObject rawActivity;
843847
try{
@@ -907,19 +911,23 @@ else if(o!=null)
907911
}
908912

909913
Actor httpSigOwner;
910-
try{
911-
httpSigOwner=ActivityPub.verifyHttpSignature(req, actor);
912-
}catch(Exception x){
913-
LOG.warn("Exception while verifying HTTP signature on {} from {}: {}", getActivityType(activity), actor.activityPubID, x.toString());
914-
if(Config.DEBUG)
915-
LOG.debug("", x);
916-
throw new UserActionNotAllowedException(x);
914+
if(verifySignatures){
915+
try{
916+
httpSigOwner=ActivityPub.verifyHttpSignature(req, actor);
917+
}catch(Exception x){
918+
LOG.warn("Exception while verifying HTTP signature on {} from {}: {}", getActivityType(activity), actor.activityPubID, x.toString());
919+
if(Config.DEBUG)
920+
LOG.debug("", x);
921+
throw new UserActionNotAllowedException(x);
922+
}
923+
}else{
924+
httpSigOwner=actor;
917925
}
918926

919927
// if the activity has an LD-signature, verify that and allow any (cached) user to sign the HTTP signature
920928
// if it does not, the owner of the HTTP signature must match the actor
921929
boolean hasValidLDSignature=false;
922-
if(rawActivity.has("signature")){
930+
if(rawActivity.has("signature") && verifySignatures){
923931
JsonObject sig=rawActivity.getAsJsonObject("signature");
924932
try{
925933
URI keyID=URI.create(sig.get("creator").getAsString());
@@ -1059,14 +1067,16 @@ else if(o!=null)
10591067
LOG.debug("Bad request", x);
10601068
resp.status(400);
10611069
return TextProcessor.escapeHTML(x.getMessage());
1070+
}catch(SQLException x){
1071+
throw new InternalServerErrorException(x);
10621072
}/*catch(Exception x){
10631073
LOG.warn("Exception while processing an incoming activity", x);
10641074
throw new BadRequestException(x.toString());
10651075
}*/
10661076
if(Config.DEBUG)
10671077
throw new BadRequestException("No handler found for activity type: "+getActivityType(activity));
10681078
else
1069-
LOG.error("Received and ignored an activity of an unsupported type {}: {}", getActivityType(activity), activity.asRootActivityPubObject(ctx, req.host()));
1079+
LOG.error("Received and ignored an activity of an unsupported type {}: {}", getActivityType(activity), body);
10701080
return "";
10711081
}
10721082

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package smithereen.routes.admin;
2+
3+
import smithereen.ApplicationContext;
4+
import smithereen.model.Account;
5+
import smithereen.model.WebDeltaResponse;
6+
import smithereen.routes.ActivityPubRoutes;
7+
import smithereen.templates.RenderedTemplateResponse;
8+
import smithereen.text.TextProcessor;
9+
import spark.Request;
10+
import spark.Response;
11+
import spark.utils.StringUtils;
12+
13+
import static smithereen.Utils.*;
14+
15+
public class AdminDebugRoutes{
16+
public static Object injectActivity(Request req, Response resp, Account self, ApplicationContext ctx){
17+
return new RenderedTemplateResponse("admin_debug_inject_activity", req)
18+
.pageTitle("Inject activity");
19+
}
20+
21+
public static Object doInjectActivity(Request req, Response resp, Account self, ApplicationContext ctx){
22+
String activity=req.queryParams("activity");
23+
String result=ActivityPubRoutes.dispatchActivity(activity, req, resp, false).toString();
24+
resp.status(200);
25+
if(isAjax(req)){
26+
return new WebDeltaResponse(resp)
27+
.messageBox("Result", StringUtils.isEmpty(result) ? "Activity submitted, see server log for details." : TextProcessor.escapeHTML(result), lang(req).get("close"));
28+
}
29+
return result;
30+
}
31+
}

src/main/java/smithereen/templates/Templates.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public static void addGlobalParamsToTemplate(Request req, RenderedTemplateRespon
199199
.with("serverName", Config.getServerDisplayName())
200200
.with("serverDomain", Config.domain)
201201
.with("serverVersion", BuildInfo.VERSION)
202+
.with("isDebugMode", Config.DEBUG)
202203
.with("langName", lang.name)
203204
.with("isMobile", mobile)
204205
.with("isAjax", Utils.isAjax(req))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends "page" %}
2+
{% block content %}
3+
{% include "admin_debug_tabbar" with {'tab': 'injectActivity'} %}
4+
<div class="gray borderBottom singleColumn textByItself">
5+
<p>Use this to inject activities as if they were posted to this server's inbox with a valid signature. Useful for debugging federation issues.</p>
6+
</div>
7+
<form class="singleColumn" action="/settings/admin/debug/injectActivity" method="post" data-ajax>
8+
<textarea name="activity" placeholder="Activity JSON" style="width: 100%; font-family: monospace" id="activity"></textarea>
9+
{% script %}autoSizeTextArea(ge('activity'));{% endscript %}
10+
<input type="submit" value="Submit"/>
11+
</form>
12+
{% endblock %}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div class="secondaryTabBar">
2+
<a href="/settings/admin/debug/injectActivity" class="{{ tab=='injectActivity' ? 'selected' : '' }}">Inject activity</a>
3+
</div>

src/main/resources/templates/common/left_menu.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
{% if userPermissions.hasPermission('MANAGE_INVITES') and (serverSignupMode=='MANUAL_APPROVAL' or adminNotifications.signupRequestsCount>0) %}<li><a href="/settings/admin/signupRequests">{{ L('menu_signup_requests') }}{{ menuCounter(adminNotifications.signupRequestsCount, 'adminSignupRequests') }}</a></li>{% endif %}
2424
{% if userPermissions.hasPermission('MANAGE_REPORTS') %}<li><a href="/settings/admin/reports">{{ L('menu_reports') }}{{ menuCounter(adminNotifications.openReportsCount, 'adminReports') }}</a></li>{% endif %}
2525
{% if userPermissions.hasAnyPermission(['MANAGE_FEDERATION', 'MANAGE_BLOCKING_RULES']) %}<li><a href="/settings/admin/federation">{{ L('menu_access') }}</a></li>{% endif %}
26+
{% if isDebugMode %}<li><a href="/settings/admin/debug/injectActivity">Debug tools</a></li>{% endif %}
2627
{% endif %}
2728
{% else %}
2829
<li><a href="/account/login">{{ L('log_in') }}</a></li>

0 commit comments

Comments
 (0)