From 2f284fda3eedca70c077a9ab07bb6bb95e815cbf Mon Sep 17 00:00:00 2001
From: Travis Ralston <travpc@gmail.com>
Date: Fri, 27 Dec 2019 11:58:03 -0700
Subject: [PATCH] Support quarantining an entire domain's worth of media

---
 api/custom/quarantine.go   | 39 ++++++++++++++++++++++++++++++++++++++
 api/webserver/webserver.go |  2 ++
 docs/admin.md              |  6 ++++++
 3 files changed, 47 insertions(+)

diff --git a/api/custom/quarantine.go b/api/custom/quarantine.go
index 459e59fb..4922cf93 100644
--- a/api/custom/quarantine.go
+++ b/api/custom/quarantine.go
@@ -117,6 +117,45 @@ func QuarantineUserMedia(r *http.Request, log *logrus.Entry, user api.UserInfo)
 	return &api.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}}
 }
 
+func QuarantineDomainMedia(r *http.Request, log *logrus.Entry, user api.UserInfo) interface{} {
+	canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, log, user)
+	if !canQuarantine {
+		return api.AuthFailed()
+	}
+
+	params := mux.Vars(r)
+
+	serverName := params["serverName"]
+
+	log = log.WithFields(logrus.Fields{
+		"serverName": serverName,
+		"localAdmin": isLocalAdmin,
+	})
+
+	if !allowOtherHosts && serverName != r.Host {
+		return api.AuthFailed()
+	}
+
+	db := storage.GetDatabase().GetMediaStore(r.Context(), log)
+	userMedia, err := db.GetAllMediaForServer(serverName)
+	if err != nil {
+		log.Error("Error while listing media for the server: " + err.Error())
+		return api.InternalServerError("error retrieving media for server")
+	}
+
+	total := 0
+	for _, media := range userMedia {
+		resp, ok := doQuarantineOn(media, allowOtherHosts, log, r.Context())
+		if !ok {
+			return resp
+		}
+
+		total += resp.(*MediaQuarantinedResponse).NumQuarantined
+	}
+
+	return &api.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}}
+}
+
 func QuarantineMedia(r *http.Request, log *logrus.Entry, user api.UserInfo) interface{} {
 	canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, log, user)
 	if !canQuarantine {
diff --git a/api/webserver/webserver.go b/api/webserver/webserver.go
index 724cb383..570c18cd 100644
--- a/api/webserver/webserver.go
+++ b/api/webserver/webserver.go
@@ -41,6 +41,7 @@ func Init() {
 	quarantineHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineMedia), "quarantine_media", counter, false}
 	quarantineRoomHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineRoomMedia), "quarantine_room", counter, false}
 	quarantineUserHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineUserMedia), "quarantine_user", counter, false}
+	quarantineDomainHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineDomainMedia), "quarantine_domain", counter, false}
 	localCopyHandler := handler{api.AccessTokenRequiredRoute(unstable.LocalCopy), "local_copy", counter, false}
 	infoHandler := handler{api.AccessTokenRequiredRoute(unstable.MediaInfo), "info", counter, false}
 	configHandler := handler{api.AccessTokenRequiredRoute(r0.PublicConfig), "config", counter, false}
@@ -91,6 +92,7 @@ func Init() {
 		routes["/_matrix/media/"+version+"/admin/quarantine/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[a-zA-Z0-9.\\-_]+}"] = route{"POST", quarantineHandler}
 		routes["/_matrix/media/"+version+"/admin/quarantine/room/{roomId:[^/]+}"] = route{"POST", quarantineRoomHandler}
 		routes["/_matrix/media/"+version+"/admin/quarantine/user/{userId:[^/]+}"] = route{"POST", quarantineUserHandler}
+		routes["/_matrix/media/"+version+"/admin/quarantine/server/{serverName:[^/]+}"] = route{"POST", quarantineDomainHandler}
 		routes["/_matrix/media/"+version+"/admin/datastores/{datastoreId:[^/]+}/size_estimate"] = route{"GET", storageEstimateHandler}
 		routes["/_matrix/media/"+version+"/admin/datastores"] = route{"GET", datastoreListHandler}
 		routes["/_matrix/media/"+version+"/admin/datastores/{sourceDsId:[^/]+}/transfer_to/{targetDsId:[^/]+}"] = route{"POST", dsTransferHandler}
diff --git a/docs/admin.md b/docs/admin.md
index aad4fbf7..a00bf477 100644
--- a/docs/admin.md
+++ b/docs/admin.md
@@ -80,6 +80,12 @@ URL: `POST /_matrix/media/unstable/admin/quarantine/room/<room id>?access_token=
 
 URL: `POST /_matrix/media/unstable/admin/quarantine/user/<user id>?access_token=your_access_token`
 
+#### Quarantine a whole server's worth of media
+
+URL: `POST /_matrix/media/unstable/admin/quarantine/server/<server name>?access_token=your_access_token`
+
+Note that this will only quarantine what is currently known to the repo. It will not flag the domain for future quarantines.
+
 ## Datastore management
 
 Datastores are used by the media repository to put files. Typically these match what is configured in the config file, such as s3 and directories. 
-- 
GitLab