2017-10-28 19:55:55 -04:00
"use strict" ;
2024-07-18 21:35:17 +03:00
import options from "../../services/options.js" ;
import utils from "../../services/utils.js" ;
import dateUtils from "../../services/date_utils.js" ;
import instanceId from "../../services/instance_id.js" ;
import passwordEncryptionService from "../../services/encryption/password_encryption.js" ;
import protectedSessionService from "../../services/protected_session.js" ;
import appInfo from "../../services/app_info.js" ;
import eventService from "../../services/events.js" ;
import sqlInit from "../../services/sql_init.js" ;
import sql from "../../services/sql.js" ;
import ws from "../../services/ws.js" ;
import etapiTokenService from "../../services/etapi_tokens.js" ;
2024-04-06 21:34:34 +03:00
import { Request } from 'express' ;
2024-07-24 20:23:05 +03:00
import { AppRequest } from '../route-interface.js' ;
2024-04-06 21:34:34 +03:00
2024-04-07 14:29:08 +03:00
function loginSync ( req : AppRequest ) {
2020-06-20 12:31:38 +02:00
if ( ! sqlInit . schemaExists ( ) ) {
2020-05-29 22:06:36 +02:00
return [ 500 , { message : "DB schema does not exist, can't sync." } ] ;
2018-07-24 20:35:03 +02:00
}
2017-12-10 15:45:17 -05:00
const timestampStr = req . body . timestamp ;
2017-10-28 19:55:55 -04:00
2018-04-02 20:46:46 -04:00
const timestamp = dateUtils . parseDateTime ( timestampStr ) ;
2017-12-10 15:45:17 -05:00
const now = new Date ( ) ;
2019-01-07 23:29:56 +01:00
// login token is valid for 5 minutes
if ( Math . abs ( timestamp . getTime ( ) - now . getTime ( ) ) > 5 * 60 * 1000 ) {
2022-12-02 22:12:07 +01:00
return [ 401 , { message : 'Auth request time is out of sync, please check that both client and server have correct time. The difference between clocks has to be smaller than 5 minutes.' } ] ;
2017-10-28 22:17:00 -04:00
}
2018-06-10 15:55:29 -04:00
const syncVersion = req . body . syncVersion ;
2017-10-28 22:17:00 -04:00
2018-06-10 15:55:29 -04:00
if ( syncVersion !== appInfo . syncVersion ) {
2019-02-15 00:15:09 +01:00
return [ 400 , { message : ` Non-matching sync versions, local is version ${ appInfo . syncVersion } , remote is ${ syncVersion } . It is recommended to run same version of Trilium on both sides of sync. ` } ] ;
2017-10-28 22:17:00 -04:00
}
2020-06-20 12:31:38 +02:00
const documentSecret = options . getOption ( 'documentSecret' ) ;
2017-12-10 15:45:17 -05:00
const expectedHash = utils . hmac ( documentSecret , timestampStr ) ;
2017-10-28 22:17:00 -04:00
const givenHash = req . body . hash ;
if ( expectedHash !== givenHash ) {
2020-05-02 13:52:02 +02:00
return [ 400 , { message : "Sync login credentials are incorrect. It looks like you're trying to sync two different initialized documents which is not possible." } ] ;
2017-10-28 22:17:00 -04:00
}
2024-04-07 14:29:08 +03:00
req . session . loggedIn = true ;
2017-10-28 22:17:00 -04:00
2018-03-30 19:31:22 -04:00
return {
2022-01-09 21:25:15 +01:00
instanceId : instanceId ,
2020-08-02 23:27:48 +02:00
maxEntityChangeId : sql.getValue ( "SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1" )
2018-03-30 19:31:22 -04:00
} ;
}
2017-10-28 19:55:55 -04:00
2024-04-06 21:34:34 +03:00
function loginToProtectedSession ( req : Request ) {
2017-11-09 23:25:23 -05:00
const password = req . body . password ;
2020-06-20 12:31:38 +02:00
if ( ! passwordEncryptionService . verifyPassword ( password ) ) {
2018-03-30 19:31:22 -04:00
return {
2017-11-09 23:25:23 -05:00
success : false ,
message : "Given current password doesn't match hash"
2018-03-30 19:31:22 -04:00
} ;
2017-11-09 23:25:23 -05:00
}
2020-06-20 12:31:38 +02:00
const decryptedDataKey = passwordEncryptionService . getDataKey ( password ) ;
2024-04-06 21:34:34 +03:00
if ( ! decryptedDataKey ) {
return {
success : false ,
message : "Unable to obtain data key."
}
}
2017-11-09 23:25:23 -05:00
2021-05-07 22:23:49 +02:00
protectedSessionService . setDataKey ( decryptedDataKey ) ;
2018-04-20 00:12:01 -04:00
2020-06-20 12:31:38 +02:00
eventService . emit ( eventService . ENTER_PROTECTED_SESSION ) ;
2017-11-09 23:25:23 -05:00
2021-05-07 22:23:49 +02:00
ws . sendMessageToAllClients ( { type : 'protectedSessionLogin' } ) ;
2018-03-30 19:31:22 -04:00
return {
2021-05-07 22:23:49 +02:00
success : true
2018-03-30 19:31:22 -04:00
} ;
}
2017-11-09 23:25:23 -05:00
2021-04-03 22:02:25 +02:00
function logoutFromProtectedSession() {
protectedSessionService . resetDataKey ( ) ;
eventService . emit ( eventService . LEAVE_PROTECTED_SESSION ) ;
2021-05-07 22:23:49 +02:00
ws . sendMessageToAllClients ( { type : 'protectedSessionLogout' } ) ;
2021-04-03 22:02:25 +02:00
}
2022-05-13 23:20:56 +02:00
function touchProtectedSession() {
protectedSessionService . touchProtectedSession ( ) ;
}
2024-04-06 21:34:34 +03:00
function token ( req : Request ) {
2019-06-23 21:22:08 +02:00
const password = req . body . password ;
2021-12-29 23:37:12 +01:00
if ( ! passwordEncryptionService . verifyPassword ( password ) ) {
return [ 401 , "Incorrect password" ] ;
2019-06-23 21:22:08 +02:00
}
2022-01-10 17:09:20 +01:00
// for backwards compatibility with Sender which does not send the name
const tokenName = req . body . tokenName || "Trilium Sender / Web Clipper" ;
2022-05-13 23:20:56 +02:00
2022-01-10 17:09:20 +01:00
const { authToken } = etapiTokenService . createToken ( tokenName ) ;
2019-06-23 21:22:08 +02:00
2022-01-10 17:09:20 +01:00
return { token : authToken } ;
2019-06-23 21:22:08 +02:00
}
2024-07-18 21:47:30 +03:00
export default {
2018-03-30 19:31:22 -04:00
loginSync ,
2019-06-23 21:22:08 +02:00
loginToProtectedSession ,
2021-04-03 22:02:25 +02:00
logoutFromProtectedSession ,
2022-05-13 23:20:56 +02:00
touchProtectedSession ,
2019-06-23 21:22:08 +02:00
token
2020-05-29 22:06:36 +02:00
} ;