Use SFJS
This commit is contained in:
@@ -1,18 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var Neeto = window.Neeto = Neeto || {};
|
||||
var SN = SN || {};
|
||||
|
||||
// detect IE8 and above, and edge.
|
||||
// IE and Edge do not support pbkdf2 in WebCrypto, therefore we need to use CryptoJS
|
||||
var IEOrEdge = document.documentMode || /Edge/.test(navigator.userAgent);
|
||||
|
||||
if(!IEOrEdge && (window.crypto && window.crypto.subtle)) {
|
||||
Neeto.crypto = new SNCryptoWeb();
|
||||
} else {
|
||||
Neeto.crypto = new SNCryptoJS();
|
||||
}
|
||||
|
||||
angular.module('app', [])
|
||||
|
||||
function getParameterByName(name, url) {
|
||||
|
||||
@@ -296,9 +296,9 @@ class AccountMenu {
|
||||
}.bind(this)
|
||||
|
||||
if(data.auth_params) {
|
||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, data.auth_params), function(keys){
|
||||
SFJS.crypto.computeEncryptionKeysForUser(_.merge({password: password}, data.auth_params), function(keys){
|
||||
try {
|
||||
EncryptionHelper.decryptMultipleItems(data.items, keys, false); /* throws = false as we don't want to interrupt all decryption if just one fails */
|
||||
SFItemTransformer.decryptMultipleItems(data.items, keys, false); /* throws = false as we don't want to interrupt all decryption if just one fails */
|
||||
// delete items enc_item_key since the user's actually key will do the encrypting once its passed off
|
||||
data.items.forEach(function(item){
|
||||
item.enc_item_key = null;
|
||||
@@ -479,7 +479,7 @@ class AccountMenu {
|
||||
$scope.securityUpdateData.processing = true;
|
||||
var authParams = authManager.getAuthParams();
|
||||
|
||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: $scope.securityUpdateData.password}, authParams), function(keys){
|
||||
SFJS.crypto.computeEncryptionKeysForUser(_.merge({password: $scope.securityUpdateData.password}, authParams), function(keys){
|
||||
if(keys.mk !== authManager.keys().mk) {
|
||||
alert("Invalid password. Please try again.");
|
||||
$timeout(function(){
|
||||
|
||||
@@ -9,7 +9,7 @@ class Item {
|
||||
this.observers = [];
|
||||
|
||||
if(!this.uuid) {
|
||||
this.uuid = Neeto.crypto.generateUUID();
|
||||
this.uuid = SFJS.crypto.generateUUID();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class ItemParams {
|
||||
// Items should always be encrypted for export files. Only respect item.doNotEncrypt for remote sync params;
|
||||
var doNotEncrypt = this.item.doNotEncrypt() && !this.forExportFile;
|
||||
if(this.keys && !doNotEncrypt) {
|
||||
var encryptedParams = EncryptionHelper.encryptItem(this.item, this.keys, this.version);
|
||||
var encryptedParams = SFItemTransformer.encryptItem(this.item, this.keys, this.version);
|
||||
_.merge(params, encryptedParams);
|
||||
|
||||
if(this.version !== "001") {
|
||||
@@ -47,7 +47,7 @@ class ItemParams {
|
||||
}
|
||||
}
|
||||
else {
|
||||
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + Neeto.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
|
||||
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + SFJS.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
|
||||
if(!this.forExportFile) {
|
||||
params.enc_item_key = null;
|
||||
params.auth_hash = null;
|
||||
|
||||
@@ -63,7 +63,7 @@ class ActionsManager {
|
||||
this.httpManager.getAbsolute(action.url, {}, function(response){
|
||||
action.error = false;
|
||||
var items = response.items || [response.item];
|
||||
EncryptionHelper.decryptMultipleItems(items, this.authManager.keys());
|
||||
SFItemTransformer.decryptMultipleItems(items, this.authManager.keys());
|
||||
items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
|
||||
for(var item of items) {
|
||||
item.setDirty(true);
|
||||
@@ -82,7 +82,7 @@ class ActionsManager {
|
||||
|
||||
this.httpManager.getAbsolute(action.url, {}, function(response){
|
||||
action.error = false;
|
||||
EncryptionHelper.decryptItem(response.item, this.authManager.keys());
|
||||
SFItemTransformer.decryptItem(response.item, this.authManager.keys());
|
||||
var item = this.modelManager.createItem(response.item, true /* Dont notify observers */);
|
||||
customCallback({item: item});
|
||||
|
||||
|
||||
@@ -112,11 +112,7 @@ angular.module('app')
|
||||
// which accidentally used 60,000 iterations (now adjusted), which CryptoJS can't handle here (WebCrypto can however).
|
||||
// if user has high password cost and is using browser that doesn't support WebCrypto,
|
||||
// we want to tell them that they can't login with this browser.
|
||||
if(cost > 5000) {
|
||||
return Neeto.crypto instanceof SNCryptoWeb ? true : false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return SFJS.crypto.supportsPasswordDerivationCost(cost);
|
||||
}
|
||||
|
||||
this.login = function(url, email, password, ephemeral, extraParams, callback) {
|
||||
@@ -153,7 +149,7 @@ angular.module('app')
|
||||
return;
|
||||
}
|
||||
|
||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, authParams), function(keys){
|
||||
SFJS.crypto.computeEncryptionKeysForUser(_.merge({password: password}, authParams), function(keys){
|
||||
|
||||
var requestUrl = url + "/auth/sign_in";
|
||||
var params = _.merge({password: keys.pw, email: email}, extraParams);
|
||||
@@ -202,7 +198,7 @@ angular.module('app')
|
||||
}
|
||||
|
||||
this.register = function(url, email, password, ephemeral, callback) {
|
||||
Neeto.crypto.generateInitialEncryptionKeysForUser({password: password, email: email}, function(keys, authParams){
|
||||
SFJS.crypto.generateInitialEncryptionKeysForUser({password: password, email: email}, function(keys, authParams){
|
||||
var requestUrl = url + "/auth";
|
||||
var params = _.merge({password: keys.pw, email: email}, authParams);
|
||||
|
||||
@@ -221,7 +217,7 @@ angular.module('app')
|
||||
}
|
||||
|
||||
this.changePassword = function(email, new_password, callback) {
|
||||
Neeto.crypto.generateInitialEncryptionKeysForUser({password: new_password, email: email}, function(keys, authParams){
|
||||
SFJS.crypto.generateInitialEncryptionKeysForUser({password: new_password, email: email}, function(keys, authParams){
|
||||
var requestUrl = storageManager.getItem("server") + "/auth/change_pw";
|
||||
var params = _.merge({new_password: keys.pw}, authParams);
|
||||
|
||||
|
||||
@@ -716,7 +716,7 @@ class ComponentManager {
|
||||
console.log("Web|componentManager|registerComponentWindow", component);
|
||||
}
|
||||
component.window = componentWindow;
|
||||
component.sessionKey = Neeto.crypto.generateUUID();
|
||||
component.sessionKey = SFJS.crypto.generateUUID();
|
||||
this.sendMessageToComponent(component, {
|
||||
action: "component-registered",
|
||||
sessionKey: component.sessionKey,
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
class SNCrypto {
|
||||
|
||||
generateRandomKey(bits) {
|
||||
return CryptoJS.lib.WordArray.random(bits/8).toString();
|
||||
}
|
||||
|
||||
generateUUID() {
|
||||
var crypto = window.crypto || window.msCrypto;
|
||||
if(crypto) {
|
||||
var buf = new Uint32Array(4);
|
||||
crypto.getRandomValues(buf);
|
||||
var idx = -1;
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
idx++;
|
||||
var r = (buf[idx>>3] >> ((idx%8)*4))&15;
|
||||
var v = c == 'x' ? r : (r&0x3|0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
} else {
|
||||
var d = new Date().getTime();
|
||||
if(window.performance && typeof window.performance.now === "function"){
|
||||
d += performance.now(); //use high-precision timer if available
|
||||
}
|
||||
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = (d + Math.random()*16)%16 | 0;
|
||||
d = Math.floor(d/16);
|
||||
return (c=='x' ? r : (r&0x3|0x8)).toString(16);
|
||||
});
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
|
||||
decryptText({ciphertextToAuth, contentCiphertext, encryptionKey, iv, authHash, authKey} = {}, requiresAuth) {
|
||||
if(requiresAuth && !authHash) {
|
||||
console.error("Auth hash is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(authHash) {
|
||||
var localAuthHash = Neeto.crypto.hmac256(ciphertextToAuth, authKey);
|
||||
if(authHash !== localAuthHash) {
|
||||
console.error("Auth hash does not match, returning null.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var keyData = CryptoJS.enc.Hex.parse(encryptionKey);
|
||||
var ivData = CryptoJS.enc.Hex.parse(iv || "");
|
||||
var decrypted = CryptoJS.AES.decrypt(contentCiphertext, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
|
||||
return decrypted.toString(CryptoJS.enc.Utf8);
|
||||
}
|
||||
|
||||
encryptText(text, key, iv) {
|
||||
var keyData = CryptoJS.enc.Hex.parse(key);
|
||||
var ivData = CryptoJS.enc.Hex.parse(iv || "");
|
||||
var encrypted = CryptoJS.AES.encrypt(text, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
|
||||
return encrypted.toString();
|
||||
}
|
||||
|
||||
generateRandomEncryptionKey() {
|
||||
var salt = Neeto.crypto.generateRandomKey(512);
|
||||
var passphrase = Neeto.crypto.generateRandomKey(512);
|
||||
return CryptoJS.PBKDF2(passphrase, salt, { keySize: 512/32 }).toString();
|
||||
}
|
||||
|
||||
firstHalfOfKey(key) {
|
||||
return key.substring(0, key.length/2);
|
||||
}
|
||||
|
||||
secondHalfOfKey(key) {
|
||||
return key.substring(key.length/2, key.length);
|
||||
}
|
||||
|
||||
base64(text) {
|
||||
return window.btoa(text);
|
||||
}
|
||||
|
||||
base64Decode(base64String) {
|
||||
return window.atob(base64String);
|
||||
}
|
||||
|
||||
sha256(text) {
|
||||
return CryptoJS.SHA256(text).toString();
|
||||
}
|
||||
|
||||
hmac256(message, key) {
|
||||
var keyData = CryptoJS.enc.Hex.parse(key);
|
||||
var messageData = CryptoJS.enc.Utf8.parse(message);
|
||||
var result = CryptoJS.HmacSHA256(messageData, keyData).toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
computeEncryptionKeysForUser({password, pw_salt, pw_cost} = {}, callback) {
|
||||
this.generateSymmetricKeyPair({password: password, pw_salt: pw_salt, pw_cost: pw_cost}, function(keys){
|
||||
callback({pw: keys[0], mk: keys[1], ak: keys[2]});
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
generateInitialEncryptionKeysForUser({email, password} = {}, callback) {
|
||||
var pw_cost = this.defaultPasswordGenerationCost();
|
||||
var pw_nonce = this.generateRandomKey(512);
|
||||
var pw_salt = this.sha256([email, pw_nonce].join(":"));
|
||||
this.generateSymmetricKeyPair({password: password, pw_salt: pw_salt, pw_cost: pw_cost}, function(keys){
|
||||
callback({pw: keys[0], mk: keys[1], ak: keys[2]}, {pw_salt: pw_salt, pw_cost: pw_cost, version: "002"});
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export { SNCrypto }
|
||||
@@ -1,21 +0,0 @@
|
||||
class SNCryptoJS extends SNCrypto {
|
||||
|
||||
/** Generates two deterministic keys based on one input */
|
||||
generateSymmetricKeyPair({password, pw_salt, pw_cost} = {}, callback) {
|
||||
var output = CryptoJS.PBKDF2(password, pw_salt, { keySize: 768/32, hasher: CryptoJS.algo.SHA512, iterations: pw_cost }).toString();
|
||||
|
||||
var outputLength = output.length;
|
||||
var splitLength = outputLength/3;
|
||||
var firstThird = output.slice(0, splitLength);
|
||||
var secondThird = output.slice(splitLength, splitLength * 2);
|
||||
var thirdThird = output.slice(splitLength * 2, splitLength * 3);
|
||||
callback([firstThird, secondThird, thirdThird])
|
||||
}
|
||||
|
||||
defaultPasswordGenerationCost() {
|
||||
return 3000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export { SNCryptoJS }
|
||||
@@ -1,163 +0,0 @@
|
||||
class EncryptionHelper {
|
||||
|
||||
static _private_encryptString(string, encryptionKey, authKey, uuid, version) {
|
||||
var fullCiphertext, contentCiphertext;
|
||||
if(version === "001") {
|
||||
contentCiphertext = Neeto.crypto.encryptText(string, encryptionKey, null);
|
||||
fullCiphertext = version + contentCiphertext;
|
||||
} else {
|
||||
var iv = Neeto.crypto.generateRandomKey(128);
|
||||
contentCiphertext = Neeto.crypto.encryptText(string, encryptionKey, iv);
|
||||
var ciphertextToAuth = [version, uuid, iv, contentCiphertext].join(":");
|
||||
var authHash = Neeto.crypto.hmac256(ciphertextToAuth, authKey);
|
||||
fullCiphertext = [version, authHash, uuid, iv, contentCiphertext].join(":");
|
||||
}
|
||||
|
||||
return fullCiphertext;
|
||||
}
|
||||
|
||||
static encryptItem(item, keys, version = "002") {
|
||||
var params = {};
|
||||
// encrypt item key
|
||||
var item_key = Neeto.crypto.generateRandomEncryptionKey();
|
||||
if(version === "001") {
|
||||
// legacy
|
||||
params.enc_item_key = Neeto.crypto.encryptText(item_key, keys.mk, null);
|
||||
} else {
|
||||
params.enc_item_key = this._private_encryptString(item_key, keys.mk, keys.ak, item.uuid, version);
|
||||
}
|
||||
|
||||
// encrypt content
|
||||
var ek = Neeto.crypto.firstHalfOfKey(item_key);
|
||||
var ak = Neeto.crypto.secondHalfOfKey(item_key);
|
||||
var ciphertext = this._private_encryptString(JSON.stringify(item.createContentJSONFromProperties()), ek, ak, item.uuid, version);
|
||||
if(version === "001") {
|
||||
var authHash = Neeto.crypto.hmac256(ciphertext, ak);
|
||||
params.auth_hash = authHash;
|
||||
}
|
||||
|
||||
params.content = ciphertext;
|
||||
return params;
|
||||
}
|
||||
|
||||
static encryptionComponentsFromString(string, encryptionKey, authKey) {
|
||||
var encryptionVersion = string.substring(0, 3);
|
||||
if(encryptionVersion === "001") {
|
||||
return {
|
||||
contentCiphertext: string.substring(3, string.length),
|
||||
encryptionVersion: encryptionVersion,
|
||||
ciphertextToAuth: string,
|
||||
iv: null,
|
||||
authHash: null,
|
||||
encryptionKey: encryptionKey,
|
||||
authKey: authKey
|
||||
}
|
||||
} else {
|
||||
let components = string.split(":");
|
||||
return {
|
||||
encryptionVersion: components[0],
|
||||
authHash: components[1],
|
||||
uuid: components[2],
|
||||
iv: components[3],
|
||||
contentCiphertext: components[4],
|
||||
ciphertextToAuth: [components[0], components[2], components[3], components[4]].join(":"),
|
||||
encryptionKey: encryptionKey,
|
||||
authKey: authKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static decryptItem(item, keys) {
|
||||
|
||||
if((item.content.startsWith("001") || item.content.startsWith("002")) && item.enc_item_key) {
|
||||
// is encrypted, continue to below
|
||||
} else {
|
||||
// is base64 encoded
|
||||
try {
|
||||
item.content = JSON.parse(Neeto.crypto.base64Decode(item.content.substring(3, item.content.length)));
|
||||
} catch (e) {}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// decrypt encrypted key
|
||||
var encryptedItemKey = item.enc_item_key;
|
||||
var requiresAuth = true;
|
||||
if(encryptedItemKey.startsWith("002") === false) {
|
||||
// legacy encryption type, has no prefix
|
||||
encryptedItemKey = "001" + encryptedItemKey;
|
||||
requiresAuth = false;
|
||||
}
|
||||
var keyParams = this.encryptionComponentsFromString(encryptedItemKey, keys.mk, keys.ak);
|
||||
|
||||
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
||||
if(keyParams.uuid && keyParams.uuid !== item.uuid) {
|
||||
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||
item.errorDecrypting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var item_key = Neeto.crypto.decryptText(keyParams, requiresAuth);
|
||||
|
||||
if(!item_key) {
|
||||
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||
item.errorDecrypting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// decrypt content
|
||||
var ek = Neeto.crypto.firstHalfOfKey(item_key);
|
||||
var ak = Neeto.crypto.secondHalfOfKey(item_key);
|
||||
var itemParams = this.encryptionComponentsFromString(item.content, ek, ak);
|
||||
|
||||
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
||||
if(itemParams.uuid && itemParams.uuid !== item.uuid) {
|
||||
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||
item.errorDecrypting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!itemParams.authHash) {
|
||||
// legacy 001
|
||||
itemParams.authHash = item.auth_hash;
|
||||
}
|
||||
|
||||
var content = Neeto.crypto.decryptText(itemParams, true);
|
||||
if(!content) {
|
||||
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||
item.errorDecrypting = true;
|
||||
} else {
|
||||
if(item.errorDecrypting == true) { item.errorDecryptingValueChanged = true;}
|
||||
// Content should only be set if it was successfully decrypted, and should otherwise remain unchanged.
|
||||
item.errorDecrypting = false;
|
||||
item.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
static decryptMultipleItems(items, keys, throws) {
|
||||
for (var item of items) {
|
||||
|
||||
// 4/15/18: Adding item.content == null clause. We still want to decrypt deleted items incase
|
||||
// they were marked as dirty but not yet synced. Not yet sure why we had this requirement.
|
||||
if(item.deleted == true && item.content == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var isString = typeof item.content === 'string' || item.content instanceof String;
|
||||
if(isString) {
|
||||
try {
|
||||
this.decryptItem(item, keys);
|
||||
} catch (e) {
|
||||
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||
item.errorDecrypting = true;
|
||||
if(throws) {
|
||||
throw e;
|
||||
}
|
||||
console.error("Error decrypting item", item, e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
var subtleCrypto = window.crypto ? window.crypto.subtle : null;
|
||||
|
||||
class SNCryptoWeb extends SNCrypto {
|
||||
|
||||
/**
|
||||
Overrides
|
||||
*/
|
||||
defaultPasswordGenerationCost() {
|
||||
return 101000;
|
||||
}
|
||||
|
||||
/** Generates two deterministic keys based on one input */
|
||||
generateSymmetricKeyPair({password, pw_salt, pw_cost} = {}, callback) {
|
||||
this.stretchPassword({password: password, pw_salt: pw_salt, pw_cost: pw_cost}, function(output){
|
||||
var outputLength = output.length;
|
||||
var splitLength = outputLength/3;
|
||||
var firstThird = output.slice(0, splitLength);
|
||||
var secondThird = output.slice(splitLength, splitLength * 2);
|
||||
var thirdThird = output.slice(splitLength * 2, splitLength * 3);
|
||||
callback([firstThird, secondThird, thirdThird])
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
Internal
|
||||
*/
|
||||
|
||||
stretchPassword({password, pw_salt, pw_cost} = {}, callback) {
|
||||
|
||||
this.webCryptoImportKey(password, function(key){
|
||||
|
||||
if(!key) {
|
||||
console.log("Key is null, unable to continue");
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.webCryptoDeriveBits({key: key, pw_salt: pw_salt, pw_cost: pw_cost}, function(key){
|
||||
if(!key) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(key);
|
||||
|
||||
}.bind(this))
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
webCryptoImportKey(input, callback) {
|
||||
subtleCrypto.importKey(
|
||||
"raw",
|
||||
this.stringToArrayBuffer(input),
|
||||
{name: "PBKDF2"},
|
||||
false,
|
||||
["deriveBits"]
|
||||
)
|
||||
.then(function(key){
|
||||
callback(key);
|
||||
})
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
webCryptoDeriveBits({key, pw_salt, pw_cost} = {}, callback) {
|
||||
subtleCrypto.deriveBits(
|
||||
{
|
||||
"name": "PBKDF2",
|
||||
salt: this.stringToArrayBuffer(pw_salt),
|
||||
iterations: pw_cost,
|
||||
hash: {name: "SHA-512"},
|
||||
},
|
||||
key,
|
||||
768
|
||||
)
|
||||
.then(function(bits){
|
||||
var key = this.arrayBufferToHexString(new Uint8Array(bits));
|
||||
callback(key);
|
||||
}.bind(this))
|
||||
.catch(function(err){
|
||||
console.error(err);
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
stringToArrayBuffer(string) {
|
||||
// not available on Edge/IE
|
||||
|
||||
if(window.TextEncoder) {
|
||||
var encoder = new TextEncoder("utf-8");
|
||||
var result = encoder.encode(string);
|
||||
return result;
|
||||
} else {
|
||||
string = unescape(encodeURIComponent(string));
|
||||
var buf = new ArrayBuffer(string.length);
|
||||
var bufView = new Uint8Array(buf);
|
||||
for (var i=0, strLen=string.length; i<strLen; i++) {
|
||||
bufView[i] = string.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
arrayBufferToHexString(arrayBuffer) {
|
||||
var byteArray = new Uint8Array(arrayBuffer);
|
||||
var hexString = "";
|
||||
var nextHexByte;
|
||||
|
||||
for (var i=0; i<byteArray.byteLength; i++) {
|
||||
nextHexByte = byteArray[i].toString(16);
|
||||
if (nextHexByte.length < 2) {
|
||||
nextHexByte = "0" + nextHexByte;
|
||||
}
|
||||
hexString += nextHexByte;
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
}
|
||||
|
||||
export { SNCryptoWeb }
|
||||
@@ -47,7 +47,7 @@ class ModelManager {
|
||||
// we need to clone this item and give it a new uuid, then delete item with old uuid from db (you can't mofidy uuid's in our indexeddb setup)
|
||||
var newItem = this.createItem(item);
|
||||
|
||||
newItem.uuid = Neeto.crypto.generateUUID();
|
||||
newItem.uuid = SFJS.crypto.generateUUID();
|
||||
|
||||
// Update uuids of relationships
|
||||
newItem.informReferencesOfUUIDChange(item.uuid, newItem.uuid);
|
||||
|
||||
@@ -28,7 +28,7 @@ angular.module('app')
|
||||
|
||||
this.unlock = function(passcode, callback) {
|
||||
var params = this.passcodeAuthParams();
|
||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: passcode}, params), function(keys){
|
||||
SFJS.crypto.computeEncryptionKeysForUser(_.merge({password: passcode}, params), function(keys){
|
||||
if(keys.pw !== params.hash) {
|
||||
callback(false);
|
||||
return;
|
||||
@@ -42,11 +42,11 @@ angular.module('app')
|
||||
}
|
||||
|
||||
this.setPasscode = (passcode, callback) => {
|
||||
var cost = Neeto.crypto.defaultPasswordGenerationCost();
|
||||
var salt = Neeto.crypto.generateRandomKey(512);
|
||||
var cost = SFJS.crypto.defaultPasswordGenerationCost();
|
||||
var salt = SFJS.crypto.generateRandomKey(512);
|
||||
var defaultParams = {pw_cost: cost, pw_salt: salt, version: "002"};
|
||||
|
||||
Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: passcode}, defaultParams), function(keys) {
|
||||
SFJS.crypto.computeEncryptionKeysForUser(_.merge({password: passcode}, defaultParams), function(keys) {
|
||||
defaultParams.hash = keys.pw;
|
||||
this._keys = keys;
|
||||
this._hasPasscode = true;
|
||||
|
||||
@@ -158,7 +158,7 @@ class StorageManager {
|
||||
|
||||
decryptStorage() {
|
||||
var stored = JSON.parse(this.getItem("encryptedStorage", StorageManager.Fixed));
|
||||
EncryptionHelper.decryptItem(stored, this.encryptedStorageKeys);
|
||||
SFItemTransformer.decryptItem(stored, this.encryptedStorageKeys);
|
||||
var encryptedStorage = new EncryptedStorage(stored);
|
||||
|
||||
for(var key of Object.keys(encryptedStorage.storage)) {
|
||||
|
||||
@@ -407,7 +407,7 @@ class SyncManager {
|
||||
|
||||
handleItemsResponse(responseItems, omitFields, source) {
|
||||
var keys = this.authManager.keys() || this.passcodeManager.keys();
|
||||
EncryptionHelper.decryptMultipleItems(responseItems, keys);
|
||||
SFItemTransformer.decryptMultipleItems(responseItems, keys);
|
||||
var items = this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields, source);
|
||||
|
||||
// During the decryption process, items may be marked as "errorDecrypting". If so, we want to be sure
|
||||
@@ -450,7 +450,7 @@ class SyncManager {
|
||||
|
||||
var mapping = unsaved[i];
|
||||
var itemResponse = mapping.item;
|
||||
EncryptionHelper.decryptMultipleItems([itemResponse], this.authManager.keys());
|
||||
SFItemTransformer.decryptMultipleItems([itemResponse], this.authManager.keys());
|
||||
var item = this.modelManager.findItem(itemResponse.uuid);
|
||||
|
||||
if(!item) {
|
||||
|
||||
Reference in New Issue
Block a user