0

I need to write a chrome extension, that gets the downloaded file type.

This is the existing code that gets it by the extension file.

chrome.downloads.onDeterminingFilename.addListener(function(item, __suggest) {

    function suggest(filename, conflictAction) {
        __suggest({
            filename: filename,
            conflictAction: conflictAction,
            conflict_action: conflictAction
        });
    }
    var fileType = item.fileName.substr(item.fileName.lastIndexOf('.') + 1);
    console.log(fileType);
});

I need to change the code, to get it based on the Magic number of the file.

https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files

How?

Zag Gol
  • 1,038
  • 1
  • 18
  • 43

1 Answers1

1

Using information from this page, this is a way of getting the magic numbers from files. Please choose some files from your computer with different types to test.

let filesRead = [];
let numFiles = 0;

function treatResult() {
 filesRead.map(e=>{
         const uint = new Uint8Array(e.fileStart);
                let bytes = [];
                uint.forEach((byte)=>bytes.push(byte.toString(16)));
                e.magicNumber = bytes.join('').toUpperCase();
  e.typeFromMagicNumber = getTypeFromMagicNumber(e.magicNumber);
 });
 let list = filesRead.map(e=>
  '<li>Name: ' + e.name + ' ||| MimeType: ' + e.type + ' ||| Magic Number: ' + 
      e.magicNumber + ' ||| Type from mn: ' + e.typeFromMagicNumber + '</li>').join('');
 document.getElementById('list').innerHTML = list;
} 

function getTypeFromMagicNumber(signature) {
 switch (signature) {
     case '89504E47':
  return 'image/png'
     case '47494638':
  return 'image/gif'
     case '25504446':
  return 'application/pdf'
     case 'FFD8FFDB':
     case 'FFD8FFE0':
     case 'FFD8FFE1':
  return 'image/jpeg'
     case '504B0304':
  return 'application/zip'
     default:
  return 'Unknown filetype'
 }
}

function treatFile(file) {
        const blob = file.slice(0, 4);
        var reader = new FileReader();
 reader.readAsArrayBuffer(blob);
 reader.onprogress = function(event) {
     filesRead.push({name: file.name, type : file.type, fileStart: event.target.result});
     reader.abort();
     if (filesRead.length == numFiles) 
      treatResult();
 };
}

function handleFileSelect(evt) {
 var files = evt.target.files;
 numFiles = files.length;
 for (var i = 0, f; f = files[i]; i++) 
     treatFile(files[i]);
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);
<html>
<body>
        <h1>List files with magic number types</h1>
        <input type="file" id="files" name="files[]" multiple />

        <ul id='list'></ul>

<script src="teste.js"></script>
</body>
</html>                     

Please note that the file object that is returned by the input already informs the file type in the type property.

The page I mentioned used the method onloadend to read the file. As we only need the first few bytes I don't think it's necessary to read the whole file.

Also the magic number table is very limited and should be improved for a real life application.

EDIT based on comment

FYI all of these operations are performed AT CLIENT LEVEL. ReadFile can only read client machine's files. So there is no download here. If you're trying to read a file in the server to check it's magic number before it's downloaded, that is not possible, because you not allowed by the server to read files in it using a client.

What is possible is the server to have a url prepared to receive incoming calls and then respond with a file, page or information. But to make an extension that reads the file that WILL be downloaded is not possible. You can only read the file after the download or at least after it starts to download.

Nelson Teixeira
  • 6,297
  • 5
  • 36
  • 73
  • The problem is, that I need to read it before the file downloads, to know if to block the download. – Zag Gol Apr 22 '19 at 18:11