I'm building a service for users where I must have private files.
Actually, with Cloud Code, I can control the download flux, through a function. But, how I can prevent a hacker to use the javascript console and upload his files ? He will get a link, which he can share with anyone without restriction and at my charges.
const file = Parse.File('hackerFile', hackerFileArray);
file.save().then(() => console.log(file.url)) // Now, he have a free file hosting.
Is there a way to completely remove this feature for everyone, except the master key ?
Example of hosting a file on http://todolist.parseapp.com/
Open the console in your browser then
var script = document.createElement('script');
script.src = '//www.parsecdn.com/js/parse-1.6.14.min.js'; // Because of their version.
document.head.appendChild(script);
Parse.initialize("0Oq3tTp9JMvd72LOrGN25PiEq9XgVHCxo57MQbpT", "vUFy2o7nFx3eeKVlZneYMPI2MBoxT5LhWNoIWPja"); // Found in their sources
var reader = new FileReader();
var input = document.createElement('input');
input.type = 'file';
document.body.appendChild(input);
// Then choose a file from the browser. I choosen a picture.
reader.onloadend = function() {
var file = new Parse.File('hackFile', {base64: reader.result});
file.save().then(function() {
console.log(file.url());
})
};
reader.readAsDataURL(input.files[0]);
Then you have a link. I got http://files.parsetfss.com/ae2ddbce-9cc0-4e1a-a16d-52ec5fdb7570/tfss-8fccfba0-ccf7-41cd-8f42-75f0a3478262-hackFile
Haven't tried this, but think it could work:
1) Add a beforeSave function on whatever class you're looking to prevent this behavior on.
2) In the beforeSave, check request.object.dirtyKeys() and iterate through each of those keys on the newly created object.
3) If the value associated with one of those dirtyKeys is a file, don't allow the file to save: response.error
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var dirtyKeys = request.object.dirtyKeys();
for (var i = 0; i < dirtyKeys.length; ++i) {
var dirtyKey = dirtyKeys[i];
if (isUnwantedFile(request.object, dirtyKey)) {
response.error("User is not allowed to store files");
return;
}
}
response.success();
});
//note this function is untested -- I'm not sure what type a user-created file would be,
//but basically if you can figure that out, substitute it in here
function isUnwantedFile(obj, key){
return typeof obj[dirtyKey] === Parse.File
}
Related
I've been trying to save a user-uploaded image to parse for the longest time, and nothing seems to work -- even when following their documentation.
Below is the handler I use for the onChange() on a multiple file upload. At first I was concerned about multiple file uploads, but at this point just saving one image doesn't work.
function fileHandler(event) {
var files = event.target.files;
stopPictures = [];
$("#stop-img-container").empty();
if (files[0] != null) {
$("#stop-img-container").show();
for (var i = 0; i < files.length; i++) {
var file = files[i];
var picReader = new FileReader();
picReader.addEventListener("load",function(event){
var picFile = event.target;
var image = $("<img/>",{
"title": picFile.name,
"class": "stop-image",
"src": picFile.result
}).appendTo("#stop-img-container");
var name = picFile.name;
var dataFile = picFile.result;
var base64str = dataFile.substring(dataFile.indexOf("base64,")+7,dataFile.length);
var parseFile = new Parse.File(name,{base64:base64str}); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,dataFile); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
var parseFile = new Parse.File(name,file); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,base64str); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
parseFile.save().then(function (savedFile) {
stopPictures.push(savedFile);
alert("worked");
});
});
picReader.readAsDataURL(file);
}
} else {
$("#stop-img-container").hide();
}
}
There's some extraneous stuff here, but basically it collects the user's selected files, displays them for them once they've finished loading, and then creates them as a Parse file. I've left it in to show that at least something is working as it properly locally stores and previews the user's selected files.
I have included three different ways of creating the same Parse file. However, all of them fail when I try to save to Parse in any way.
Parse's Javascript API docs says that any of these should work fine. But they lie, or I'm an idiot.
Anyone have any idea why this doesn't seem to work? Seems like a pretty critical aspect of their API is broken completely -- which I find hard to imagine.
EDIT: I'm also positive I'm properly parsing (lower case p) the base64 string as this site confirms the appropriate image and works.
I experienced the same problem.
Finally I found what causes the problem.
It's a "file name".
I suspect the file name in tuckerchapin's example is null.
var name = picFile.name;
I wrote the example with React.
this code works fine.
class ImageUpload extends React.Component {
onChange(e) {
var file = e.target.files[0];
var parseFile = new Parse.File(file.name, file);
Parse.User.current().set("icon",parseFile);
Parse.User.current().save();
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="file" onChange={this.onChange.bind(this)} />
</form>
);
}
}
I'm using openxml in my HTML5 mobile app to generate word documents on the mobile device.
In general openxml works fine and straight forward, but I'm struggling with an annyoing problem.
The document generation only works the first time after I've started the app. This time I can open and view the document. Restart the app means:
- Redeploy from development machine
- Removing the app from the task pane (pushing aside; I assume the app is removed then?)
The second time I get the message the document is corrupted and I'm unable to view the file
UPDATE:
I can't reproduce this behaviour when I'm running the app connected to the remote debugger without having a breakpoint set. Doing it this way I always get a working document.
I doesn't make a difference wether I do any changes on the document or not. Simply open and saving reproduce this error.
After doing some research I've found that structure of the docx.zip file of the working and the corrupt file is the same. They also have the same file length. But in the corrupt docx there are some files I've found some files having a wrong/invalid CRC. See here an example when trying to get a corrupt file out of the zip. Other files are working as expected.
The properties for this file are->
(CRC in a working version is: 44D3906C)
Code for processing the doc-template:
/*
* Process the template
*/
function processTemplate(doc64, callback)
{
"use strict";
console.log("PROCESS TEMPLATE");
var XAttribute = Ltxml.XAttribute;
var XCData = Ltxml.XCData;
var XComment = Ltxml.XComment;
var XContainer = Ltxml.XContainer;
var XDeclaration = Ltxml.XDeclaration;
var XDocument = Ltxml.XDocument;
var XElement = Ltxml.XElement;
var XName = Ltxml.XName;
var XNamespace = Ltxml.XNamespace;
var XNode = Ltxml.XNode;
var XObject = Ltxml.XObject;
var XProcessingInstruction = Ltxml.XProcessingInstruction;
var XText = Ltxml.XText;
var XEntity = Ltxml.XEntity;
var cast = Ltxml.cast;
var castInt = Ltxml.castInt;
var W = openXml.W;
var NN = openXml.NoNamespace;
var wNs = openXml.wNs;
var doc = new openXml.OpenXmlPackage(doc64);
// add a paragraph to the beginning of the document.
var body = doc.mainDocumentPart().getXDocument().root.element(W.body);
var tpl_row = ((doc.mainDocumentPart().getXDocument().descendants(W.tbl)).elementAt(1).descendants(W.tr)).elementAt(2);
var newrow = new XElement(tpl_row);
doc.mainDocumentPart().getXDocument().descendants(W.tbl).elementAt(1).add(newrow);
// callback(doc);
var mod_file = null;
var newfile;
var path;
if (doc != null && doc != undefined ) {
mod_file = doc.saveToBlob();
// Start writing document
path = "Templates";
newfile = "Templates/Bau.docx";
console.log("WRITE TEMPLATE DOCUMENT");
fs.root.getFile("Templates/" + "MyGenerated.docx", {create: true, exclusive: false},
function(fileEntry)
{
fileEntry.createWriter(
function(fileWriter)
{
fileWriter.onwriteend = function(e) {
console.log("TEMPLATE DOCUMENT WRITTEN:"+e.target.length);
};
fileWriter.onerror = function(e) {
console.log("ERROR writing DOCUMENT:" + e.code + ";" + e.message);
};
var blobreader = new FileReader();
blobreader.onloadend = function()
{
fileWriter.write(blobreader.result); // reader.result contains the contents of blob as a typed array
};
blobreader.readAsArrayBuffer(mod_file);
},
null);
}, null);
};
Any ideas what I'm doing wrong?
Thanks for posting about the error. There were some issues with jszip.js that I encountered when I was developing the Open XML SDK for JavaScript.
At the following link, there is a sample javascript app that demonstrates generating a document.
Open XML SDK for JavaScript Demo
In that app you can save multiple DOCXs, one after another, and they are not corrupted.
In order to work on this issue, I need to be able to re-produce locally. Maybe you can take that little working web app and replace parts with your parts until it is generating invalid files?
Cheers, Eric
P.S. I am traveling and have intermittent access to internet. If you can continue the thread on OpenXmlDeveloper.org, then it will help me to answer quicker. :-)
What made it work for me, was changing the way of adding images (Parts) to the document. I was using the type "binary" for adding images to document. I changed this to "base64"
So I changed the source from:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "binary", fotodata ); // add Image Part to doc
to:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "base64", window.btoa(fotodata) ); // add Image Part to doc
I have some input boxes in a HTML form that need to be updated when the form loads and these values need to be uploaded from a text file.
A similar question was also asked here:
Uploading Text File to Input in Html/JS
I have searched for this on the internet, but couldn't find any correct answer.
So I want to know whether it is possible or not?
If you wish to go the client side route, you'll be interested in the HTML5 FileReader API. Unfortunately, there is not wide browser support for this, so you may want to consider who will be using the functionality. Works in latest Chrome and Firefox, I think.
Here's a practical example: http://www.html5rocks.com/en/tutorials/file/dndfiles/#toc-reading-files
And I also read here to find the readAsText method: http://www.w3.org/TR/file-upload/#dfn-readAsText
I would do something like this (jQuery for brevity): http://jsfiddle.net/AjaDT/2/
Javascript
var fileInput = $('#files');
var uploadButton = $('#upload');
uploadButton.on('click', function() {
if (!window.FileReader) {
alert('Your browser is not supported');
return false;
}
var input = fileInput.get(0);
// Create a reader object
var reader = new FileReader();
if (input.files.length) {
var textFile = input.files[0];
// Read the file
reader.readAsText(textFile);
// When it's loaded, process it
$(reader).on('load', processFile);
} else {
alert('Please upload a file before continuing')
}
});
function processFile(e) {
var file = e.target.result,
results;
if (file && file.length) {
results = file.split("\n");
$('#name').val(results[0]);
$('#age').val(results[1]);
}
}
Text file
Jon
25
The other answer is great, but a bit outdated and it requires HTML & jQuery to run.
Here is how I do it, works in all modern browsers down to IE11.
/**
* Creates a file upload dialog and returns text in promise
* #returns {Promise<any>}
*/
function uploadText() {
return new Promise((resolve) => {
// create file input
const uploader = document.createElement('input')
uploader.type = 'file'
uploader.style.display = 'none'
// listen for files
uploader.addEventListener('change', () => {
const files = uploader.files
if (files.length) {
const reader = new FileReader()
reader.addEventListener('load', () => {
uploader.parentNode.removeChild(uploader)
resolve(reader.result)
})
reader.readAsText(files[0])
}
})
// trigger input
document.body.appendChild(uploader)
uploader.click()
})
}
// usage example
uploadText().then(text => {
console.log(text)
})
// async usage example
const text = await uploadText()
I have a local program which writes a JSON object to a file so that a JavaScript can pick up its data and process it. The file is selected using an <input> object:
<form id = "getfiles">
<input type = "file" multiple id = "files" />
</form>
with the following JS function setInterval to repeat every 300ms. However, when the file changes, only Google Chrome reloads the file and processes the new content; I have to manually reselect the file on the page in IE 10 and Firefox 20.
function speakText()
{
var thefile = document.getElementById('files').files[0];
var lastChanged = thefile.lastModifiedDate;
var reader = new FileReader();
reader.onload = function(event)
{
var lcd = document.getElementById("last_change_date");
if (!lcd)
{
var spanLastChanged = document.createElement("span");
spanLastChanged.id = "last_change_date";
spanLastChanged.innerText = lastChanged;
console.log(lastChanged);
document.body.appendChild(spanLastChanged);
}
else
{
// compare lastChanged with last_change_date
var last_known_change = Date.parse(lcd.innerText);
// var last_known_change = Date.parse(thefile.lastModifiedDate);
if (last_known_change !== Date.parse(lastChanged))
{
console.log("Something is new since " + lcd.innerText);
var fileContent = event.target.result;
var commands = JSON.parse(fileContent);
handleJSON(fileContent);
lcd.innerText = lastChanged;
}
}
}
reader.readAsText(thefile, "UTF-8");
}
Firefox and IE are doing the right thing per spec: the File objects associated with a file input are supposed to be immutable snapshots of a file at the point when the File object was created. It's a known bug in WebKit/Blink that they just store a reference to the file's data, so that mutating the data will change what the File object sees.
In fact, the WebKit/Blink behavior is a privacy bug: when a user selects a file in a file input, they are giving a web page permission to read the data of the file at that time, not for all future versions of the file! Which is why the spec is written as it is.
I have a C++ function which once called consumes input from stdin. Exporting this function to javascript using emscripten causes calls to window.prompt.
Interacting with browser prompt is really tedious task. First of all you can paste only one line at time. Secondly the only way to indicate EOF is by pressing 'cancel'. Last but not least the only way (in case of my function) to make it stop asking user for input by window.prompt is by checking the checkbox preventing more prompts to pop up.
For me the best input method would be reading some blob. I know I can hack library.js but I see some problems:
Reading blob is asynchronous.
To read a blob, first you have to open a file user has to select first.
I don't really know how to prevent my function from reading this blob forever - there is no checkbox like with window.prompt and I'm not sure if spotting EOF will stop it if it didn't in window.prompt case (only checking a checkbox helped).
The best solution would be some kind of callback but I would like to see sime hints from more experienced users.
A way would be to use the Emscripten Filesystem API, for example by calling FS.init in the Module preRun function, passing a custom function as the standard input.
var Module = {
preRun: function() {
function stdin() {
// Return ASCII code of character, or null if no input
}
var stdout = null; // Keep as default
var stderr = null; // Keep as default
FS.init(stdin, stdout, stderr);
}
};
The function is quite low-level: is must deal with one character at a time. To read some data from a blob, you could do something like:
var data = new Int8Array([1,2,3,4,5]);
var blob = new Blob([array], {type: 'application/octet-binary'});
var reader = new FileReader();
var result;
reader.addEventListener("loadend", function() {
result = new Int8Array(reader.result);
});
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (if < result.byteLength {
var code = result[i];
++i;
return code;
} else {
return null;
}
}
var stdout = null; // Keep as default
var stderr = null; // Keep as default
FS.init(stdin, stdout, stderr);
}
};
Note (as you have hinted), due to the asynchronous nature of the reader, there could be a race condition: the reader must have loaded before you can expect the data at the standard input. You might need to implement some mechanism to avoid this in a real case. Depending on your exact requirements, you could make it so the Emscripten program doesn't actually call main() until you have the data:
var fileRead = false;
var initialised = false;
var result;
var array = new Int8Array([1,2,3,4,5]);
var blob = new Blob([array], {type: 'application/octet-binary'});
var reader = new FileReader();
reader.addEventListener("loadend", function() {
result = new Int8Array(reader.result);
fileRead = true;
runIfCan();
});
reader.readAsArrayBuffer(blob);
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (i < result.byteLength)
{
var code = result[i];
++i;
return code;
} else{
return null;
}
}
var stdout = null;
var stderr = null;
FS.init(stdin, stdout, stderr);
initialised = true;
runIfCan();
},
noInitialRun: true
};
function runIfCan() {
if (fileRead && initialised) {
// Module.run() doesn't seem to work here
Module.callMain();
}
}
Note: this is a version of my answer at Providing stdin to an emscripten HTML program? , but with focus on the standard input, and adding parts about passing data from a Blob.
From what I understand you could try the following:
Implement selecting a file in Javascript and access it via Javascript Blob interface.
Allocate some memory in Emscripten
var buf = Module._malloc( blob.size );
Write the content of your Blob into the returned memory location from Javascript.
Module.HEAPU8.set( new Uint8Array(blob), buf );
Pass that memory location to a second Emscripten compiled function, which then processes the file content and
Deallocate allocated memory.
Module._free( buf );
Best to read the wiki first.