From 2a8e93e4beda3a280ca02b0951bbd704fef4e7e1 Mon Sep 17 00:00:00 2001
From: KevinWh0 <45321184+KevinWh0@users.noreply.github.com>
Date: Thu, 1 Feb 2024 15:58:50 +0100
Subject: [PATCH] Fixed code injection from twitter import

---
 .../processors/ImportNotesProcessorService.ts | 42 +++++++++++--------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/packages/backend/src/queue/processors/ImportNotesProcessorService.ts b/packages/backend/src/queue/processors/ImportNotesProcessorService.ts
index 817befdf08..e5177d28e5 100644
--- a/packages/backend/src/queue/processors/ImportNotesProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportNotesProcessorService.ts
@@ -130,6 +130,17 @@ export class ImportNotesProcessorService {
 		return typeof obj[Symbol.iterator] === 'function';
 	}
 
+	private parseTwitterFile(str : string) : null | [{ tweet: any }] {
+		const removed = str.replace(new RegExp('window\\.YTD\\.tweets\\.part0 = ', 'g'), '');
+	
+		try {
+			return JSON.parse(removed);
+		} catch (error) {
+			//The format is not what we expected. Either this file was tampered with or twitters exports changed
+			return null;
+		}
+	}
+
 	@bindThis
 	public async process(job: Bull.Job<DbNoteImportJobData>): Promise<void> {
 		this.logger.info(`Starting note import of ${job.data.user.id} ...`);
@@ -175,23 +186,20 @@ export class ImportNotesProcessorService {
 			try {
 				this.logger.succ(`Unzipping to ${outputPath}`);
 				ZipReader.withDestinationPath(outputPath).viaBuffer(await fs.promises.readFile(destPath));
-				const fakeWindow: any = {
-					window: {
-						YTD: {
-							tweets: {
-								part0: {},
-							},
-						},
-					},
-				};
-				const script = new vm.Script(fs.readFileSync(outputPath + '/data/tweets.js', 'utf-8'));
-				const context = vm.createContext(fakeWindow);
-				script.runInContext(context);
-				const tweets = Object.keys(fakeWindow.window.YTD.tweets.part0).reduce((m, key, i, obj) => {
-					return m.concat(fakeWindow.window.YTD.tweets.part0[key].tweet);
-				}, []);
-				const processedTweets = await this.recreateChain(['id_str'], ['in_reply_to_status_id_str'], tweets, false);
-				this.queueService.createImportTweetsToDbJob(job.data.user, processedTweets, null);
+
+				const unprocessedTweetJson = this.parseTwitterFile(fs.readFileSync(outputPath + '/data/tweets.js', 'utf-8'));
+
+				//Make sure that it isnt null (because if something went wrong in parseTwitterFile it returns null)
+				if (unprocessedTweetJson) {
+					const tweets = Object.keys(unprocessedTweetJson).reduce((m, key, i, obj) => {
+						return m.concat(unprocessedTweetJson[i].tweet);
+					}, []);
+
+					const processedTweets = await this.recreateChain(['id_str'], ['in_reply_to_status_id_str'], tweets, false);
+					this.queueService.createImportTweetsToDbJob(job.data.user, processedTweets, null);
+				} else {
+					this.logger.warn('Failed to import twitter notes due to malformed file');
+				}
 			} finally {
 				cleanup();
 			}