mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-29 02:28:57 +01:00 
			
		
		
		
	safe import implementation
This commit is contained in:
		
							parent
							
								
									caa7dd9619
								
							
						
					
					
						commit
						14f7a8b7b9
					
				| @ -12,6 +12,7 @@ const $fileUploadInput = $("#import-file-upload-input"); | ||||
| const $importProgressCountWrapper = $("#import-progress-count-wrapper"); | ||||
| const $importProgressCount = $("#import-progress-count"); | ||||
| const $importButton = $("#import-button"); | ||||
| const $safeImport = $("#safe-import"); | ||||
| 
 | ||||
| let importId; | ||||
| 
 | ||||
| @ -21,6 +22,7 @@ async function showDialog() { | ||||
|     $importProgressCountWrapper.hide(); | ||||
|     $importProgressCount.text('0'); | ||||
|     $fileUploadInput.val('').change(); // to trigger Import button disabling listener below
 | ||||
|     $safeImport.attr("checked", "checked"); | ||||
| 
 | ||||
|     glob.activeDialog = $dialog; | ||||
| 
 | ||||
| @ -49,8 +51,10 @@ function importIntoNote(importNoteId) { | ||||
|     // dialog (which shouldn't happen, but still ...)
 | ||||
|     importId = utils.randomString(10); | ||||
| 
 | ||||
|     const safeImport = $safeImport.is(":checked") ? 1 : 0; | ||||
| 
 | ||||
|     $.ajax({ | ||||
|         url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId, | ||||
|         url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId + '/safe/' + safeImport, | ||||
|         headers: server.getHeaders(), | ||||
|         data: formData, | ||||
|         dataType: 'json', | ||||
|  | ||||
| @ -12,10 +12,13 @@ const noteCacheService = require('../../services/note_cache'); | ||||
| const log = require('../../services/log'); | ||||
| 
 | ||||
| class ImportContext { | ||||
|     constructor(importId) { | ||||
|     constructor(importId, safeImport) { | ||||
|         // importId is to distinguish between different import events - it is possible (though not recommended)
 | ||||
|         // to have multiple imports going at the same time
 | ||||
|         this.importId = importId; | ||||
| 
 | ||||
|         this.safeImport = safeImport; | ||||
| 
 | ||||
|         // // count is mean to represent count of exported notes where practical, otherwise it's just some measure of progress
 | ||||
|         this.progressCount = 0; | ||||
|         this.lastSentCountTs = Date.now(); | ||||
| @ -53,7 +56,10 @@ class ImportContext { | ||||
| } | ||||
| 
 | ||||
| async function importToBranch(req) { | ||||
|     const {parentNoteId, importId} = req.params; | ||||
|     let {parentNoteId, importId, safeImport} = req.params; | ||||
| 
 | ||||
|     safeImport = safeImport !== '0'; | ||||
| 
 | ||||
|     const file = req.file; | ||||
| 
 | ||||
|     if (!file) { | ||||
| @ -74,7 +80,7 @@ async function importToBranch(req) { | ||||
| 
 | ||||
|     let note; // typically root of the import - client can show it after finishing the import
 | ||||
| 
 | ||||
|     const importContext = new ImportContext(importId); | ||||
|     const importContext = new ImportContext(importId, safeImport); | ||||
| 
 | ||||
|     try { | ||||
|         if (extension === '.tar') { | ||||
|  | ||||
| @ -129,7 +129,7 @@ function register(app) { | ||||
|     apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter); | ||||
| 
 | ||||
|     route(GET, '/api/notes/:branchId/export/:type/:format/:exportId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch); | ||||
|     route(POST, '/api/notes/:parentNoteId/import/:importId', [auth.checkApiAuthOrElectron, uploadMiddleware], importRoute.importToBranch, apiResultHandler); | ||||
|     route(POST, '/api/notes/:parentNoteId/import/:importId/safe/:safeImport', [auth.checkApiAuthOrElectron, uploadMiddleware], importRoute.importToBranch, apiResultHandler); | ||||
| 
 | ||||
|     route(POST, '/api/notes/:parentNoteId/upload', [auth.checkApiAuthOrElectron, uploadMiddleware], | ||||
|         filesRoute.uploadFile, apiResultHandler); | ||||
|  | ||||
| @ -5,13 +5,14 @@ const sql = require('./sql'); | ||||
| const utils = require('./utils'); | ||||
| const Attribute = require('../entities/attribute'); | ||||
| 
 | ||||
| const ATTRIBUTE_TYPES = [ 'label', 'label-definition', 'relation', 'relation-definition' ]; | ||||
| 
 | ||||
| const BUILTIN_ATTRIBUTES = [ | ||||
|     // label names
 | ||||
|     { type: 'label', name: 'disableVersioning' }, | ||||
|     { type: 'label', name: 'calendarRoot' }, | ||||
|     { type: 'label', name: 'archived' }, | ||||
|     { type: 'label', name: 'excludeFromExport' }, | ||||
|     { type: 'label', name: 'run' }, | ||||
|     { type: 'label', name: 'manualTransactionHandling' }, | ||||
|     { type: 'label', name: 'disableInclusion' }, | ||||
|     { type: 'label', name: 'appCss' }, | ||||
| @ -19,19 +20,20 @@ const BUILTIN_ATTRIBUTES = [ | ||||
|     { type: 'label', name: 'hideChildrenOverview' }, | ||||
|     { type: 'label', name: 'hidePromotedAttributes' }, | ||||
|     { type: 'label', name: 'readOnly' }, | ||||
|     { type: 'label', name: 'customRequestHandler' }, | ||||
|     { type: 'label', name: 'customResourceProvider' }, | ||||
|     { type: 'label', name: 'run', isDangerous: true }, | ||||
|     { type: 'label', name: 'customRequestHandler', isDangerous: true }, | ||||
|     { type: 'label', name: 'customResourceProvider', isDangerous: true }, | ||||
| 
 | ||||
|     // relation names
 | ||||
|     { type: 'relation', name: 'runOnNoteView' }, | ||||
|     { type: 'relation', name: 'runOnNoteCreation' }, | ||||
|     { type: 'relation', name: 'runOnNoteTitleChange' }, | ||||
|     { type: 'relation', name: 'runOnNoteChange' }, | ||||
|     { type: 'relation', name: 'runOnChildNoteCreation' }, | ||||
|     { type: 'relation', name: 'runOnAttributeCreation' }, | ||||
|     { type: 'relation', name: 'runOnAttributeChange' }, | ||||
|     { type: 'relation', name: 'runOnNoteView', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnNoteCreation', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnNoteTitleChange', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnNoteChange', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnChildNoteCreation', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnAttributeCreation', isDangerous: true }, | ||||
|     { type: 'relation', name: 'runOnAttributeChange', isDangerous: true }, | ||||
|     { type: 'relation', name: 'template' }, | ||||
|     { type: 'relation', name: 'renderNote' } | ||||
|     { type: 'relation', name: 'renderNote', isDangerous: true } | ||||
| ]; | ||||
| 
 | ||||
| async function getNotesWithLabel(name, value) { | ||||
| @ -94,11 +96,25 @@ async function getAttributeNames(type, nameLike) { | ||||
|     return names; | ||||
| } | ||||
| 
 | ||||
| function isAttributeType(type) { | ||||
|     return ATTRIBUTE_TYPES.includes(type); | ||||
| } | ||||
| 
 | ||||
| function isAttributeDangerous(type, name) { | ||||
|     return BUILTIN_ATTRIBUTES.some(attr =>  | ||||
|         attr.type === attr.type &&  | ||||
|         attr.name.toLowerCase() === name.trim().toLowerCase() && | ||||
|         attr.isDangerous | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     getNotesWithLabel, | ||||
|     getNotesWithLabels, | ||||
|     getNoteWithLabel, | ||||
|     createLabel, | ||||
|     createAttribute, | ||||
|     getAttributeNames | ||||
|     getAttributeNames, | ||||
|     isAttributeType, | ||||
|     isAttributeDangerous | ||||
| }; | ||||
| @ -6,6 +6,7 @@ const utils = require('../../services/utils'); | ||||
| const log = require('../../services/log'); | ||||
| const repository = require('../../services/repository'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const attributeService = require('../../services/attributes'); | ||||
| const Branch = require('../../entities/branch'); | ||||
| const tar = require('tar-stream'); | ||||
| const stream = require('stream'); | ||||
| @ -153,10 +154,19 @@ async function importTar(importContext, fileBuffer, importRootNote) { | ||||
|         for (const attr of noteMeta.attributes) { | ||||
|             attr.noteId = note.noteId; | ||||
| 
 | ||||
|             if (!attributeService.isAttributeType(attr.type)) { | ||||
|                 log.error("Unrecognized attribute type " + attr.type); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if (attr.type === 'relation') { | ||||
|                 attr.value = getNewNoteId(attr.value); | ||||
|             } | ||||
| 
 | ||||
|             if (importContext.safeImport && attributeService.isAttributeDangerous(attr.type, attr.name)) { | ||||
|                 attr.name = 'disabled-' + attr.name; | ||||
|             } | ||||
| 
 | ||||
|             attributes.push(attr); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam