Salesforce, Locker: Cannot "createObjectURL" using a unsecure [object File] - javascript
I'm having some problem with a lightning component that was done by other developer that left the company, users are telling me that the tool was working perfectly 1 month ago but i don't have any idea of what is happening then
The error is :
This page has an error. You might just need to refresh it. Action
failed: c:EMB_CCW_Panel$controller$onPickFile [Locker: Cannot
"createObjectURL" using a unsecure [object File]!] Failing descriptor:
{c:EMB_CCW_Panel$controller$onPickFile}
and the javascript method is this one
onPickFile : function(component, event, helper) {
var catalog = component.get("v.catalogWrapper");
var brandsList = component.get("v.brandsList");
console.log("onPickFile", catalog);
var file = event.target.files[0];
var fileURL = URL.createObjectURL(file);
var req = new XMLHttpRequest();
req.open('GET', fileURL);
req.onload = function() {
URL.revokeObjectURL(fileURL);
component.set("v.catalogWrapper",
helper.fillCatalogWithXMLData(catalog, helper.extractSlideNotesFromODTContentXML(this.responseXML), brandsList));
};
req.onerror = function() {
URL.revokeObjectURL(fileURL);
console.log('Error loading XML file.');
};
req.send();
},
and the helper methods,
extractSlideNotesFromODTContentXML : function(xmlDoc){
var output = [];
var slides = xmlDoc.getElementsByTagName("draw:page");
for(var s=0;s<slides.length;s++){
var notes = slides[s].getElementsByTagName("presentation:notes")[0].getElementsByTagName("draw:frame")[0].getElementsByTagName("draw:text-box")[0].getElementsByTagName("text:p");
var slideNotesList = [];
for(var i =0;i<notes.length;i++){
slideNotesList.push(notes[i].textContent);
}
output.push(slideNotesList);
}
return output;
},
fillCatalogWithXMLData : function(catalog, slidesList, brandsList){
try {
var referenceRegEX = /^(\d){9}/;
for(var i=0;i<slidesList.length;i++){
catalog.slides.splice(i, 0, this.generateSlideObject(i+1));
for(var j=0;j<slidesList[i].length;j++){
var wholeLine = slidesList[i][j];
var firstWord = wholeLine.split(" ")[0].toUpperCase();
console.log('firstWord', firstWord)
// Lines that begin with a number are references (SAP Id code). Consider the rest brand names:
if(referenceRegEX.test(firstWord) && firstWord.length == 9){
catalog.slides[i].referencesText += wholeLine+"\n";
}else{
// That's not a reference, check if it's a brand:
// 1.- Check if the whole line is a brand (removing leading and trailing spaces)
if(brandsList.includes(wholeLine.trim())){
// Found brand:
catalog.slides[i].brandsText += wholeLine + "\n";
}else{
// Not found, not recognized:
catalog.slides[i].unrecognizedText += wholeLine + "\n";
}
}
}
}
component.set("v.catalogWrapper", catalog);
} catch(err) {
}
return catalog;
}
anyone can't help me or tell me how can i fixe it !
thanks
If it used to work 1 month ago it's probably something Salesforce patched in Summer release. No idea what (if anything) is unsecure in your code but sounds like you're hit by Lightning Locker Service. Do you get same result in different browsers?
See if it works if you knock back the API version of component to version 39. It's a hack but might be a temp relief while you figure out what to do.
This suggests File is supported all right: https://developer.salesforce.com/docs/component-library/tools/locker-service-viewer
Maybe you need to read the file's content different way, maybe you need to give up on parsing it with JavaScript and push to server-side apex? I don't know what your functionality is.
If you go to setup -> lightning components -> debug mode and enable for yourself it might help a bit. You will see more human-friendly code generated in browser's developer tools, debugging might be simpler. Lesson learned would be to pay more attention to release preview windows (from ~September 12th we can preview Winter'21 release, SF should publish blog post about it in 1-2 weeks)
This looks promising: https://salesforce.stackexchange.com/a/245232/799
Maybe your code needs proper Aura accessors, event.getSource().get("v.files")[0] instead of event.target.files[0]. You really would have to debug it and experiment in browser's console, see what sticks.
Related
Facing issue to open Macro document in Modern Browser(FF, chrome) and Export As Fixed Format, Some could help here
Facing issue to open Macro document in Modern Browser(FF, chrome) and Export As Fixed Format.The below code user open macro document and set value as per the condition, next export it as fixed format. function launch_alwaysprint (loc) var i; { var w= new ActiveXObject("Word.Application"); w.Visible = true; w.WindowState = 2; //Minimize w.WindowState = 1; //Maximize var obj= w.documents.open(loc); for (i=1; i<=obj.FormFields.count; i++) { if (obj.FormFields(i).name == "AccountOwner") { if (document.forms[0].AccountOwnerOverride.value != "") { obj.FormFields(obj.FormFields(i).name).Range.Fields(1).result.text = document.forms[0].AccountOwnerOverride.value; } else { obj.FormFields(obj.FormFields(i).name).Range.Fields(1).result.text = document.forms[0][obj.FormFields(i).name].value; } } } //End For obj.RunAutoMacro(2); //obj.Protect(1,true,"Xz123Asdf34"); var shell = new ActiveXObject("WScript.Shell"); var pathToMyDocuments = shell.SpecialFolders('MyDocuments')+"\\test1.pdf"; alert("Contract will be opened as a PDF but it will not be automatically saved"); obj.ExportAsFixedFormat(pathToMyDocuments,"17","true"); obj.Close(0) w.Quit(0) } // End Main fnc
You can't do this in a web browser. Launching and interacting with applications on the user's computer is a security risk, and web pages are no longer allowed to do it. (This code would only have ever worked on Internet Explorer, and even then, only on certain older versions with nonstandard security zone settings.) You will need to find another way of doing this -- probably by processing the document and generating a PDF on the server.
Google Script not Appending Spreadsheet
I'm trying to write a little script to make my coworkers and mine lives easier. I am trying to append lines to a spreadsheet based on information entered into a custom form. The code posted below just the doPost block which should be appending the google spreadsheet. function doPost(form) { var PN = form.PartNumber; var REV = form.Revision; var DATE = form.RevisionDate; var DESC = form.Description; var NOTE = form.PartNotes; var URL = form.myFile.getURL(); var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid) var sheet = ss.getSheetName('Uploads'); sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]); } I am unsure why it isn't writing to the spreadsheet but it isn't throwing me any errors. If you can offer any insight as to what is wrong I would greatly appreciate it; there are many guides online but most seem to be based on deprecated functions/code/etc. Thanks for your time.
Instead of using doPost, set up a "On form submit" trigger. You need to get the namedValues to be able to pull specific values and take the first output. Also, it should be "getSheetByName('Uploads')" . As pointed out in the previous answer, it is unclear what you are trying to achieve by "form.myFile.getURL();" If you want to get the form url you might as well create it as a string, as it always stays the same. Here is a working example of your code: function doPost(form) { var formResponses = form.namedValues; var PN = formResponses.PartNumber[0]; var REV = formResponses.Revision[0]; var DATE = formResponses.RevisionDate[0]; var DESC = formResponses.Description[0]; var NOTE = formResponses.PartNotes[0]; //var URL = form.myFile.getURL(); //Not sure what you are tyring to get here as form URL will always be the same. var URL = "Your form's url"; //You can put the form url in here so it will be pushed in to every row. var ss = SpreadsheetApp.openById("ID HERE"); // removed ID for sake of safety (let me be paranoid) var sheet = ss.getSheetByName('Uploads'); sheet.appendRow([PN,REV,DATE,DESC,NOTE,URL]); }
The form fields are nested in a "parameter" property in the doPost parameter. So, you should access them using: function doPost(form) { var actualForm = form.parameter; var PN = actualForm.PartNumber; //etc To double check all parameters your receiving and their names, you could append to your sheet everything stringfied, like this: sheet.appendRow([JSON.stringify(form)]); --edit This form.myFile.getURL() also looks odd. I guess another good debugging trick you could do is to wrap everything in a try-catch and email yourself any errors you get. For example: function doPost(form) { try { //all your code } catch(err) { MailApp.sendMail('yourself#etc', 'doPost error', err+'\n\n'+JSON.stringify(form)); } }
On form submit onFormSubmit works. "doPost" looks wrong. Simple example: function Initialize() { var triggers = ScriptApp.getProjectTriggers(); for(var i in triggers) { ScriptApp.deleteTrigger(triggers[i]); } ScriptApp.newTrigger("SendGoogleForm") .forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet()) .onFormSubmit() .create(); } function SendGoogleForm(e) { try { Full example - Scroll down to the code http://www.labnol.org/internet/google-docs-email-form/20884/ (Note: example sends email) Trigger docs: https://developers.google.com/apps-script/guides/triggers/events Notes: I think the problem is doPost, Does it work with google Forms? Never seen it used with google forms.
First and foremost, thank you everyone who has responded with information thus far. None of the solutions posted here worked for my particular implementation (my implementation is probably to blame, it is very crude), but they definitely set me down the path to a working version of my form which we now lightly use. I have posted some of the code below: function sheetFill(form, link) { try { var formResponses = form.namedValues; var toForm = [0,0,0,0,0,0,0]; for (i=0;i < form.PartNumber.length;i++){ toForm[0] = toForm[0]+form.PartNumber[i]; } ... (several for loops later) var d = new Date(); var ss = SpreadsheetApp.openById("IDHERE"); var sheet = ss.getCurrentSheet; ss.appendRow([toForm[0], toForm[1], toForm[2], toForm[3], toForm[4], toForm[5], toForm[6], link, d]); } catch(err) { MailApp.sendEmail('EMAIL', 'doPost error', err+'\n\n'+JSON.stringify(form)); } } It is not very versatile or robust and isn't elegant, but it is a starting point.
converting array buffers to string
I'm getting some weird results when converting an array buffer to a string then displaying the output in a div. I'm getting some GPS data from the USB port in a chrome packaged app. It converts the array buffer received from the port into a string and outputs. The functions are: var onReceiveCallback = function(info) { if (info.connectionId == connectionId && info.data) { $(".output").append(ab2str(info.data)); } }; /* Interprets an ArrayBuffer as UTF-8 encoded string data. */ var ab2str = function(buf) { var bufView = new Uint8Array(buf); var encodedString = String.fromCharCode.apply(null, bufView); return decodeURIComponent(escape(encodedString)); }; I have a start and stop button to obviously start and stop the reading of data from the gps device. When I start it the first time it works and outputs as expected, something like: $GPGGA,214948.209,,,,,0,0,,,M,,M,,*41 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,1,1,01,07,,,33*7F $GPRMC,214948.209,V,,,,,0.00,0.00,270814,,,N*4C $GPGGA,214949.209,,,,,0,0,,,M,,M,,*40 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,1,1,01,07,,,34*78 $GPRMC,214949.209,V,,,,,0.00,0.00,270814,,,N*4D but then when I stop it, and restart it, although I clear the output div, the output data seems to be mixing in with the previous result. Like: $$GPGPGGGGAA,,221155115544..202099,,,,,,,,,0,0,0,0,,,,,,MM,,,,MM,,,,**4455 $$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE $$GGPGPGSSVV,,11,,11,,0022,,0077,,,,,,3344,1,177,,,,,,3311**77FF $$GGPPRRMMCC,,212155115544..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,NN*4*488 $$GPGGPGGGAA,,221155115555..220099,,,,,,,,,,00,,00,,,,,,MM,,,,MM,,,,**4444 $$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE $G$GPPGGSSVV,,11,,11,,0022,,0077,,,,,,331,1,1177,,,,,,2255**77FF $$GGPPRRMMCC,2,21155115555..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,N*N*4499 Its like a buffer or variable isnt being emptied, or something else crazy that I cant figure out. Any pointers appreciated. edit: this is the 'start' function which clears the output div and reconnects: // when the start button is clicked $( "#start" ).click(function() { if ( deviceId == 0 ) { console.log("Please select a device"); return; } else { $(".output").empty(); serial.connect(deviceId, {bitrate: 9600}, onConnect); } });
I have found this technique unreliable in my own code, although I don't remember if the problem was similar to one you report: var ab2str = function(buf) { // not reliable var bufView = new Uint8Array(buf); var encodedString = String.fromCharCode.apply(null, bufView); return decodeURIComponent(escape(encodedString)); }; So, I have done it this way, with code taken from one of the Google Chrome App examples (tcpserver): function ab2str(buf, callback) { var bb = new Blob([new Uint8Array(buf)]); var f = new FileReader(); f.onload = function(e) { callback(e.target.result); }; f.readAsText(bb); } Note that this version isn't an exact replacement, since it's asynchronous. Now, starting with Chrome Version 38 (now in beta), you can do it this way: function ab2str(buf) { var dataView = new DataView(buf); var decoder = new TextDecoder('utf-8'); return decoder.decode(dataView); } As I always run the beta and am preparing examples for a forthcoming book, I am now doing it the newest way. Give that a try and see if your problem goes away. If not, my suggestion to examine info.data is still a good one, I think. UPDATE: I've just checked out this reverse function, which you may also find handy at some point: function str2ab(buf) { var encoder = new TextEncoder('utf-8'); return encoder.encode(buf).buffer; }
firefox addon install.rdf pass data to server on update
Is there any chance to pass some data to my server through install.rdf when my Firefox add-on check server for update? Example: ... <em:updateURL>http://www.site.com/update.php?var=myData</em:updateURL> ... where "myData" is saved in options.xul or in another place like simple-storage.
Yes, but it is quite nasty. The AddonManager will replace a bunch of predefined and dynamic properties in the URL: Register a new component implementing nsIPropertyBag2 (or use an existing implementation, such as ["#mozilla.org/hash-property-bag;1"]). Register your component in the nsICategoryManager under the "extension-update-params" category. Since you mentioned simple-storage: restartless add-ons must also unregister their stuff when being unloaded. There is a unit test demonstrating how this stuff works. You of course need to adapt it a bit (if alone for require("chrome").
I found one "simple solution" but I dont know if that is also good practice ... var origLink = "http://www.site.net/update.php?var=myData"; var newsLink = "http://www.site.net/update.php?var=" + simplePref.prefs.myData; const {Cc,Ci,Cu} = require("chrome"); var observer = { QueryInterface: function(iid) { if (iid.equals(Ci.nsIObserver) || iid.equals(Ci.nsISupports)) return this; }, observe: function(subject, topic, data){ if (topic == "http-on-modify-request"){ var channel = subject.QueryInterface(Ci.nsIChannel); if (channel.originalURI.spec == origLink) { channel.originalURI.spec = newsLink; } } } }; var ObsService = Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); ObsService.addObserver(observer, "http-on-modify-request", false);
Setting a preference at startup in firefox
Thanks to everyone in advance - I need to load a preference before any windows are loaded at startup. Below is some /component code I have been working with. The SetPreference method seems to fail when it is called (nothing executes afterwords either) - I am assuming because the resources that it needs are not available at the time of execution...or I am doing something wrong. Any suggestions with this code or another approach to setting a preference at startup? Thanks again, Sam For some reason the code formatting for SO is not working properly - here is a link to the code as well - http://samingrassia.com/_FILES/startup.js Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); const Cc = Components.classes; const Ci = Components.interfaces; const ObserverService = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService); function MyStartupService() {}; MyStartupService.prototype = { observe : function(aSubject, aTopic, aData) { switch (aTopic) { case 'xpcom-startup': this.SetPreference("my.extension.is_running", "false"); break; case 'app-startup': this.SetPreference("my.extension.is_running", "false"); ObserverService.addObserver(this, 'final-ui-startup', false); break; case 'final-ui-startup': //make sure is_running is set to false this.SetPreference("my.extension.is_running", "false"); ObserverService.removeObserver(this, 'final-ui-startup'); const WindowWatcher = Cc['#mozilla.org/embedcomp/window-watcher;1'].getService(Ci.nsIWindowWatcher); WindowWatcher.registerNotification(this); break; case 'domwindowopened': this.initWindow(aSubject); break; } }, SetPreference : function(Token, Value) { var prefs = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService); var str = Components.classes["#mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); str.data = Value; prefs.setComplexValue(Token, Components.interfaces.nsISupportsString, str); //save preferences var prefService = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService); prefService.savePrefFile(null); }, initWindow : function(aWindow) { if (aWindow != '[object ChromeWindow]') return; aWindow.addEventListener('load', function() { aWindow.removeEventListener('load', arguments.callee, false); aWindow.document.title = 'domwindowopened!'; // for browser windows var root = aWindow.document.documentElement; root.setAttribute('title', aWindow.document.title); root.setAttribute('titlemodifier', aWindow.document.title); }, false); }, classDescription : 'My Startup Service', contractID : '#mystartupservice.com/startup;1', classID : Components.ID('{770825e7-b39c-4654-94bc-008e5d6d57b7}'), QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver]), _xpcom_categories : [{ category : 'app-startup', service : true }] }; function NSGetModule(aCompMgr, aFileSpec) { return XPCOMUtils.generateModule([MyStartupService]); }
To answer your real question, which is I have code that loads on every window load and I need to make sure that only gets executed once every time firefox starts up. ..you should just use a module, in the load handler that you wish to execute once, check a flag on the object exported from (i.e. "living in") the module, then after running the code you need, set the flag. Since the module is shared across all windows, the flag will remain set until you close Firefox. As for your intermediate problem, I'd suggest wrapping the code inside observe() in a try { ... } catch(e) {dump(e)} (you'll need to set a pref and run Firefox in a special way in order to see the output) and check the error returned. I guess xpcom-startup and app-startup is too early to mess with preferences (I think you need a profile for that), note that you don't register to get xpcom-startup notification anyway. You probably want to register for profile-after-change instead.