You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Desktop: Security: Prevent calling arbitrary commands via x-callback-url
This commit is contained in:
		| @@ -34,7 +34,7 @@ import ShareFolderDialog from '../ShareFolderDialog/ShareFolderDialog'; | ||||
| import { ShareInvitation } from '@joplin/lib/services/share/reducer'; | ||||
| import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems'; | ||||
| import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils'; | ||||
| import { parseCallbackUrl } from '@joplin/lib/callbackUrlUtils'; | ||||
| import { isCallbackUrl, parseCallbackUrl } from '@joplin/lib/callbackUrlUtils'; | ||||
| import ElectronAppWrapper from '../../ElectronAppWrapper'; | ||||
| import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils'; | ||||
| import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types'; | ||||
| @@ -173,6 +173,7 @@ class MainScreenComponent extends React.Component<Props, State> { | ||||
| 	} | ||||
|  | ||||
| 	private openCallbackUrl(url: string) { | ||||
| 		if (!isCallbackUrl(url)) throw new Error(`Invalid callback URL: ${url}`); | ||||
| 		const { command, params } = parseCallbackUrl(url); | ||||
| 		void CommandService.instance().execute(command.toString(), params.id); | ||||
| 	} | ||||
|   | ||||
| @@ -3,13 +3,14 @@ import * as callbackUrlUtils from './callbackUrlUtils'; | ||||
| describe('callbackUrlUtils', () => { | ||||
|  | ||||
| 	it('should identify valid callback urls', () => { | ||||
| 		const url = 'joplin://x-callback-url/123?a=b'; | ||||
| 		const url = 'joplin://x-callback-url/openFolder?a=b'; | ||||
| 		expect(callbackUrlUtils.isCallbackUrl(url)).toBe(true); | ||||
| 	}); | ||||
|  | ||||
| 	it('should identify invalid callback urls', () => { | ||||
| 		expect(callbackUrlUtils.isCallbackUrl('not-joplin://x-callback-url/123?a=b')).toBe(false); | ||||
| 		expect(callbackUrlUtils.isCallbackUrl('joplin://xcallbackurl/123?a=b')).toBe(false); | ||||
| 		expect(callbackUrlUtils.isCallbackUrl('joplin://x-callback-url/invalidCommand?a=b')).toBe(false); | ||||
| 	}); | ||||
|  | ||||
| 	it('should build valid note callback urls', () => { | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| const URL = require('url-parse'); | ||||
|  | ||||
| export function isCallbackUrl(s: string) { | ||||
| 	return s.startsWith('joplin://x-callback-url/'); | ||||
| 	return s.startsWith('joplin://x-callback-url/openNote?') || | ||||
| 		s.startsWith('joplin://x-callback-url/openFolder?') || | ||||
| 		s.startsWith('joplin://x-callback-url/openTag?'); | ||||
| } | ||||
|  | ||||
| export function getNoteCallbackUrl(noteId: string) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user