How to check if csv files contains a formula? - javascript

After browsing a file I have to check if a csv file contains a formula or not in typescript or javascript.
Please help with an npm module or a function, as I need to protect a file from CSV Injection before uploading a file. The below code is what I have tried so far, it is just giving me the string-like #VALUE!, #NAME!, etc. instead I want =B1+C1
var files = e.target.files;
var file = files[0];
if(file) {
var reader = new FileReader();
reader.readAsText(file);
reader.onload = (event: any) => {
var csv = event.target.result;
var string = <string>csv ;
if(string.replace(/\s+/, "").includes(',-') == true) {
this.service.openSnackBar('PLEASE UPLOAD A VALID FILE','');
} else if (string.includes("+") == true || string.includes("=") == true) {
this.service.openSnackBar('PLEASE UPLOAD A VALID FILE','');
e.target.value = '';
} else {
// if valid upload to server
}
}
}

I was surprised to hear that CSVs could have embedded functions - I always thought that CSVs were simply text files, and relatively "safe" from vulnerabilities.
This is from OWASP (the Open Web Application Security Project):
https://owasp.org/www-community/attacks/CSV_Injection
This attack is difficult to mitigate, and explicitly disallowed from
quite a few bug bounty programs. To remediate it, ensure that no cells
begin with any of the following characters:
Equals to (“=”)
Plus (“+”)
Minus (“-“)
At (“#”)
So that's probably a good place to start:
Read your .csv a line at a time and parse into columns (e.g. string.split(','))
Ensure no column begins with any of the four characters above: =, +, - or #
Also read this post: Is there a way to programmatically insert formulas into a csv file using vb.net?

Related

Verifying drag & dropped file extension using JavaScript

I created a page that would accept drag & drop method of file upload, however, I couldn't get it to verify whether file extension is correct, and as of right now it simply rejects every file fed to it as "not of the right file extension". Can anyone explain to me why that is and what fixes can be done in order to fix my problem?
I'm using Apache to run my website
Here's my script of what I have tried:
const dropArea = document.getElementById("dropArea");
dropArea.addEventListener("dragover", (event)=>{
event.preventDefault();
dropArea.classList.add("active");
});
dropArea.addEventListener("dragleave", ()=>{
dropArea.classList.remove("active");
});
dropArea.addEventListener("drop", (event)=>{
event.preventDefault();
file = event.dataTransfer.files[0];
showFile(); //calling function
});
function showFile(){
const pheil = document.getElementById('TotalFail');
var filePath = file.type;
let validExtensions = ["application/x-java-keystore", "application/pkcs12"]; //adding some valid extensions in array
if(!validExtensions.includes(filePath)){
dropArea.classList.remove("active");
dropArea.classList.add("upload-fail")
var errorMessage = document.createElement("p")
errorMessage.className = "ErrorMsg"
errorMessage.id = "TotalFail"
if(pheil === null){
var errorTxt = document.createTextNode("Maximum file size exceeded or file extension is incorrect")
errorMessage.appendChild(errorTxt)
var errorDiv = document.getElementById("error-message")
errorDiv.appendChild(errorMessage)
} else {
return;
}
file.value = null;
}else{
alert("things are supposed to happen here")
}
}
What current code does:
Rejecting every file extension fed to it, even the one that's supposed to be the correct file extension
What I expect my code to do:
Correctly validate .jks and .pfx files without fault
P.S.:
I could provide a full html page with all the code if needed. Just in case that this doesn't actually look sensible at all.
Could also be that my complication is that I want my javascript to check for .jks and .pfx file extensions (e-key files) which aren't really super common.
What I have tried:
Rewriting code with different ways of verifying file extensions, none of which worked out for me.
Adding .jks and .pfx file extensions to mime.types and .htaccess
Trying other people's codes.

Normalize file path in JavaScript front-end

The short story:
Is there simple way to normalize file path in JavaScript, like in Java we have Paths.get("/a/b/../c").normalize() so /a/../../c would become /c. I seen many same questions here, but they are Node.js solutions, and I need pure JS or JQuery approach so it can be used in browser.
The long story:
I have a file server with web UI, that allows to browse files and download them. UI is written in spring and accessible at mysite.com/ui/
The file storage located at mysite.com/files/ which is plain Apache directory, so its possible to get direct link to file.
The real storage directory on server is /var/www/files
Path passing to back-end as mysite.com/ui/?path=/a/../../c, so back-end will normalize path variable separately to /c and then append it to base dir and so retrieving content of /home/storage/c, so it works perfectly.
The problem comes when user tries to download file like this with direct link. I.e. if user tries to download /a/../../c/d file from file server root, it appending to base storage url, which mysite.com/files/, and it becomes mysite.com/files/a/../../c/d so it will point to /var/www/d instead of /var/www/files/d so file can't be downloaded even if it is visible from web UI.
So I need to normalize relative file path first on front-end like on back-end when retrieving content of directory but I don't know how it can be done in JS. Is there function for it, or I have to write my own one?
So I ended up writing my own function on JS. It might be not what "path normalization" stands for, but anyway its exactly what I need
function normalizePath(path) {
// remove multiple slashes
path = path.replace(/\/+/g, '/');
// remove leading slash, will be added further
if (path.startsWith("/"))
path = path.substring(1)
// remove trailing slash
if (path.endsWith("/"))
path = path.slice(0, -1);
let segments = path.split("/");
let normalizedPath = "/";
for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
if (segments[segmentIndex] === "." || segments[segmentIndex] === "") {
// skip single dots and empty segments
continue;
}
if (segments[segmentIndex] === "..") {
// go up one level if possible
normalizedPath = normalizedPath.substring(0, normalizedPath.lastIndexOf("/") + 1);
continue;
}
// append path segment
if (!normalizedPath.endsWith("/"))
normalizedPath = normalizedPath + "/"
normalizedPath = normalizedPath + segments[segmentIndex];
}
return normalizedPath;
}
Still, I won't mark this as accepted answer as it's more of a quick fix, and I'm not JS expert so it definitely must be more elegant solution.

Check file content compared to file type

I would like to check a file (or several) whether they really are the files that have been specified with the extension . E.g. .pdf does not contain .exe content.
I don't want a PDF file to contain executable code and only use the pdf extension.
In x++ I validated for certain file types with reg ex e.g. pdf
Is there a library?
Use Case:
I built an extensible control in MS D365 for finance and operations. This is a file drop zone. I have to check these files. I can either do this in my external resources (Json) or in X++ itself. Would prefer X++. I am a beginner in both languages.
I have the files in X++ as two strings with the name and the base data. In java script as shown below.
$(".droparea").on("drop", function (event) {
event.preventDefault();
event.stopPropagation();
var file = event.originalEvent.dataTransfer.files;
for (let i = 0; i < file.length; i++)
{
var fileName = file[i].name;
var fileBase64 = window.btoa(file[i]);
var params = { _fileName: fileName, _fileBase64: fileBase64 };
//send files to x++ Control-Class
$dyn.callFunction(self.SetFiles, self, params);
}
});

Javascript and HTML5 File API - problems getting file correctly routed to function

I am wondering how to define a file reference for an HTML5 'file' object, to be used as input to a JavaScript function that will convert the file into Base64 encoding, WITHOUT using an interactive file input element. I have seen the HTML5Rocks examples, and numerous others, but they all use an <input type=file> element to read and gather inputs about the file to operate on. I am intending to take image files (i.e. binary) as input, and output Base64 strings. (Perhaps it is obvious, but I am new to the HTML5 and JavaScript worlds)
Some of my reading seems to indicate that this isn't possible for security reasons: JS would then be able to run arbitrary files. I wanted to double check.
What is the output of the 'file' input type? Can I manually mimic it in some way? (I found one reference here about just directly including the file itself inside the JS, but can you do that with a binary file? Frankly, not sure how I would do that on the FileMaker side, though, either. My plan, up to this point, was the export the file from FileMaker to a known location, then use that location as the input to the JavaScript)
The whole picture: I am trying to create a self contained web-viewer element in FileMaker 12. In FileMaker, I can dynamically define my HTML and JavaScript BEFORE running it. I want to dynamically hardcode the JavaScript to ALREADY contain the file reference based on the information from the database (i.e. path and filename). This is all running on a local machine, no server involved.
I am trying to minimize the interaction the end user has to make to get the file encoded: I don't want them to have to put the image into the database, and then also have to drop (or file-chooser) the image again in the web viewer. I want to keep all of this code inside the FileMaker database to make it much more portable and robust, i.e. not have to rely on an internet connection. So, the user puts their file into the database, which automatically detects that event, it calculates the JavaScript (including the path to the file), and the JavaScript runs the Base64 function on it, returning the encoded string to the database.
Perhaps I should do it the other way around: have the user drop the file into a JavaScript area that then copies it into the database. Not sure that the JavaScript would have any handles for interacting with the database, though.
------------------------ EDIT (in addition to some tagging and flagging of original question)
Let's ignore the whole FileMaker side of things for now. I decided to go the route of just using HTML5 and JavaScript as the file input portion (instead of trying to read it in FM and then output to JS). Just to see if I can get the JavaScript part to work.
Here is some code that I am playing with right now. It is mostly from the HTML5 Rocks demo, as well as the base64 encoding routine I found. However, I am running into problems with exactly how to define and call my reader, the onload event, and the encoding function. Any suggestions would be appreciated:
<script>
// From: http://www.html5rocks.com/en/tutorials/file/dndfiles/
// JC update: changing the handleFileSelect() function to do the base64 Processing
function base64Encode(aFile) {
/*
* base64.js - Base64 encoding and decoding functions
* See: http://developer.mozilla.org/en/docs/DOM:window.btoa
* http://developer.mozilla.org/en/docs/DOM:window.atob
* Copyright (c) 2007, David Lindquist <david.lindquist#gmail.com>
* Released under the MIT license
*
* JC, update: Removed the 'atob' section of code; only need ENcoding, not DEcoding.
*/
if (typeof btoa == 'undefined') {
function btoa(str) {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var encoded = [];
var c = 0;
while (c < str.length) {
var b0 = str.charCodeAt(c++);
var b1 = str.charCodeAt(c++);
var b2 = str.charCodeAt(c++);
var buf = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
var i0 = (buf & (63 << 18)) >> 18;
var i1 = (buf & (63 << 12)) >> 12;
var i2 = isNaN(b1) ? 64 : (buf & (63 << 6)) >> 6;
var i3 = isNaN(b2) ? 64 : (buf & 63);
encoded[encoded.length] = chars.charAt(i0);
encoded[encoded.length] = chars.charAt(i1);
encoded[encoded.length] = chars.charAt(i2);
encoded[encoded.length] = chars.charAt(i3);
}
return encoded.join('');
}
}
}
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object - a FileList of File objects.
var fReader = new FileReader () ;
var output = [];
for (var i = 0, f; f = files[i]; i++) {
if ( !f.type.match('image.*')) { continue; } //To skip non-image files
fReader.onLoad = (function (aFile) { return base64Encode(aFile); } ) (f);
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'<br><br>' , fReader.readAsBinaryString(f) , '<br><br>', '</li>');
//This defines the 'onLoad' behavior/function...I think.
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
// Setup the dnd listeners. [Slightly modified by JC]
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
</script>
No, in web browsers you can't access arbitrary files on user's computer. Never ever.
You can get files from the network (but read contents only if they are from the same origin or allowed via CORS, and file:// protocol doesn't allow it), IndexedDB database and Chrome's sandboxed filesystem (which is not user's filesystem — it only contains files you've put there yourself).
And you can create "files" yourself:
var file = new Blob(["file content"], {type:"text/plain"})
Blob is the base class of File and it's generally usable everywhere where input.files[] is.
You may have privileges to access local files from other JS-based environments like Widgets or browser extensions.

How to resolve the C:\fakepath?

<input type="file" id="file-id" name="file_name" onchange="theimage();">
This is my upload button.
<input type="text" name="file_path" id="file-path">
This is the text field where I have to show the full path of the file.
function theimage(){
var filename = document.getElementById('file-id').value;
document.getElementById('file-path').value = filename;
alert(filename);
}
This is the JavaScript which solve my problem. But in the alert value gives me
C:\fakepath\test.csv
and Mozilla gives me:
test.csv
But I want the local fully qualified file path. How to resolve this issue?
If this is due to browser security issue then what should be the alternate way to do this?
Some browsers have a security feature that prevents JavaScript from knowing your file's local full path. It makes sense - as a client, you don't want the server to know your local machine's filesystem. It would be nice if all browsers did this.
Use
document.getElementById("file-id").files[0].name;
instead of
document.getElementById('file-id').value
I use the object FileReader on the input onchange event for your input file type! This example uses the readAsDataURL function and for that reason you should have an tag. The FileReader object also has readAsBinaryString to get the binary data, which can later be used to create the same file on your server
Example:
var input = document.getElementById("inputFile");
var fReader = new FileReader();
fReader.readAsDataURL(input.files[0]);
fReader.onloadend = function(event){
var img = document.getElementById("yourImgTag");
img.src = event.target.result;
}
If you go to Internet Explorer, Tools, Internet Option, Security, Custom, find the "Include local directory path When uploading files to a server" (it is quite a ways down) and click on "Enable" . This will work
I am happy that browsers care to save us from intrusive scripts and the like. I am not happy with IE putting something into the browser that makes a simple style-fix look like a hack-attack!
I've used a < span > to represent the file-input so that I could apply appropriate styling to the < div > instead of the < input > (once again, because of IE). Now due to this IE want's to show the User a path with a value that's just guaranteed to put them on guard and in the very least apprehensive (if not totally scare them off?!)... MORE IE-CRAP!
Anyhow, thanks to to those who posted the explanation here: IE Browser Security: Appending "fakepath" to file path in input[type="file"], I've put together a minor fixer-upper...
The code below does two things - it fixes a lte IE8 bug where the onChange event doesn't fire until the upload field's onBlur and it updates an element with a cleaned filepath that won't scare the User.
// self-calling lambda to for jQuery shorthand "$" namespace
(function($){
// document onReady wrapper
$().ready(function(){
// check for the nefarious IE
if($.browser.msie) {
// capture the file input fields
var fileInput = $('input[type="file"]');
// add presentational <span> tags "underneath" all file input fields for styling
fileInput.after(
$(document.createElement('span')).addClass('file-underlay')
);
// bind onClick to get the file-path and update the style <div>
fileInput.click(function(){
// need to capture $(this) because setTimeout() is on the
// Window keyword 'this' changes context in it
var fileContext = $(this);
// capture the timer as well as set setTimeout()
// we use setTimeout() because IE pauses timers when a file dialog opens
// in this manner we give ourselves a "pseudo-onChange" handler
var ieBugTimeout = setTimeout(function(){
// set vars
var filePath = fileContext.val(),
fileUnderlay = fileContext.siblings('.file-underlay');
// check for IE's lovely security speil
if(filePath.match(/fakepath/)) {
// update the file-path text using case-insensitive regex
filePath = filePath.replace(/C:\\fakepath\\/i, '');
}
// update the text in the file-underlay <span>
fileUnderlay.text(filePath);
// clear the timer var
clearTimeout(ieBugTimeout);
}, 10);
});
}
});
})(jQuery);
On Chrome/Chromium based apps like electron you can just use the target.files:
(I'm using React JS on this example)
const onChange = (event) => {
const value = event.target.value;
// this will return C:\fakepath\somefile.ext
console.log(value);
const files = event.target.files;
//this will return an ARRAY of File object
console.log(files);
}
return (
<input type="file" onChange={onChange} />
)
The File object I'm talking above looks like this:
{
fullName: "C:\Users\myname\Downloads\somefile.ext"
lastModified: 1593086858659
lastModifiedDate: (the date)
name: "somefile.ext"
size: 10235546
type: ""
webkitRelativePath: ""
}
So then you can just get the fullName if you wanna get the path.
Note that this would only work on chrome/chromium browsers, so if you don't have to support other browsers (like if you're building an electron project) you can use this.
I came accross the same problem. In IE8 it could be worked-around by creating a hidden input after the file input control. The fill this with the value of it's previous sibling. In IE9 this has been fixed aswell.
My reason in wanting to get to know the full path was to create an javascript image preview before uploading. Now I have to upload the file to create a preview of the selected image.
If you really need to send the full path of the uploded file, then you'd probably have to use something like a signed java applet as there isn't any way to get this information if the browser doesn't send it.
Use file readers:
$(document).ready(function() {
$("#input-file").change(function() {
var length = this.files.length;
if (!length) {
return false;
}
useImage(this);
});
});
// Creating the function
function useImage(img) {
var file = img.files[0];
var imagefile = file.type;
var match = ["image/jpeg", "image/png", "image/jpg"];
if (!((imagefile == match[0]) || (imagefile == match[1]) || (imagefile == match[2]))) {
alert("Invalid File Extension");
} else {
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(img.files[0]);
}
function imageIsLoaded(e) {
$('div.withBckImage').css({ 'background-image': "url(" + e.target.result + ")" });
}
}
seems you can't find the full path in you localhost by js, but you can hide the fakepath to just show the file name. Use jQuery to get the file input's selected filename without the path
The best solution for this, I've found, is to use a middleware like Multer. Here's a quick rundown:
npm i multer
Add enctype="multipart/form-data" to your html form.
In your backend dock where you're making your post request, require multer (const multer = require('multer'))
In the same dock, set your upload destination: const upload = multer({dest:'uploas/'}). This will automatically create a local folder called 'uploads' where your files will be added. The code I've included shows you how to upload to your local disk storage. If you're using cloud storage (e.g. AWS, Azure, Cloudinary etc.) you can check out the Multer docs to see how to manage that. There aren't too many extra steps though.
in your post request, add 'upload.single' (for one file) or 'upload.array' (for multiple files), like this:
router.post('/new', upload.single('image'), async function(req, res) { //'image' should be the name of the input you're sending in the req.body
console.log(req.file) //note, if you're using 'upload.array', this should be 'req.files'
});
the req.file will have a full path name that you can use in your post request. For more information, check out the Multer docs:
https://www.npmjs.com/package/multer
I hope this helps!
You would be able to get at least temporary created copy of the file path on your machine. The only condition here is your input element should be within a form
What you have to do else is putting in the form an attribute enctype, e.g.:
<form id="formid" enctype="multipart/form-data" method="post" action="{{url('/add_a_note' )}}">...</form>
you can find the path string at the bottom.
It opens stream to file and then deletes it.
Hy there , in my case i am using asp.net development environment, so i was want to upload those data in asynchronus ajax request , in [webMethod] you can not catch the file uploader since it is not static element ,
so i had to make a turnover for such solution by fixing the path , than convert the wanted image into bytes to save it in DB .
Here is my javascript function ,
hope it helps you:
function FixPath(Path)
{
var HiddenPath = Path.toString();
alert(HiddenPath.indexOf("FakePath"));
if (HiddenPath.indexOf("FakePath") > 1)
{
var UnwantedLength = HiddenPath.indexOf("FakePath") + 7;
MainStringLength = HiddenPath.length - UnwantedLength;
var thisArray =[];
var i = 0;
var FinalString= "";
while (i < MainStringLength)
{
thisArray[i] = HiddenPath[UnwantedLength + i + 1];
i++;
}
var j = 0;
while (j < MainStringLength-1)
{
if (thisArray[j] != ",")
{
FinalString += thisArray[j];
}
j++;
}
FinalString = "~" + FinalString;
alert(FinalString);
return FinalString;
}
else
{
return HiddenPath;
}
}
here only for testing :
$(document).ready(function () {
FixPath("hakounaMatata:/7ekmaTa3mahaLaziz/FakePath/EnsaLmadiLiYghiz");
});
// this will give you : ~/EnsaLmadiLiYghiz

Categories

Resources