From a62e4f1cf2c99150d345917c290f13e5a48ab92e Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Thu, 14 Nov 2024 19:32:08 -0500
Subject: [PATCH 1/4] ignore `isNSFW` for pure renotes

---
 packages/backend/src/core/NoteCreateService.ts | 9 ++++++++-
 packages/backend/src/core/NoteEditService.ts   | 9 ++++++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 1bc4599a60..ccc5bc0214 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -146,6 +146,8 @@ type Option = {
 	app?: MiApp | null;
 };
 
+type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
+
 @Injectable()
 export class NoteCreateService implements OnApplicationShutdown {
 	#shutdownController = new AbortController();
@@ -412,7 +414,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 
 		if (user.host && !data.cw) {
 			await this.federatedInstanceService.fetch(user.host).then(async i => {
-				if (i.isNSFW) {
+				if (i.isNSFW && !this.isPureRenote(data)) {
 					data.cw = 'Instance is marked as NSFW';
 				}
 			});
@@ -821,6 +823,11 @@ export class NoteCreateService implements OnApplicationShutdown {
 		if (!user.noindex) this.index(note);
 	}
 
+	@bindThis
+	private isPureRenote(note: Option): note is PureRenoteOption {
+		return this.isRenote(note) && !this.isQuote(note);
+	}
+
 	@bindThis
 	private isRenote(note: Option): note is Option & { renote: MiNote } {
 		return note.renote != null;
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index d31958e5d4..6c456fb4a3 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -142,6 +142,8 @@ type Option = {
 	editcount?: boolean | null;
 };
 
+type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
+
 @Injectable()
 export class NoteEditService implements OnApplicationShutdown {
 	#shutdownController = new AbortController();
@@ -442,7 +444,7 @@ export class NoteEditService implements OnApplicationShutdown {
 
 		if (user.host && !data.cw) {
 			await this.federatedInstanceService.fetch(user.host).then(async i => {
-				if (i.isNSFW) {
+				if (i.isNSFW && !this.isPureRenote(data)) {
 					data.cw = 'Instance is marked as NSFW';
 				}
 			});
@@ -787,6 +789,11 @@ export class NoteEditService implements OnApplicationShutdown {
 		if (!user.noindex) this.index(note);
 	}
 
+	@bindThis
+	private isPureRenote(note: Option): note is PureRenoteOption {
+		return this.isRenote(note) && !this.isQuote(note);
+	}
+
 	@bindThis
 	private isRenote(note: Option): note is Option & { renote: MiNote } {
 		return note.renote != null;
-- 
GitLab


From eb1e32681345aaa6184a540c7dba9ae4fd5a6e77 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Thu, 14 Nov 2024 19:50:34 -0500
Subject: [PATCH 2/4] add script to fix hellspawns

---
 UPGRADE_NOTES.md | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index 8bebd4eb34..fb81a611b7 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -1,5 +1,38 @@
 # Upgrade Notes
 
+## 2024.10.0
+
+### Hellspawns
+
+Sharkey versions before 2024.10 suffered from a bug in the "Mark instance as NSFW" feature.
+When a user from such an instance boosted a note, the boost would be converted to a hellspawn (pure renote with Content Warning).
+Hellspawns are buggy and do not properly federate, so it may be desirable to correct any that already exist in the database.
+The following script will correct any local or remote hellspawns in the database.
+
+```postgresql
+/* Remove "instance is marked as NSFW" hellspawns */
+UPDATE note
+SET cw = null
+WHERE
+	"renoteId" IS NOT NULL
+	AND "text" IS NULL
+	AND cw = 'Instance is marked as NSFW'
+	AND "replyId" IS NULL
+	AND "hasPoll" = false
+	AND "fileIds" = '{}';
+
+/* Fix legacy / user-created hellspawns */
+UPDATE note
+SET text = '.'
+WHERE
+	"renoteId" IS NOT NULL
+	AND "text" IS NULL
+	AND cw IS NOT NULL
+	AND "replyId" IS NULL
+	AND "hasPoll" = false
+	AND "fileIds" = '{}';
+```
+
 ## 2024.9.0
 
 ### Following Feed
-- 
GitLab


From c9934c379fcaaf02511f7d3ba63be44306feb722 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Sun, 17 Nov 2024 09:31:17 -0500
Subject: [PATCH 3/4] remove duplicate `isPureRenote` method

---
 packages/backend/src/core/NoteCreateService.ts | 4 ++--
 packages/backend/src/core/NoteEditService.ts   | 9 +--------
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index ccc5bc0214..892a929c41 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -146,7 +146,7 @@ type Option = {
 	app?: MiApp | null;
 };
 
-type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
+export type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
 
 @Injectable()
 export class NoteCreateService implements OnApplicationShutdown {
@@ -824,7 +824,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 	}
 
 	@bindThis
-	private isPureRenote(note: Option): note is PureRenoteOption {
+	public isPureRenote(note: Option): note is PureRenoteOption {
 		return this.isRenote(note) && !this.isQuote(note);
 	}
 
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index 6c456fb4a3..e5e3c38cd3 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -142,8 +142,6 @@ type Option = {
 	editcount?: boolean | null;
 };
 
-type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
-
 @Injectable()
 export class NoteEditService implements OnApplicationShutdown {
 	#shutdownController = new AbortController();
@@ -444,7 +442,7 @@ export class NoteEditService implements OnApplicationShutdown {
 
 		if (user.host && !data.cw) {
 			await this.federatedInstanceService.fetch(user.host).then(async i => {
-				if (i.isNSFW && !this.isPureRenote(data)) {
+				if (i.isNSFW && !this.noteCreateService.isPureRenote(data)) {
 					data.cw = 'Instance is marked as NSFW';
 				}
 			});
@@ -789,11 +787,6 @@ export class NoteEditService implements OnApplicationShutdown {
 		if (!user.noindex) this.index(note);
 	}
 
-	@bindThis
-	private isPureRenote(note: Option): note is PureRenoteOption {
-		return this.isRenote(note) && !this.isQuote(note);
-	}
-
 	@bindThis
 	private isRenote(note: Option): note is Option & { renote: MiNote } {
 		return note.renote != null;
-- 
GitLab


From cc394d9a4bd560097ddfa7c4d11f7abe9a993fa8 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Sun, 17 Nov 2024 09:32:13 -0500
Subject: [PATCH 4/4] quote all symbols in hellspawn upgrade script

---
 UPGRADE_NOTES.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index fb81a611b7..c941de6643 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -11,23 +11,23 @@ The following script will correct any local or remote hellspawns in the database
 
 ```postgresql
 /* Remove "instance is marked as NSFW" hellspawns */
-UPDATE note
-SET cw = null
+UPDATE "note"
+SET "cw" = null
 WHERE
 	"renoteId" IS NOT NULL
 	AND "text" IS NULL
-	AND cw = 'Instance is marked as NSFW'
+	AND "cw" = 'Instance is marked as NSFW'
 	AND "replyId" IS NULL
 	AND "hasPoll" = false
 	AND "fileIds" = '{}';
 
 /* Fix legacy / user-created hellspawns */
-UPDATE note
-SET text = '.'
+UPDATE "note"
+SET "text" = '.'
 WHERE
 	"renoteId" IS NOT NULL
 	AND "text" IS NULL
-	AND cw IS NOT NULL
+	AND "cw" IS NOT NULL
 	AND "replyId" IS NULL
 	AND "hasPoll" = false
 	AND "fileIds" = '{}';
-- 
GitLab