2017-10-28 19:55:55 -04:00
"use strict" ;
2017-11-02 20:48:02 -04:00
const options = require ( '../../services/options' ) ;
2017-10-28 22:17:00 -04:00
const utils = require ( '../../services/utils' ) ;
2018-04-02 20:46:46 -04:00
const dateUtils = require ( '../../services/date_utils' ) ;
2018-04-01 21:27:46 -04:00
const sourceIdService = require ( '../../services/source_id' ) ;
const passwordEncryptionService = require ( '../../services/password_encryption' ) ;
const protectedSessionService = require ( '../../services/protected_session' ) ;
const appInfo = require ( '../../services/app_info' ) ;
2018-04-20 00:12:01 -04:00
const eventService = require ( '../../services/events' ) ;
const cls = require ( '../../services/cls' ) ;
2018-07-24 20:35:03 +02:00
const sqlInit = require ( '../../services/sql_init' ) ;
2019-01-04 18:58:46 +01:00
const sql = require ( '../../services/sql' ) ;
2019-06-23 21:22:08 +02:00
const optionService = require ( '../../services/options' ) ;
const ApiToken = require ( '../../entities/api_token' ) ;
2017-10-28 19:55:55 -04:00
2020-06-20 12:31:38 +02:00
function loginSync ( req ) {
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 ) {
2020-05-29 22:06:36 +02:00
return [ 401 , { message : 'Auth request time is out of sync, please check that both client and server have correct time.' } ] ;
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
}
req . session . loggedIn = true ;
2018-03-30 19:31:22 -04:00
return {
2019-01-04 18:58:46 +01:00
sourceId : sourceIdService . getCurrentSourceId ( ) ,
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
2020-06-20 12:31:38 +02:00
function loginToProtectedSession ( req ) {
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 ) ;
2017-11-09 23:25:23 -05:00
2018-04-20 00:12:01 -04:00
const protectedSessionId = protectedSessionService . setDataKey ( decryptedDataKey ) ;
2018-04-21 12:23:35 -04:00
// this is set here so that event handlers have access to the protected session
2020-06-15 17:56:53 +02:00
cls . set ( 'protectedSessionId' , protectedSessionId ) ;
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
2018-03-30 19:31:22 -04:00
return {
2017-11-09 23:25:23 -05:00
success : true ,
protectedSessionId : protectedSessionId
2018-03-30 19:31:22 -04:00
} ;
}
2017-11-09 23:25:23 -05:00
2020-06-20 12:31:38 +02:00
function token ( req ) {
2019-06-23 21:22:08 +02:00
const username = req . body . username ;
const password = req . body . password ;
2020-06-20 12:31:38 +02:00
const isUsernameValid = username === optionService . getOption ( 'username' ) ;
const isPasswordValid = passwordEncryptionService . verifyPassword ( password ) ;
2019-06-23 21:22:08 +02:00
if ( ! isUsernameValid || ! isPasswordValid ) {
return [ 401 , "Incorrect username/password" ] ;
}
2020-06-20 12:31:38 +02:00
const apiToken = new ApiToken ( {
2019-06-23 21:22:08 +02:00
token : utils . randomSecureToken ( )
} ) . save ( ) ;
return {
token : apiToken . token
} ;
}
2018-03-30 19:31:22 -04:00
module . exports = {
loginSync ,
2019-06-23 21:22:08 +02:00
loginToProtectedSession ,
token
2020-05-29 22:06:36 +02:00
} ;