Firefox Quantum for Android - backup profile without root?
I had the same problem and got inspired by your idea to use WebIDE. It turns out it is possible to access the profile files throughout JavaScript at least in my Firefox for Android version 59.0.2, but this only helps partially to back up all profile data.

Principle

The file contents can be accessed using Ajax (see here), also if they are binary (reference). It however seems like you can only access files that are in your current directory or that are in a subdirectory.

For example, the contents of browser.db can be accessed by navigating to file:///data/data/org.mozilla.firefox/files/mozilla/XXXXXXXX.default/ and then executing in the console via WebIDE:

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "browser.db");
xmlhttp.responseType = "arraybuffer";
xmlhttp.send();


The result will then be stored in xmlhttp.response as an arraybuffer. If the data is non-binary, "text" can be used instead of "arraybuffer".

For small, non-binary files it can by sufficient to copy them to the clipboard with copy(xmlhttp.responseText), but for larger files this can throw an out of memory error.

The same technique can be used to get a listing of files and directories. The problem is that this (for me at least) worked only for the directory the browser was navigated to, but not for subdirectories. The returned data is a list of files as plain text:

300: file:///data/data/org.mozilla.firefox/files/mozilla/XXXXXXXX.default/
200: filename content-length last-modified file-type
201: AlternateServices.txt 0 Thu,%2010%20May%202018%2015:33:20%20GMT FILE 
201: OfflineCache 0 Thu,%2009%20Nov%202017%2018:28:54%20GMT DIRECTORY
...


Backing up

For completeness, here are two scripts I used to backup the files. Both are only quick&amp;dirty and minimal scripts. The data is transferred to a Python server running on the computer, which then stores them.

Important: They only backup the files in the current directory, but not the directories (See the limitation above). However since most of the profile is in the root directory this might be sufficient. If you want to store the files in the subdirectories as well you need to paste and run the JavaScript again for each directory. The neccessary directories will be created by the server.

Python server (save this as server.py and then run e.g. with python3 server.py 2222 depending on the port you want to use)

import os
from http.server import BaseHTTPRequestHandler, HTTPServer

class FileReceiveHandler(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()

    def do_POST(self):
        content_length = int(self.headers['Content-Length']) # &lt;--- Gets the size of data
        post_data = self.rfile.read(content_length) # &lt;--- Gets the data itself
        print(self.path)

        # Store file
        relative_file_path = os.path.join('received_files', self.path.lstrip('/'))
        directories = os.path.dirname(relative_file_path)
        os.makedirs(directories, exist_ok=True)
        with open(relative_file_path, 'wb') as f:
            f.write(post_data)

        self._set_headers()
        self.wfile.write(b'received')


if __name__ == '__main__':
    from sys import argv
    port = int(argv[1]) if len(argv) == 2 else 80
    server_address = ('', port)
    httpd = HTTPServer(server_address, FileReceiveHandler)
    print('Starting server')
    httpd.serve_forever()


This is the source I used as a reference for the server.

JavaScript source for the browser

Adapt the first two lines to your own profile path and local IP address and port. Then paste this script directly in the console of WebIDE with the browser navigated to the profile directory.

var profile_basepath = "file:///data/data/org.mozilla.firefox/files/mozilla/XXXXXXXX.default";
var server = "http://&lt;your_local_ip&gt;:2222";

function send() {
    var list_xmlhttp = new XMLHttpRequest();

    // Get files
    list_xmlhttp.onreadystatechange = function() {
        if(list_xmlhttp.status == 200 &amp;&amp; list_xmlhttp.readyState == 4){
            itemslist = list_xmlhttp.response.split('\n');

            for (var i = 0; i &lt; itemslist.length; i++) {
                if (itemslist[i].startsWith('201:')) {
                    parts = itemslist[i].split(' ');
                    if (parts[4] == 'FILE') {
                        handleFile(parts);
                    }
                }
            }
            console.log(itemslist);
        }
    };
    list_xmlhttp.open("GET", window.location.href, true);
    list_xmlhttp.responseType = "text";
    list_xmlhttp.send();
}

function handleFile(parts) {
    var filename = JSON.parse(JSON.stringify(parts[1]));

    // Get file content
    var file_xmlhttp = new XMLHttpRequest();
    file_xmlhttp.onreadystatechange = function() {
        if(file_xmlhttp.status == 200 &amp;&amp; file_xmlhttp.readyState == 4){
            // Send file
            var filepath = window.location.href.substring(profile_basepath.length) + filename;
            var send_xmlhttp = new XMLHttpRequest();
            send_xmlhttp.open("POST", server + filepath, true);
            send_xmlhttp.send(file_xmlhttp.response);

            console.log(filepath + " sent");
        }
    }
    file_xmlhttp.open("GET", window.location.href + parts[1], true);
    file_xmlhttp.responseType = "arraybuffer";
    file_xmlhttp.send();
}

send();


It might take some time until the script has finished.