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:
zadam 2019-03-30 22:11:03 +01:00
commit 9a5a085103
7 changed files with 50 additions and 19 deletions

View 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
)

View File

@ -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": {

View File

@ -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,

View File

@ -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
}; };

View File

@ -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" };

View File

@ -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(() => {

View File

@ -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,12 +82,17 @@ function decryptNoteRevision(hist) {
return; return;
} }
if (hist.title) { try {
hist.title = dataEncryptionService.decryptString(dataKey, hist.title); if (hist.title) {
} hist.title = dataEncryptionService.decryptString(dataKey, hist.title);
}
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);
} }
} }