App.DataExportController = Ember.ArrayController.extend({ successors: App.Successor.find(), self: App.Self.find(0), assets: App.Asset.find(), download: function() { /* Encrypt the data: 1) the data/export template receives all objects and puts json objects of it into the invisible div 'rawjson'. this happened on first template execution. 2) when the 'download' action gets triggered, fetch that generated json out of the div. 3) fetch self.pass and create an SHA512 hash from it. 4) hash this hash 32times recursive (that is, create a hash of the previous hash and so on 32 times). 5) encrypt the json string using AES256 using the generated base64 encoded hash. 6) put the base64 encoded encrypted data into the div 'rawdata' 7) retrieve the data from 'rawdata'. note: it doesn't work to just continue to work with the already base64 encoded data (variable cr), it is empty. however, if we put it into the div and retrieve it right away then it's filled. that's reliable javascript programming, yay. 8) now calculate a SHA256 MAC authentication message of the base64 encoded encrypted data using the base64 encoded password hash (=> mac). 9) concatenate the mac and the encrypted data (mac first minus the last 2 chars '==') (=> signedcrypted). 10) insert a msdos newline every 64 chars so that we get a nice base64 encoded block. 11) add a header and footer to that block. 12) create a Blob object of that block. 13) put up a "save as..." dialog box to the user using this blob as content. */ var raw = $('#rawjson').text(); var pass = $('#rawp').text(); var hash = CryptoJS.SHA512(pass); for(var i=0; i<31; i++) { hash = CryptoJS.SHA512(hash); } // fix comma syntax raw = raw.replace(/,\],/g, '],'); // console.log("raw: %s", raw); var cr = CryptoJS.AES.encrypt(escape(raw), hash.toString(CryptoJS.enc.Base64)); $('#rawdata').text(cr); var crypted = $('#rawdata').text(); var mac = CryptoJS.HmacSHA512(crypted, hash.toString(CryptoJS.enc.Base64)); var signedcrypted = mac.toString(CryptoJS.enc.Base64).substring(0,86) + crypted; // console.log("cr: %s", crypted); // console.log("pass: <%s>, hash: <%s>", pass, hash.toString(CryptoJS.enc.Base64)); // console.log("mac: %s", mac.toString(CryptoJS.enc.Base64).substring(0,86)); var block = ''; var c = 1; for(var i=0; i, hash: <%s>, hash: %o", pass, hash.toString(CryptoJS.enc.Base64), hash); // console.log("json: %s", json); // make it an obj var importobj = JSON.parse(json); // console.log("imported json: %o", importobj); if(json) { // suck it in ImportJSON(importobj, pass); this.set('clear', translate('_importdone')); var isuccessors = []; $.each(importobj.successors, function(index, obj) { if(obj.id != '0') { isuccessors.pushObject(obj); } }); this.set('successors', isuccessors); this.set('assets', importobj.assets); this.set('self', importobj.self); } else { throw 'decrypted variable $json doesnt contain anything, weird'; } } catch (e) { // console.log("decryption exception: %o", e); this.set('clear', translate('_error_decrypt') + " (" + e + ")"); this.set('failed', true); } } else { // no password given this.set('isEditing', true); this.set('errors', validated); this.set('failed', true); this.set('clear', translate('_error_decrypt')); } }, repeatEditing: function() { this.set('isEditing', true); this.set('importdata', ''); this.set('password', ''); } }); function ImportJSON(json, pass) { // start with self var self = App.Self.find(0).then(function(self) { self.set('name', json.self.name); self.set('birth', json.self.birth); self.set('address', json.self.address); self.set('password', pass); }); // now the successors $.each(json.successors, function(index, obj){ if(obj.id !== "0") { var exists = App.Successor.all().some(function(successor) { return successor.get('id') === obj.id; }); if(exists) { // Update App.Successor.find(obj.id).then(function(successor) { //console.log("updating successor %o", obj); successor.set("name", obj.name); successor.set("address", obj.address); successor.set("birth", obj.birth); successor.set("name2", obj.name2); successor.set("address2", obj.address2); successor.set("birth2", obj.birth2); }); } else { var successor = App.Successor.createRecord(obj); } } }); // and the assets $.each(json.assets, function(index, obj){ var exists = App.Asset.all().some(function(asset) { return asset.get('id') === obj.id; }); if(exists) { /// Update App.Asset.find(obj.id).then(function(asset) { //console.log("updating asset %o", obj); asset.set("name", obj.name); asset.set("uri", obj.uri); asset.set("login", obj.login); asset.set("password", obj.password); asset.set("mail", obj.mail); asset.set("successor", App.Successor.find(obj.successor)); asset.set("order", App.Order.find(obj.order)); asset.set("notes", obj.notes); App.store.commit(); // we do update it here to avoid rootState.loaded.updated.uncommitted }); } else { // create var asset = App.Asset.createRecord({ id: obj.id, name: obj.name, uri: obj.uri, login: obj.login, password: obj.password, mail: obj.mail, successor: App.Successor.find(obj.successor), order: App.Order.find(obj.order), notes: obj.notes }); } }); App.store.commit(); }