2013-08-30 17:56:53 +02:00
/ *
2015-03-09 15:45:35 +01:00
Copyright 2008 - 2015 Clipperz Srl
2013-08-30 17:56:53 +02:00
This file is part of Clipperz , the online password manager .
For further information about its features and functionalities please
refer to http : //www.clipperz.com.
* Clipperz is free software : you can redistribute it and / or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
* Clipperz is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU Affero General Public License for more details .
* You should have received a copy of the GNU Affero General Public
License along with Clipperz . If not , see http : //www.gnu.org/licenses/.
* /
try { if ( typeof ( Clipperz . PM . Proxy . Offline ) == 'undefined' ) { throw "" ; } } catch ( e ) {
throw "Clipperz.PM.Proxy.Offline.DataStore depends on Clipperz.PM.Proxy.Offline!" ;
}
//=============================================================================
Clipperz . PM . Proxy . Offline . DataStore = function ( args ) {
args = args || { } ;
this . _data = args . data || ( typeof ( _clipperz _dump _data _ ) != 'undefined' ? _clipperz _dump _data _ : null ) ;
this . _isReadOnly = ( typeof ( args . readOnly ) == 'undefined' ? true : args . readOnly ) ;
this . _shouldPayTolls = args . shouldPayTolls || false ;
this . _tolls = { } ;
this . _currentStaticConnection = null ;
2014-07-28 18:07:48 +02:00
2015-11-23 16:10:44 +01:00
this . NETWORK _SIMULATED _SPEED = 100 * 1024 ;
2013-08-30 17:56:53 +02:00
return this ;
}
Clipperz . Base . extend ( Clipperz . PM . Proxy . Offline . DataStore , Object , {
//-------------------------------------------------------------------------
'isReadOnly' : function ( ) {
return this . _isReadOnly ;
} ,
2014-07-28 18:07:48 +02:00
2013-08-30 17:56:53 +02:00
'canRegisterNewUsers' : function ( ) {
return false ;
} ,
//-------------------------------------------------------------------------
'shouldPayTolls' : function ( ) {
return this . _shouldPayTolls ;
} ,
//-------------------------------------------------------------------------
'data' : function ( ) {
return this . _data ;
} ,
//-------------------------------------------------------------------------
'tolls' : function ( ) {
return this . _tolls ;
} ,
//=========================================================================
'resetData' : function ( ) {
this . _data = {
'users' : {
'catchAllUser' : {
_ _masterkey _test _value _ _ : 'masterkey' ,
s : '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00' ,
v : '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00'
}
}
} ;
} ,
//-------------------------------------------------------------------------
'setupWithEncryptedData' : function ( someData ) {
this . _data = Clipperz . Base . deepClone ( someData ) ;
} ,
//-------------------------------------------------------------------------
2015-06-27 19:08:20 +02:00
// Should this be updated to include OTP field?
2013-08-30 17:56:53 +02:00
'setupWithData' : function ( someData ) {
var deferredResult ;
var resultData ;
var i , c ;
//Clipperz.log(">>> Proxy.Test.setupWithData");
resultData = this . _data ;
deferredResult = new Clipperz . Async . Deferred ( "Proxy.Test.seupWithData" , { trace : false } ) ;
c = someData [ 'users' ] . length ;
for ( i = 0 ; i < c ; i ++ ) {
var newConnection ;
var recordConfiguration ;
deferredResult . addMethod ( this , 'userSerializedEncryptedData' , someData [ 'users' ] [ i ] ) ;
deferredResult . addCallback ( MochiKit . Base . bind ( function ( aUserSerializationContext ) {
resultData [ 'users' ] [ aUserSerializationContext [ 'credentials' ] [ 'C' ] ] = {
's' : aUserSerializationContext [ 'credentials' ] [ 's' ] ,
'v' : aUserSerializationContext [ 'credentials' ] [ 'v' ] ,
'version' : aUserSerializationContext [ 'data' ] [ 'connectionVersion' ] ,
'userDetails' : aUserSerializationContext [ 'encryptedData' ] [ 'user' ] [ 'header' ] ,
'userDetailsVersion' : aUserSerializationContext [ 'encryptedData' ] [ 'user' ] [ 'version' ] ,
'statistics' : aUserSerializationContext [ 'encryptedData' ] [ 'user' ] [ 'statistics' ] ,
'lock' : aUserSerializationContext [ 'encryptedData' ] [ 'user' ] [ 'lock' ] ,
'records' : this . rearrangeRecordsData ( aUserSerializationContext [ 'encryptedData' ] [ 'records' ] )
}
} , this ) ) ;
}
deferredResult . addCallback ( MochiKit . Base . bind ( function ( ) {
this . _data = resultData ;
} , this ) ) ;
deferredResult . callback ( ) ;
//Clipperz.log("<<< Proxy.Test.setupWithData");
return deferredResult ;
} ,
//=========================================================================
'getTollForRequestType' : function ( aRequestType ) {
var result ;
var targetValue ;
var cost ;
targetValue = Clipperz . Crypto . PRNG . defaultRandomGenerator ( ) . getRandomBytes ( 32 ) . toHexString ( ) . substring ( 2 ) ;
switch ( aRequestType ) {
case 'REGISTER' :
cost = 5 ;
break ;
case 'CONNECT' :
cost = 5 ;
break ;
case 'MESSAGE' :
cost = 2 ;
break ;
}
result = {
requestType : aRequestType ,
targetValue : targetValue ,
cost : cost
}
if ( this . shouldPayTolls ( ) ) {
this . tolls ( ) [ targetValue ] = result ;
}
return result ;
} ,
//-------------------------------------------------------------------------
'checkToll' : function ( aFunctionName , someParameters ) {
if ( this . shouldPayTolls ( ) ) {
var localToll ;
var tollParameters ;
tollParameters = someParameters [ 'toll' ] ;
localToll = this . tolls ( ) [ tollParameters [ 'targetValue' ] ] ;
if ( localToll != null ) {
if ( ! Clipperz . PM . Toll . validate ( tollParameters [ 'targetValue' ] , tollParameters [ 'toll' ] , localToll [ 'cost' ] ) ) {
throw "Toll value too low." ;
} ;
} else {
throw "Missing toll" ;
}
}
} ,
//=========================================================================
'currentStaticConnection' : function ( ) {
if ( this . _currentStaticConnection == null ) {
this . _currentStaticConnection = { } ;
}
return this . _currentStaticConnection ;
} ,
//-------------------------------------------------------------------------
'getConnectionForRequest' : function ( aFunctionName , someParameters ) {
var result ;
if ( this . shouldPayTolls ( ) ) {
if ( ( typeof ( someParameters [ 'toll' ] ) != 'undefined' ) && ( typeof ( someParameters [ 'toll' ] [ 'targetValue' ] ) != 'undefined' ) ) {
result = this . tolls ( ) [ someParameters [ 'toll' ] [ 'targetValue' ] ] [ 'connection' ] ;
if ( typeof ( result ) == 'undefined' ) {
result = { } ;
}
} else {
result = { } ;
}
} else {
result = this . currentStaticConnection ( ) ;
}
return result ;
} ,
//-------------------------------------------------------------------------
'storeConnectionForRequestWithConnectionAndResponse' : function ( aFunctionName , someParameters , aConnection , aResponse ) {
if ( this . shouldPayTolls ( ) ) {
if ( ( typeof ( aResponse [ 'toll' ] ) != 'undefined' )
&& ( typeof ( aResponse [ 'toll' ] [ 'targetValue' ] ) != 'undefined' )
&& ( typeof ( this . tolls ( ) [ aResponse [ 'toll' ] [ 'targetValue' ] ] ) != 'undefined' )
) {
this . tolls ( ) [ aResponse [ 'toll' ] [ 'targetValue' ] ] [ 'connection' ] = aConnection ;
}
}
} ,
//=========================================================================
2015-11-23 16:10:44 +01:00
'processMessage' : function ( aFunctionName , someParameters , someOptionalParameters ) {
2015-09-23 10:24:49 +02:00
var deferredResult ;
2015-11-23 16:10:44 +01:00
2015-09-23 10:24:49 +02:00
try {
var result ;
var connection ;
connection = this . getConnectionForRequest ( aFunctionName , someParameters ) ;
switch ( aFunctionName ) {
case 'knock' :
result = this . _knock ( connection , someParameters ) ;
break ;
case 'registration' :
this . checkToll ( aFunctionName , someParameters ) ;
result = this . _registration ( connection , someParameters . parameters ) ;
break ;
case 'handshake' :
this . checkToll ( aFunctionName , someParameters ) ;
result = this . _handshake ( connection , someParameters . parameters ) ;
break ;
case 'message' :
this . checkToll ( aFunctionName , someParameters ) ;
result = this . _message ( connection , someParameters . parameters ) ;
break ;
case 'logout' :
this . _currentStaticConnection = null ;
result = this . _logout ( connection , someParameters . parameters ) ;
break ;
}
2013-08-30 17:56:53 +02:00
2015-09-23 10:24:49 +02:00
this . storeConnectionForRequestWithConnectionAndResponse ( aFunctionName , someParameters , connection , result ) ;
2013-08-30 17:56:53 +02:00
2015-11-23 16:10:44 +01:00
deferredResult = MochiKit . Async . succeed ( result )
2015-09-23 10:24:49 +02:00
} catch ( exception ) {
deferredResult = MochiKit . Async . fail ( exception ) ;
2013-08-30 17:56:53 +02:00
}
2015-09-23 10:24:49 +02:00
return deferredResult ;
2013-08-30 17:56:53 +02:00
} ,
2015-11-23 16:10:44 +01:00
//-------------------------------------------------------------------------
uploadAttachment : function ( someArguments , aProgressCallback , aSharedSecret , aToll ) {
var connection = this . currentStaticConnection ( ) ;
var attachmentReference = someArguments [ 'attachmentReference' ] ;
2015-11-25 11:42:18 +01:00
var payloadSize = someArguments [ 'arrayBufferData' ] . length ;
var resultValue = {
result : { } ,
toll : this . getTollForRequestType ( 'MESSAGE' )
} ;
2015-11-23 16:10:44 +01:00
if ( this . isReadOnly ( ) == false ) {
connection [ 'userData' ] [ 'attachments' ] [ attachmentReference ] = {
'record' : someArguments [ 'recordReference' ] ,
'status' : 'AVAILABLE' ,
'data' : someArguments [ 'arrayBufferData' ] ,
'version' : someArguments [ 'version' ] ,
} ;
2015-11-25 11:42:18 +01:00
return Clipperz . Async . callbacks ( "Proxy.Offline.DataStore.uploadAttachment" , [
MochiKit . Base . method ( this , 'simulateNetworkDelay' , payloadSize , aProgressCallback , resultValue ) ,
function ( ) { return resultValue ; } ,
] , { trace : false } ) ;
2015-11-23 16:10:44 +01:00
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
}
} ,
downloadAttachment : function ( someArguments , aProgressCallback , aSharedSecret , aToll ) {
2015-11-25 11:42:18 +01:00
var connection = this . currentStaticConnection ( ) ;
var reference = someArguments [ 'reference' ] ;
var resultData = connection [ 'userData' ] [ 'attachments' ] [ reference ] [ 'data' ] ;
var resultValue = {
result : resultData ,
// toll: this.getTollForRequestType('MESSAGE')
} ;
2015-11-23 16:10:44 +01:00
2015-11-25 11:42:18 +01:00
return Clipperz . Async . callbacks ( "Proxy.Offline.DataStore.downloadAttachment" , [
MochiKit . Base . method ( this , 'simulateNetworkDelay' , resultData . length , aProgressCallback , resultValue ) ,
function ( ) { return resultValue ; } ,
] , { trace : false } ) ;
2015-11-23 16:10:44 +01:00
} ,
2015-11-25 11:42:18 +01:00
simulateNetworkDelay : function ( payloadSize , progressCallback ) {
2015-11-23 16:10:44 +01:00
var deferredResult ;
var i ;
deferredResult = new Clipperz . Async . Deferred ( "Proxy.Offline.DataStore.simulateNetworkDelay" , { trace : false } ) ;
for ( i = 0 ; i < payloadSize / this . NETWORK _SIMULATED _SPEED ; i ++ ) {
var loaded = i * this . NETWORK _SIMULATED _SPEED ;
deferredResult . addCallback ( MochiKit . Async . wait , 1 ) ;
deferredResult . addMethod ( this , 'runProgressCallback' , progressCallback , loaded , payloadSize ) ;
}
deferredResult . callback ( ) ;
return deferredResult ;
} ,
runProgressCallback : function ( aCallback , aLoadedValue , aTotalValue ) {
var fakeProgressEvent = {
'lengthComputable' : true ,
'loaded' : aLoadedValue ,
'total' : aTotalValue ,
}
return aCallback ( fakeProgressEvent ) ;
} ,
2013-08-30 17:56:53 +02:00
//=========================================================================
'_knock' : function ( aConnection , someParameters ) {
var result ;
result = {
toll : this . getTollForRequestType ( someParameters [ 'requestType' ] )
}
return result ;
} ,
//-------------------------------------------------------------------------
'_registration' : function ( aConnection , someParameters ) {
if ( this . isReadOnly ( ) == false ) {
if ( typeof ( this . data ( ) [ 'users' ] [ someParameters [ 'credentials' ] [ 'C' ] ] ) == 'undefined' ) {
this . data ( ) [ 'users' ] [ someParameters [ 'credentials' ] [ 'C' ] ] = {
's' : someParameters [ 'credentials' ] [ 's' ] ,
'v' : someParameters [ 'credentials' ] [ 'v' ] ,
'version' : someParameters [ 'credentials' ] [ 'version' ] ,
2015-10-27 14:31:39 +01:00
'lock' : Clipperz . PM . Crypto . randomKey ( ) ,
2013-08-30 17:56:53 +02:00
'userDetails' : someParameters [ 'user' ] [ 'header' ] ,
'statistics' : someParameters [ 'user' ] [ 'statistics' ] ,
'userDetailsVersion' : someParameters [ 'user' ] [ 'version' ] ,
2015-07-20 10:27:28 +02:00
'records' : { } ,
'accountInfo' : Clipperz . PM . Proxy . Offline . DataStore . defaultAccountInfo
2013-08-30 17:56:53 +02:00
}
} else {
throw "user already exists" ;
}
} else {
2014-07-28 18:07:48 +02:00
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
2013-08-30 17:56:53 +02:00
}
result = {
result : {
'lock' : this . data ( ) [ 'users' ] [ someParameters [ 'credentials' ] [ 'C' ] ] [ 'lock' ] ,
'result' : 'done'
2014-07-28 18:07:48 +02:00
} ,
2013-08-30 17:56:53 +02:00
toll : this . getTollForRequestType ( 'CONNECT' )
}
return result ;
} ,
//-------------------------------------------------------------------------
'_handshake' : function ( aConnection , someParameters ) {
var result ;
var nextTollRequestType ;
result = { } ;
if ( someParameters . message == "connect" ) {
var userData ;
2015-06-27 19:08:20 +02:00
var otpsData , userOTPs ;
2013-08-30 17:56:53 +02:00
var randomBytes ;
var v ;
2015-08-26 10:13:29 +02:00
if ( typeof ( this . data ( ) [ 'onetimePasswords' ] ) == 'undefined' ) {
this . data ( ) [ 'onetimePasswords' ] = { } ;
}
2013-08-30 17:56:53 +02:00
userData = this . data ( ) [ 'users' ] [ someParameters . parameters . C ] ;
2015-08-26 10:13:29 +02:00
otpsData = this . data ( ) [ 'onetimePasswords' ] ;
2015-06-27 19:08:20 +02:00
2015-11-23 16:10:44 +01:00
if ( ! userData [ 'attachments' ] ) {
userData [ 'attachments' ] = { } ;
}
2015-06-27 19:08:20 +02:00
userOTPs = { } ;
MochiKit . Base . map ( function ( aOTP ) {
if ( aOTP [ 'user' ] == someParameters . parameters . C ) {
userOTPs [ aOTP [ 'key' ] ] = aOTP ;
}
} , MochiKit . Base . values ( otpsData ) ) ;
2013-08-30 17:56:53 +02:00
if ( ( typeof ( userData ) != 'undefined' ) && ( userData [ 'version' ] == someParameters . version ) ) {
aConnection [ 'userData' ] = userData ;
2015-06-27 19:08:20 +02:00
aConnection [ 'userOTPs' ] = userOTPs ;
2013-08-30 17:56:53 +02:00
aConnection [ 'C' ] = someParameters . parameters . C ;
} else {
aConnection [ 'userData' ] = this . data ( ) [ 'users' ] [ 'catchAllUser' ] ;
}
randomBytes = Clipperz . Crypto . Base . generateRandomSeed ( ) ;
aConnection [ 'b' ] = new Clipperz . Crypto . BigInt ( randomBytes , 16 ) ;
v = new Clipperz . Crypto . BigInt ( aConnection [ 'userData' ] [ 'v' ] , 16 ) ;
2014-07-28 18:07:48 +02:00
aConnection [ 'B' ] = ( Clipperz . Crypto . SRP . k ( ) . multiply ( v ) ) . add ( Clipperz . Crypto . SRP . g ( ) . powerModule ( aConnection [ 'b' ] , Clipperz . Crypto . SRP . n ( ) ) ) ;
2013-08-30 17:56:53 +02:00
aConnection [ 'A' ] = someParameters . parameters . A ;
result [ 's' ] = aConnection [ 'userData' ] [ 's' ] ;
result [ 'B' ] = aConnection [ 'B' ] . asString ( 16 ) ;
nextTollRequestType = 'CONNECT' ;
} else if ( someParameters . message == "credentialCheck" ) {
2014-07-28 18:07:48 +02:00
var v , u , s , S , A , K , M1 ;
var stringHash = function ( aValue ) {
return Clipperz . PM . Crypto . encryptingFunctions . versions [ someParameters . version ] . hash ( new Clipperz . ByteArray ( aValue ) ) . toHexString ( ) . substring ( 2 ) ;
} ;
2013-08-30 17:56:53 +02:00
v = new Clipperz . Crypto . BigInt ( aConnection [ 'userData' ] [ 'v' ] , 16 ) ;
A = new Clipperz . Crypto . BigInt ( aConnection [ 'A' ] , 16 ) ;
2014-07-28 18:07:48 +02:00
u = new Clipperz . Crypto . BigInt ( Clipperz . PM . Crypto . encryptingFunctions . versions [ someParameters . version ] . hash ( new Clipperz . ByteArray ( A . asString ( 10 ) + aConnection [ 'B' ] . asString ( 10 ) ) ) . toHexString ( ) , 16 ) ;
s = new Clipperz . Crypto . BigInt ( aConnection [ 'userData' ] [ 's' ] , 16 ) ;
2013-08-30 17:56:53 +02:00
S = ( A . multiply ( v . powerModule ( u , Clipperz . Crypto . SRP . n ( ) ) ) ) . powerModule ( aConnection [ 'b' ] , Clipperz . Crypto . SRP . n ( ) ) ;
2014-07-28 18:07:48 +02:00
K = stringHash ( S . asString ( 10 ) ) ;
2013-08-30 17:56:53 +02:00
2014-07-28 18:07:48 +02:00
M1 = stringHash (
"597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
stringHash ( aConnection [ 'C' ] ) +
s . asString ( 10 ) +
A . asString ( 10 ) +
aConnection [ 'B' ] . asString ( 10 ) +
K
) ;
2013-08-30 17:56:53 +02:00
if ( someParameters . parameters . M1 == M1 ) {
var M2 ;
2014-07-28 18:07:48 +02:00
M2 = stringHash (
A . asString ( 10 ) +
someParameters . parameters . M1 +
K
) ;
2013-08-30 17:56:53 +02:00
result [ 'M2' ] = M2 ;
2015-01-21 18:25:58 +01:00
result [ 'accountInfo' ] = aConnection [ 'userData' ] [ 'accountInfo' ] ;
2015-09-30 20:09:58 +02:00
result [ 'lock' ] = ( aConnection [ 'userData' ] [ 'lock' ] ) ? aConnection [ 'userData' ] [ 'lock' ] : '<<LOCK>>' ;
2013-08-30 17:56:53 +02:00
} else {
throw new Error ( "Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters . parameters . M1 + ">." , "Error" ) ;
}
nextTollRequestType = 'MESSAGE' ;
} else if ( someParameters . message == "oneTimePassword" ) {
2015-08-26 10:13:29 +02:00
var otpData = this . getOneTimePasswordFromKey ( someParameters . parameters . oneTimePasswordKey ) ;
2013-08-30 17:56:53 +02:00
try {
if ( typeof ( otpData ) != 'undefined' ) {
if ( otpData [ 'status' ] == 'ACTIVE' ) {
2015-08-26 10:13:29 +02:00
if ( otpData [ 'keyChecksum' ] == someParameters . parameters . oneTimePasswordKeyChecksum ) {
2013-08-30 17:56:53 +02:00
result = {
'data' : otpData [ 'data' ] ,
'version' : otpData [ 'version' ]
}
2015-08-26 10:13:29 +02:00
otpData [ 'status' ] = 'USED' ;
2013-08-30 17:56:53 +02:00
} else {
otpData [ 'status' ] = 'DISABLED' ;
2015-08-26 10:13:29 +02:00
2013-08-30 17:56:53 +02:00
throw "The requested One Time Password has been disabled, due to a wrong keyChecksum" ;
}
} else {
throw "The requested One Time Password was not active" ;
}
} else {
throw "The requested One Time Password has not been found"
}
} catch ( exception ) {
2015-08-26 10:13:29 +02:00
// console.log("connect.oneTimePassword: Exception!", exception);
2013-08-30 17:56:53 +02:00
result = {
'data' : Clipperz . PM . Crypto . randomKey ( ) ,
'version' : Clipperz . PM . Connection . communicationProtocol . currentVersion
}
}
nextTollRequestType = 'CONNECT' ;
} else {
Clipperz . logError ( "Clipperz.PM.Proxy.Test.handshake - unhandled message: " + someParameters . message ) ;
}
result = {
result : result ,
2015-09-23 10:24:49 +02:00
toll : this . getTollForRequestType ( nextTollRequestType ) ,
2013-08-30 17:56:53 +02:00
}
return result ;
} ,
//-------------------------------------------------------------------------
2015-11-23 16:10:44 +01:00
'_message' : function ( aConnection , someParameters , someOptionalParameters ) {
2013-08-30 17:56:53 +02:00
var result ;
2015-09-23 10:24:49 +02:00
if ( MochiKit . Base . keys ( aConnection ) . length == 0 ) {
throw ( 'Trying to communicate without an active connection' ) ;
}
2013-08-30 17:56:53 +02:00
result = { } ;
//=====================================================================
//
// R E A D - O N L Y M e t h o d s
//
//=====================================================================
if ( someParameters . message == 'getUserDetails' ) {
var recordsStats ;
var recordReference ;
recordsStats = { } ;
for ( recordReference in aConnection [ 'userData' ] [ 'records' ] ) {
recordsStats [ recordReference ] = {
2014-07-28 18:07:48 +02:00
'accessDate' : aConnection [ 'userData' ] [ 'records' ] [ recordReference ] [ 'accessDate' ] ,
2013-08-30 17:56:53 +02:00
'updateDate' : aConnection [ 'userData' ] [ 'records' ] [ recordReference ] [ 'updateDate' ]
}
}
result [ 'header' ] = this . userDetails ( aConnection ) ;
result [ 'statistics' ] = this . statistics ( aConnection ) ;
result [ 'maxNumberOfRecords' ] = aConnection [ 'userData' ] [ 'maxNumberOfRecords' ] ;
result [ 'version' ] = aConnection [ 'userData' ] [ 'userDetailsVersion' ] ;
result [ 'recordsStats' ] = recordsStats ;
if ( this . isReadOnly ( ) == false ) {
var lock ;
if ( typeof ( aConnection [ 'userData' ] [ 'lock' ] ) == 'undefined' ) {
aConnection [ 'userData' ] [ 'lock' ] = "<<LOCK>>" ;
}
result [ 'lock' ] = aConnection [ 'userData' ] [ 'lock' ] ;
}
//=====================================================================
} else if ( someParameters . message == 'getRecordDetail' ) {
2015-11-23 16:10:44 +01:00
var reference = someParameters [ 'parameters' ] [ 'reference' ] ;
MochiKit . Base . update ( result , aConnection [ 'userData' ] [ 'records' ] [ reference ] ) ;
result [ 'reference' ] = reference ;
result [ 'attachmentStatus' ] = this . attachmentStatus ( aConnection , reference ) ;
//console.log('Proxy.getRecordDetail', result);
2015-08-21 11:42:05 +02:00
} else if ( someParameters . message == 'getAllRecordDetails' ) {
MochiKit . Base . update ( result , aConnection [ 'userData' ] [ 'records' ] ) ;
} else if ( someParameters . message == 'getOneTimePasswordsDetails' ) {
2015-06-27 19:08:20 +02:00
var result = MochiKit . Iter . reduce ( function ( prev , cur ) {
prev [ cur . reference ] = {
'status' : cur . status ,
2015-08-26 10:13:29 +02:00
'usageDate' : cur . usage _date ,
'connection' : {
'ip' : 'n/a' ,
'browser' : 'n/a'
}
2015-06-27 19:08:20 +02:00
} ;
return prev ;
} , MochiKit . Base . values ( aConnection [ 'userOTPs' ] ) , { } ) ;
MochiKit . Base . update ( result , result ) ;
// console.log("Proxy.Offline.DataStore.getOneTimePasswordsDetails:",result);
2013-08-30 17:56:53 +02:00
//=====================================================================
//
// R E A D - W R I T E M e t h o d s
//
//=====================================================================
} else if ( someParameters . message == 'upgradeUserCredentials' ) {
if ( this . isReadOnly ( ) == false ) {
var parameters ;
var credentials ;
parameters = someParameters [ 'parameters' ] ;
credentials = parameters [ 'credentials' ] ;
if ( ( credentials [ 'C' ] == null )
|| ( credentials [ 's' ] == null )
|| ( credentials [ 'v' ] == null )
|| ( credentials [ 'version' ] != Clipperz . PM . Connection . communicationProtocol . currentVersion )
) {
result = Clipperz . PM . DataModel . User . exception . CredentialUpgradeFailed ;
} else {
2015-08-26 10:13:29 +02:00
var key ;
var onetimePasswords = this . data ( ) [ 'onetimePasswords' ] ;
var oldCValue = aConnection [ 'C' ] ;
2013-08-30 17:56:53 +02:00
this . data ( ) [ 'users' ] [ credentials [ 'C' ] ] = aConnection [ 'userData' ] ;
aConnection [ 'C' ] = credentials [ 'C' ] ;
aConnection [ 'userData' ] [ 's' ] = credentials [ 's' ] ;
aConnection [ 'userData' ] [ 'v' ] = credentials [ 'v' ] ;
aConnection [ 'userData' ] [ 'version' ] = credentials [ 'version' ] ;
aConnection [ 'userData' ] [ 'userDetails' ] = parameters [ 'user' ] [ 'header' ] ;
aConnection [ 'userData' ] [ 'userDetailsVersion' ] = parameters [ 'user' ] [ 'version' ] ;
aConnection [ 'userData' ] [ 'statistics' ] = parameters [ 'user' ] [ 'statistics' ] ;
aConnection [ 'userData' ] [ 'lock' ] = parameters [ 'user' ] [ 'lock' ] ;
2015-08-26 10:13:29 +02:00
for ( key in onetimePasswords ) {
onetimePasswords [ key ] [ 'user' ] = credentials [ 'C' ] ;
onetimePasswords [ key ] [ 'data' ] = parameters [ 'oneTimePasswords' ] [ key ] [ 'data' ] ;
onetimePasswords [ key ] [ 'version' ] = parameters [ 'oneTimePasswords' ] [ key ] [ 'version' ] ;
}
2013-08-30 17:56:53 +02:00
delete this . data ( ) [ 'users' ] [ oldCValue ] ;
result = { result : "done" , parameters : parameters } ;
}
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
}
//=====================================================================
/ * } e l s e i f ( s o m e P a r a m e t e r s . m e s s a g e = = ' u p d a t e D a t a ' ) {
if ( this . isReadOnly ( ) == false ) {
var i , c ;
if ( this . userData ( ) [ 'lock' ] != someParameters [ 'parameters' ] [ 'user' ] [ 'lock' ] ) {
throw "the lock attribute is not processed correctly"
}
this . userData ( ) [ 'userDetails' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'header' ] ;
this . userData ( ) [ 'statistics' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'statistics' ] ;
this . userData ( ) [ 'userDetailsVersions' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'version' ] ;
c = someParameters [ 'parameters' ] [ 'records' ] . length ;
for ( i = 0 ; i < c ; i ++ ) {
var currentRecord ;
var currentRecordData ;
currentRecordData = someParameters [ 'parameters' ] [ 'records' ] [ i ] ;
currentRecord = this . userData ( ) [ 'records' ] [ currentRecordData [ 'record' ] [ 'reference' ] ] ;
if ( currentRecord == null ) {
}
currentRecord [ 'data' ] = currentRecordData [ 'record' ] [ 'data' ] ;
currentRecord [ 'version' ] = currentRecordData [ 'record' ] [ 'version' ] ;
currentRecord [ 'currentVersion' ] = currentRecordData [ 'currentRecordVersion' ] [ 'reference' ] ;
currentRecord [ 'versions' ] [ currentRecordData [ 'currentRecordVersion' ] [ 'reference' ] ] = {
'data' : currentRecordData [ 'currentRecordVersion' ] [ 'data' ] ,
'version' : currentRecordData [ 'currentRecordVersion' ] [ 'version' ] ,
'previousVersion' : currentRecordData [ 'currentRecordVersion' ] [ 'previousVersion' ] ,
'previousVersionKey' : currentRecordData [ 'currentRecordVersion' ] [ 'previousVersionKey' ]
}
}
this . userData ( ) [ 'lock' ] = Clipperz . PM . Crypto . randomKey ( ) ;
result [ 'lock' ] = this . userData ( ) [ 'lock' ] ;
result [ 'result' ] = 'done' ;
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
}
* / / /= === === === === === === === === === === === === === === === === === === === === === === ==
} else if ( someParameters . message == 'saveChanges' ) {
if ( this . isReadOnly ( ) == false ) {
2015-11-23 16:10:44 +01:00
//console.log("Proxy.Offline.DataStore.saveChanges: parameters:", someParameters);
//console.log("Proxy.Offline.DataStore.saveChanges: attachments:", aConnection['userData']['attachments']);
var i , c , j , d ;
2013-08-30 17:56:53 +02:00
if ( aConnection [ 'userData' ] [ 'lock' ] != someParameters [ 'parameters' ] [ 'user' ] [ 'lock' ] ) {
throw "the lock attribute is not processed correctly"
}
aConnection [ 'userData' ] [ 'userDetails' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'header' ] ;
aConnection [ 'userData' ] [ 'statistics' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'statistics' ] ;
aConnection [ 'userData' ] [ 'userDetailsVersion' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'version' ] ;
c = someParameters [ 'parameters' ] [ 'records' ] [ 'updated' ] . length ;
for ( i = 0 ; i < c ; i ++ ) {
var currentRecord ;
var currentRecordData ;
currentRecordData = someParameters [ 'parameters' ] [ 'records' ] [ 'updated' ] [ i ] ;
currentRecord = aConnection [ 'userData' ] [ 'records' ] [ currentRecordData [ 'record' ] [ 'reference' ] ] ;
if (
( typeof ( aConnection [ 'userData' ] [ 'records' ] [ currentRecordData [ 'record' ] [ 'reference' ] ] ) == 'undefined' )
&&
( typeof ( currentRecordData [ 'currentRecordVersion' ] ) == 'undefined' )
) {
throw "Record added without a recordVersion" ;
}
if ( currentRecord == null ) {
currentRecord = { } ;
currentRecord [ 'versions' ] = { } ;
currentRecord [ 'creationDate' ] = Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) ) ;
currentRecord [ 'accessDate' ] = Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) ) ;
aConnection [ 'userData' ] [ 'records' ] [ currentRecordData [ 'record' ] [ 'reference' ] ] = currentRecord ;
}
currentRecord [ 'data' ] = currentRecordData [ 'record' ] [ 'data' ] ;
currentRecord [ 'version' ] = currentRecordData [ 'record' ] [ 'version' ] ;
currentRecord [ 'updateDate' ] = Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) ) ;
if ( typeof ( currentRecordData [ 'currentRecordVersion' ] ) != 'undefined' ) {
currentRecord [ 'currentVersion' ] = currentRecordData [ 'currentRecordVersion' ] [ 'reference' ] ;
currentRecord [ 'versions' ] [ currentRecordData [ 'currentRecordVersion' ] [ 'reference' ] ] = {
'data' : currentRecordData [ 'currentRecordVersion' ] [ 'data' ] ,
'version' : currentRecordData [ 'currentRecordVersion' ] [ 'version' ] ,
'previousVersion' : currentRecordData [ 'currentRecordVersion' ] [ 'previousVersion' ] ,
'previousVersionKey' : currentRecordData [ 'currentRecordVersion' ] [ 'previousVersionKey' ] ,
'creationDate' : Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) ) ,
'updateDate' : Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) ) ,
'accessDate' : Clipperz . PM . Date . formatDateWithUTCFormat ( new Date ( ) )
}
}
2015-11-23 16:10:44 +01:00
this . pruneAttachments ( aConnection , currentRecordData [ 'record' ] [ 'reference' ] , currentRecordData [ 'attachments' ] ) ;
2013-08-30 17:56:53 +02:00
}
2015-11-23 16:10:44 +01:00
//console.log("Proxy.Offline.DataStore.saveChanges: attachments:", aConnection['userData']['attachments']);
2013-08-30 17:56:53 +02:00
c = someParameters [ 'parameters' ] [ 'records' ] [ 'deleted' ] . length ;
for ( i = 0 ; i < c ; i ++ ) {
var currentRecordReference ;
currentRecordReference = someParameters [ 'parameters' ] [ 'records' ] [ 'deleted' ] [ i ] ;
delete aConnection [ 'userData' ] [ 'records' ] [ currentRecordReference ] ;
}
aConnection [ 'userData' ] [ 'lock' ] = Clipperz . PM . Crypto . randomKey ( ) ;
result [ 'lock' ] = aConnection [ 'userData' ] [ 'lock' ] ;
result [ 'result' ] = 'done' ;
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
}
//=====================================================================
2015-06-27 19:08:20 +02:00
} else if ( someParameters . message == 'addNewOneTimePassword' ) {
if ( this . isReadOnly ( ) == false ) {
//console.log("Proxy.Offline.DataStore.addNewOneTimePassword: someParameters:", someParameters);
var otpKey = someParameters [ 'parameters' ] [ 'oneTimePassword' ] . key ;
2015-08-26 10:13:29 +02:00
var otpReference = someParameters [ 'parameters' ] [ 'oneTimePassword' ] . reference ;
2015-06-27 19:08:20 +02:00
if ( aConnection [ 'userData' ] [ 'lock' ] != someParameters [ 'parameters' ] [ 'user' ] [ 'lock' ] ) {
throw "the lock attribute is not processed correctly"
}
aConnection [ 'userData' ] [ 'userDetails' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'header' ] ;
aConnection [ 'userData' ] [ 'statistics' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'statistics' ] ;
aConnection [ 'userData' ] [ 'userDetailsVersion' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'version' ] ;
aConnection [ 'userOTPs' ] [ otpKey ] = someParameters [ 'parameters' ] [ 'oneTimePassword' ] ;
aConnection [ 'userOTPs' ] [ otpKey ] [ 'user' ] = aConnection [ 'C' ] ;
aConnection [ 'userOTPs' ] [ otpKey ] [ 'status' ] = 'ACTIVE' ;
aConnection [ 'userOTPs' ] [ otpKey ] [ 'creation_date' ] = new Date ( ) . toISOString ( ) . substr ( 0 , 19 ) . replace ( 'T' , ' ' ) ; // Not an elegant way to give the date the same format as the others
aConnection [ 'userOTPs' ] [ otpKey ] [ 'request_date' ] = "4001-01-01 09:00:00" ;
aConnection [ 'userOTPs' ] [ otpKey ] [ 'usage_date' ] = "4001-01-01 09:00:00" ;
2015-08-26 10:13:29 +02:00
this . data ( ) [ 'onetimePasswords' ] [ otpReference ] = aConnection [ 'userOTPs' ] [ otpKey ] ;
2015-06-27 19:08:20 +02:00
//console.log("Proxy.Offline.DataStore.addNewOneTimePassword: aConnection:", aConnection);
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
}
} else if ( someParameters . message == 'updateOneTimePasswords' ) {
if ( this . isReadOnly ( ) == false ) {
2015-08-26 23:03:41 +02:00
//console.log("Proxy.Offline.DataStore.updateOneTimePasswords: someParameters:", someParameters);
2015-06-27 19:08:20 +02:00
if ( aConnection [ 'userData' ] [ 'lock' ] != someParameters [ 'parameters' ] [ 'user' ] [ 'lock' ] ) {
throw "the lock attribute is not processed correctly"
}
aConnection [ 'userData' ] [ 'userDetails' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'header' ] ;
aConnection [ 'userData' ] [ 'statistics' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'statistics' ] ;
aConnection [ 'userData' ] [ 'userDetailsVersion' ] = someParameters [ 'parameters' ] [ 'user' ] [ 'version' ] ;
2015-08-26 23:03:41 +02:00
//console.log("Proxy.Offline.DataStore.updateOneTimePasswords: userOTPs:", aConnection['userOTPs']);
2015-06-27 19:08:20 +02:00
MochiKit . Base . map ( function ( aOTP ) {
if ( someParameters [ 'parameters' ] [ 'oneTimePasswords' ] . indexOf ( aOTP . reference ) < 0 ) {
delete aConnection [ 'userOTPs' ] [ aOTP . key ] ;
}
} , MochiKit . Base . values ( aConnection [ 'userOTPs' ] ) ) ;
} else {
throw Clipperz . PM . Proxy . Offline . DataStore . exception . ReadOnly ;
2015-11-23 16:10:44 +01:00
}
2015-06-27 19:08:20 +02:00
//=====================================================================
2013-08-30 17:56:53 +02:00
//
// U N H A N D L E D M e t h o d
//
//=====================================================================
} else {
2015-06-27 19:08:20 +02:00
Clipperz . logError ( "Clipperz.PM.Proxy.Test.message - unhandled message (Proxy.Offline.DataStore): " + someParameters . message ) ;
2013-08-30 17:56:53 +02:00
}
result = {
result : result ,
toll : this . getTollForRequestType ( 'MESSAGE' )
}
// return MochiKit.Async.succeed(result);
return result ;
} ,
//-------------------------------------------------------------------------
'_logout' : function ( someParameters ) {
// return MochiKit.Async.succeed({result: 'done'});
return { result : 'done' } ;
} ,
//=========================================================================
//#########################################################################
2015-08-26 10:13:29 +02:00
'getOneTimePasswordFromKey' : function ( aKey ) {
var result , i ;
var onetimePasswordsValues = MochiKit . Base . values ( this . data ( ) [ 'onetimePasswords' ] ) ;
for ( i = 0 ; i < onetimePasswordsValues . length ; i ++ ) {
if ( onetimePasswordsValues [ i ] [ 'key' ] == aKey ) {
result = onetimePasswordsValues [ i ] ;
}
}
return result ;
} ,
//=========================================================================
2013-08-30 17:56:53 +02:00
'isTestData' : function ( aConnection ) {
return ( typeof ( aConnection [ 'userData' ] [ '__masterkey_test_value__' ] ) != 'undefined' ) ;
} ,
'userDetails' : function ( aConnection ) {
var result ;
if ( this . isTestData ( aConnection ) ) {
var serializedHeader ;
var version ;
//Clipperz.logDebug("### test data");
version = aConnection [ 'userData' ] [ 'userDetailsVersion' ] ;
serializedHeader = Clipperz . Base . serializeJSON ( aConnection [ 'userData' ] [ 'userDetails' ] ) ;
result = Clipperz . PM . Crypto . encryptingFunctions . versions [ version ] . encrypt ( aConnection [ 'userData' ] [ '__masterkey_test_value__' ] , serializedHeader ) ;
} else {
//Clipperz.logDebug("### NOT test data");
result = aConnection [ 'userData' ] [ 'userDetails' ] ;
}
return result ;
} ,
'statistics' : function ( aConnection ) {
var result ;
if ( aConnection [ 'userData' ] [ 'statistics' ] != null ) {
if ( this . isTestData ( aConnection ) ) {
var serializedStatistics ;
var version ;
version = aConnection [ 'userData' ] [ 'userDetailsVersion' ] ;
serializedStatistics = Clipperz . Base . serializeJSON ( aConnection [ 'userData' ] [ 'statistics' ] ) ;
result = Clipperz . PM . Crypto . encryptingFunctions . versions [ version ] . encrypt ( aConnection [ 'userData' ] [ '__masterkey_test_value__' ] , serializedStatistics ) ;
} else {
result = aConnection [ 'userData' ] [ 'statistics' ] ;
}
} else {
result = null ;
}
2015-11-23 16:10:44 +01:00
return result ;
} ,
'attachmentStatus' : function ( aConnection , aRecordReference ) {
var result ;
//console.log("Proxy.attachmentStatus: data:", aConnection['userData']['attachments']);
result = { } ;
if ( aConnection [ 'userData' ] [ 'attachments' ] ) {
var reference ;
for ( reference in aConnection [ 'userData' ] [ 'attachments' ] ) {
//console.log("Proxy.attachmentStatus: -> comparison: serverRecordReference, aRecordReference", aConnection['userData']['attachments'][reference]['record'], aRecordReference);
if ( aConnection [ 'userData' ] [ 'attachments' ] [ reference ] [ 'record' ] == aRecordReference ) {
result [ reference ] = aConnection [ 'userData' ] [ 'attachments' ] [ reference ] [ 'status' ] ;
}
}
}
//console.log("Proxy.attachmentStatus: result:", result);
2013-08-30 17:56:53 +02:00
return result ;
} ,
2015-11-23 16:10:44 +01:00
/** Removes all the stored attachments whose reference is not in the given list */
'pruneAttachments' : function ( aConnection , aRecordReference , someAttachmentReferences ) {
if ( aConnection [ 'userData' ] [ 'attachments' ] ) {
var reference ;
for ( reference in aConnection [ 'userData' ] [ 'attachments' ] ) {
var attachment = aConnection [ 'userData' ] [ 'attachments' ] [ reference ] ;
if ( ( attachment [ 'record' ] == aRecordReference ) &&
( someAttachmentReferences . indexOf ( reference ) < 0 )
) {
delete aConnection [ 'userData' ] [ 'attachments' ] [ reference ] ;
}
}
}
} ,
2013-08-30 17:56:53 +02:00
/ *
'userSerializedEncryptedData' : function ( someData ) {
var deferredResult ;
var deferredContext ;
deferredContext = { 'data' : someData } ;
deferredResult = new Clipperz . Async . Deferred ( 'Proxy.Test.serializeUserEncryptedData' , { trace : false } ) ;
deferredResult . addCallback ( MochiKit . Base . bind ( function ( aDeferredContext ) {
aDeferredContext [ 'user' ] = this . createUserUsingConfigurationData ( aDeferredContext [ 'data' ] ) ;
return aDeferredContext ;
} , this ) ) ;
deferredResult . addCallback ( function ( aDeferredContext ) {
// return aDeferredContext['user'].encryptedDataUsingVersion(aDeferredContext['data']['version']);
return aDeferredContext [ 'user' ] . serializedDataUsingVersion ( MochiKit . Base . values ( aDeferredContext [ 'user' ] . records ( ) ) , aDeferredContext [ 'data' ] [ 'version' ] ) ;
} ) ;
deferredResult . addCallback ( function ( aUserEncryptedData ) {
deferredContext [ 'encryptedData' ] = aUserEncryptedData ;
return deferredContext ;
} ) ;
deferredResult . addCallback ( function ( aDeferredContext ) {
var connection ;
connection = new Clipperz . PM . Connection . communicationProtocol . versions [ aDeferredContext [ 'data' ] [ 'connectionVersion' ] ] ( )
aDeferredContext [ 'credentials' ] = connection . serverSideUserCredentials ( aDeferredContext [ 'user' ] . username ( ) , aDeferredContext [ 'user' ] . passphrase ( ) ) ;
return aDeferredContext ;
} ) ;
// deferredResult.addCallback(function(aDeferredContext) {
// return aDeferredContext['user'].serializedDataUsingVersion(MochiKit.Base.values(aDeferredContext['user'].records()), aDeferredContext['data']['version']);
// }, deferredContext);
// deferredResult.addCallback(function(aUserSerializedData) {
// });
//
// deferredResult.addCallback(MochiKit.Async.succeed, deferredContext);
deferredResult . callback ( deferredContext ) ;
return deferredResult ;
} ,
'createUserUsingConfigurationData' : function ( someData ) {
var result ;
var user ;
var recordLabel ;
user = new Clipperz . PM . DataModel . User ( ) ;
user . initForTests ( ) ;
user . setUsername ( someData [ 'username' ] ) ;
user . setPassphrase ( someData [ 'passphrase' ] ) ;
for ( recordLabel in someData [ 'records' ] ) {
var recordData ;
var record ;
var i , c ;
recordData = someData [ 'records' ] [ recordLabel ] ;
record = new Clipperz . PM . DataModel . Record ( { user : user , label : recordLabel } ) ;
record . setNotes ( recordData [ 'notes' ] ) ;
c = recordData [ 'fields' ] . length ;
for ( i = 0 ; i < c ; i ++ ) {
var recordField ;
recordField = new Clipperz . PM . DataModel . RecordField ( ) ;
recordField . setLabel ( recordData [ 'fields' ] [ i ] [ 'name' ] ) ;
recordField . setValue ( recordData [ 'fields' ] [ i ] [ 'value' ] ) ;
recordField . setType ( recordData [ 'fields' ] [ i ] [ 'type' ] ) ;
record . addField ( recordField ) ;
}
user . addRecord ( record , true ) ;
}
result = user ;
return result ;
} ,
* /
//=========================================================================
_ _syntaxFix _ _ : "syntax fix"
} ) ;
Clipperz . PM . Proxy . Offline . DataStore [ 'exception' ] = {
'ReadOnly' : new MochiKit . Base . NamedError ( "Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly" )
2015-07-20 10:27:28 +02:00
} ;
Clipperz . PM . Proxy . Offline . DataStore . defaultAccountInfo = {
'features' : [
'UPDATE_CREDENTIALS' ,
'EDIT_CARD' ,
'CARD_DETAILS' ,
'ADD_CARD' ,
'DELETE_CARD' ,
'OFFLINE_COPY' ,
'LIST_CARDS'
] ,
'paymentVerificationPending' : false ,
'currentSubscriptionType' : 'EARLY_ADOPTER' ,
'isExpiring' : false ,
'latestActiveLevel' : 'EARLY_ADOPTER' ,
'payments' : [ ] ,
'featureSet' : 'FULL' ,
'latestActiveThreshold' : '-1.00000000' ,
'referenceDate' : 'Fri, 03 April 2015 08:17:46 UTC' ,
'isExpired' : false ,
'expirationDate' : 'Mon, 01 January 4001 00:00:00 UTC'
2013-08-30 17:56:53 +02:00
} ;