mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Merge branch 'stable'
# Conflicts: # package-lock.json # src/public/javascripts/services/server.js # src/services/app_info.js # src/services/notes.js
This commit is contained in:
		
							
								
								
									
										6
									
								
								db/migrations/0127__fix_inconsistent_isProtected.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								db/migrations/0127__fix_inconsistent_isProtected.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | UPDATE notes SET title = 'Recovered protected note', isProtected = 0 WHERE noteId IN ( | ||||||
|  |     SELECT noteId FROM notes JOIN note_contents USING(noteId) | ||||||
|  |     WHERE notes.isProtected = 1 | ||||||
|  |       AND note_contents.isProtected = 0 | ||||||
|  |       AND notes.isDeleted = 0 | ||||||
|  | ) | ||||||
| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "Trilium Notes", |   "productName": "Trilium Notes", | ||||||
|   "description": "Trilium Notes", |   "description": "Trilium Notes", | ||||||
|   "version": "0.30.6", |   "version": "0.30.7", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "electron.js", |   "main": "electron.js", | ||||||
|   "bin": { |   "bin": { | ||||||
|   | |||||||
| @@ -18,6 +18,10 @@ function setProtectedSessionTimeout(encSessTimeout) { | |||||||
|     protectedSessionTimeout = encSessTimeout; |     protectedSessionTimeout = encSessTimeout; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getProtectedSessionId() { | ||||||
|  |     return utils.getCookie(PROTECTED_SESSION_ID_KEY); | ||||||
|  | } | ||||||
|  |  | ||||||
| function setProtectedSessionId(id) { | function setProtectedSessionId(id) { | ||||||
|     // using session cookie so that it disappears after browser/tab is closed |     // using session cookie so that it disappears after browser/tab is closed | ||||||
|     utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id); |     utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id); | ||||||
| @@ -42,6 +46,7 @@ function touchProtectedSession() { | |||||||
| } | } | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|  |     getProtectedSessionId, | ||||||
|     setProtectedSessionId, |     setProtectedSessionId, | ||||||
|     resetProtectedSession, |     resetProtectedSession, | ||||||
|     isProtectedSessionAvailable, |     isProtectedSessionAvailable, | ||||||
|   | |||||||
| @@ -1,11 +1,22 @@ | |||||||
|  | import protectedSessionHolder from './protected_session_holder.js'; | ||||||
| import utils from './utils.js'; | import utils from './utils.js'; | ||||||
| import infoService from "./info.js"; | import infoService from "./info.js"; | ||||||
|  |  | ||||||
| function getHeaders() { | function getHeaders() { | ||||||
|  |     let protectedSessionId = null; | ||||||
|  |  | ||||||
|  |     try { // this is because protected session might not be declared in some cases | ||||||
|  |         protectedSessionId = protectedSessionHolder.getProtectedSessionId(); | ||||||
|  |     } | ||||||
|  |     catch(e) {} | ||||||
|  |  | ||||||
|     // headers need to be lowercase because node.js automatically converts them to lower case |     // headers need to be lowercase because node.js automatically converts them to lower case | ||||||
|     // so hypothetical protectedSessionId becomes protectedsessionid on the backend |     // so hypothetical protectedSessionId becomes protectedsessionid on the backend | ||||||
|     // also avoiding using underscores instead of dashes since nginx filters them out by default |     // also avoiding using underscores instead of dashes since nginx filters them out by default | ||||||
|     return { |     return { | ||||||
|  |         // protectedSessionId is normally carried in cookie, but for electron AJAX requests we bypass | ||||||
|  |         // HTTP so no cookies and we need to pass it here explicitly | ||||||
|  |         'trilium-protected-session-id': protectedSessionId, | ||||||
|         'trilium-source-id': glob.sourceId, |         'trilium-source-id': glob.sourceId, | ||||||
|         'x-csrf-token': glob.csrfToken |         'x-csrf-token': glob.csrfToken | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| module.exports = { buildDate:"2019-03-28T23:17:24+01:00", buildRevision: "b2052a6ccda31712492cffc899ee132b0229613b" }; | module.exports = { buildDate:"2019-03-30T20:13:53+01:00", buildRevision: "c240fb98967d11ea3925c2c39b44138bb8e46f58" }; | ||||||
|   | |||||||
| @@ -150,7 +150,7 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {}) | |||||||
|         isProtected: !!extraOptions.isProtected, |         isProtected: !!extraOptions.isProtected, | ||||||
|         type: extraOptions.type, |         type: extraOptions.type, | ||||||
|         mime: extraOptions.mime, |         mime: extraOptions.mime, | ||||||
|         utcDateCreated: extraOptions.utcDateCreated, |         dateCreated: extraOptions.dateCreated, | ||||||
|         isExpanded: extraOptions.isExpanded, |         isExpanded: extraOptions.isExpanded, | ||||||
|         notePosition: extraOptions.notePosition |         notePosition: extraOptions.notePosition | ||||||
|     }; |     }; | ||||||
| @@ -307,12 +307,12 @@ async function saveNoteRevision(note) { | |||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
|     const noteRevisionSnapshotTimeInterval = parseInt(await optionService.getOption('noteRevisionSnapshotTimeInterval')); |     const noteRevisionSnapshotTimeInterval = parseInt(await optionService.getOption('noteRevisionSnapshotTimeInterval')); | ||||||
|  |  | ||||||
|     const revisionCutoff = dateUtils.utcDateStr(new Date(now.getTime() - noteRevisionSnapshotTimeInterval * 1000)); |     const revisionCutoff = dateUtils.dateStr(new Date(now.getTime() - noteRevisionSnapshotTimeInterval * 1000)); | ||||||
|  |  | ||||||
|     const existingNoteRevisionId = await sql.getValue( |     const existingNoteRevisionId = await sql.getValue( | ||||||
|         "SELECT noteRevisionId FROM note_revisions WHERE noteId = ? AND utcDateModifiedTo >= ?", [note.noteId, revisionCutoff]); |         "SELECT noteRevisionId FROM note_revisions WHERE noteId = ? AND dateModifiedTo >= ?", [note.noteId, revisionCutoff]); | ||||||
|  |  | ||||||
|     const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime(); |     const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.dateCreated).getTime(); | ||||||
|  |  | ||||||
|     if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) { |     if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) { | ||||||
|         await new NoteRevision({ |         await new NoteRevision({ | ||||||
| @@ -324,9 +324,7 @@ async function saveNoteRevision(note) { | |||||||
|             mime: note.mime, |             mime: note.mime, | ||||||
|             isProtected: false, // will be fixed in the protectNoteRevisions() call |             isProtected: false, // will be fixed in the protectNoteRevisions() call | ||||||
|             dateModifiedFrom: note.dateModified, |             dateModifiedFrom: note.dateModified, | ||||||
|             dateModifiedTo: dateUtils.localNowDateTime(), |             dateModifiedTo: dateUtils.nowDate() | ||||||
|             utcDateModifiedFrom: note.utcDateModified, |  | ||||||
|             utcDateModifiedTo: dateUtils.utcNowDateTime() |  | ||||||
|         }).save(); |         }).save(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -346,11 +344,16 @@ async function updateNote(noteId, noteUpdates) { | |||||||
|     note.isProtected = noteUpdates.isProtected; |     note.isProtected = noteUpdates.isProtected; | ||||||
|     await note.save(); |     await note.save(); | ||||||
|  |  | ||||||
|  |     const noteContent = await note.getNoteContent(); | ||||||
|  |  | ||||||
|     if (!['file', 'image'].includes(note.type)) { |     if (!['file', 'image'].includes(note.type)) { | ||||||
|         noteUpdates.content = await saveLinks(note, noteUpdates.content); |         noteUpdates.noteContent.content = await saveLinks(note, noteUpdates.noteContent.content); | ||||||
|  |  | ||||||
|  |         noteContent.content = noteUpdates.noteContent.content; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await note.setContent(noteUpdates.content); |     noteContent.isProtected = noteUpdates.isProtected; | ||||||
|  |     await noteContent.save(); | ||||||
|  |  | ||||||
|     if (noteTitleChanged) { |     if (noteTitleChanged) { | ||||||
|         await triggerNoteTitleChanged(note); |         await triggerNoteTitleChanged(note); | ||||||
| @@ -410,9 +413,9 @@ async function cleanupDeletedNotes() { | |||||||
|     // it's better to not use repository for this because it will complain about saving protected notes |     // it's better to not use repository for this because it will complain about saving protected notes | ||||||
|     // out of protected session |     // out of protected session | ||||||
|  |  | ||||||
|     await sql.execute("UPDATE note_contents SET content = NULL WHERE content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.utcDateModified <= ?)", [dateUtils.utcDateStr(cutoffDate)]); |     await sql.execute("UPDATE note_contents SET content = NULL WHERE content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.dateModified <= ?)", [dateUtils.dateStr(cutoffDate)]); | ||||||
|  |  | ||||||
|     await sql.execute("UPDATE note_revisions SET content = NULL WHERE note_revisions.content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.utcDateModified <= ?)", [dateUtils.utcDateStr(cutoffDate)]); |     await sql.execute("UPDATE note_revisions SET content = NULL WHERE note_revisions.content IS NOT NULL AND noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1 AND notes.dateModified <= ?)", [dateUtils.dateStr(cutoffDate)]); | ||||||
| } | } | ||||||
|  |  | ||||||
| sqlInit.dbReady.then(() => { | sqlInit.dbReady.then(() => { | ||||||
|   | |||||||
| @@ -15,7 +15,8 @@ function setDataKey(decryptedDataKey) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function setProtectedSessionId(req) { | function setProtectedSessionId(req) { | ||||||
|     cls.namespace.set('protectedSessionId', req.cookies.protectedSessionId); |     // cookies is the main storage but for electron header is used when bypassing HTTP | ||||||
|  |     cls.namespace.set('protectedSessionId', req.headers['trilium-protected-session-id'] || req.cookies.protectedSessionId); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getProtectedSessionId() { | function getProtectedSessionId() { | ||||||
| @@ -81,6 +82,7 @@ function decryptNoteRevision(hist) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|         if (hist.title) { |         if (hist.title) { | ||||||
|             hist.title = dataEncryptionService.decryptString(dataKey, hist.title); |             hist.title = dataEncryptionService.decryptString(dataKey, hist.title); | ||||||
|         } |         } | ||||||
| @@ -88,6 +90,10 @@ function decryptNoteRevision(hist) { | |||||||
|         if (hist.content) { |         if (hist.content) { | ||||||
|             hist.content = dataEncryptionService.decryptString(dataKey, hist.content); |             hist.content = dataEncryptionService.decryptString(dataKey, hist.content); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |     catch (e) { | ||||||
|  |         throw new Error(`Decryption failed for note ${hist.noteId}: ` + e.message + " " + e.stack); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| function encryptNote(note) { | function encryptNote(note) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user