Downloading Files From Google Drive Under No Authorization Using Browser

Gist

This is a sample script for downloading files from Google Drive under no authorization using browser. By using this sample, you can make other users download files from your Google Drive. Even if the other users are not Google users, they can download the files.

Demo

This is a demonstration for downloading files from Google Drive under no authorization using browser. From the top document, You can see that an user who is not owner of Google Drive is downloading files.

Problems and Workaround

In order to download files from Google Drive under no authorization, there are some problems. When files are downloaded from Google Drive, it is necessary to use Download Link and Drive API.

  1. In the case of use the Download Link for each file, only owner of Google Drive can download the files, even if the permission of files are changed as the ANYONE.
  2. In the case of use the Drive API, users have to authorize at Google using OAuth2 process.

I have already known that files can download under no authorization using base64 and byte array. For these problems, I solved this using base64.

Sample Script

In order to use this sample script, it is necessary to deploy Web Apps. The how to deploy Web Apps is as follows.

  • On the Script Editor
    • File
    • -> Manage Versions
    • -> Save New Version
    • Publish
    • -> Deploy as Web App
    • -> At Execute the app as, select “your account”
    • -> At Who has access to the app, select “Anyone, even anonymous”
    • -> Click “Deploy”
    • -> Copy “Current web app URL”
    • -> Click “OK”

And then, please copy and paste following respective HTML and GAS to your script editor. You can use the sample for the script of both container-bound script and standalone script. Following image is the project pasted the sample script. You can see the 2 files in the project.

Script

HTML

Filename is index.html.

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>

<body>
    <div class="files">
        <form>
            <table class="table table-striped table-hover">
                <thead>
                    <tr>
                        <th>Download</th>
                        <th>FileName</th>
                        <th>Size[byte]</th>
                        <th>Parents</th>
                        <th>Updated</th>
                        <th>Created</th>
                    </tr>
                </thead>
                <tbody>
                    <? for (var i = 0; i < data.length; i++) { ?>
                        <tr>
                            <td>
                                <input type="checkbox" id="checkbox" name="fileId" value="<?= data[i].file_id  ?>" />
                            </td>
                            <td>
                                <?= data[i].file_name ?>
                            </td>
                            <td>
                                <?= data[i].file_size ?>
                            </td>
                            <td>
                                <?= data[i].folder_tree ?>
                            </td>
                            <td>
                                <?= data[i].file_updated ?>
                            </td>
                            <td>
                                <?= data[i].file_created ?>
                            </td>
                        </tr>
                        <? } ?>
                </tbody>
            </table>
            <div class="allchk">
                <input type="checkbox" id="allCheck01">
                <label for="allCheck01">Check All</label>
            </div>
            <input type="button" class="create" value="Download" onclick="google.script.run.withSuccessHandler(executeDownload).getparams(this.parentNode)">
        </form>
    </div>
    <a id="dl" target="_blank" href="#"></a>
</body>

<script>
$(function() {
    $('.table tr').click(function(event) {
        if (event.target.type !== 'checkbox') {
            $(':checkbox', this).trigger('click');
        }
    });

    $('.allchk input').click(function() {
        var files = $('.files').find('input');
        if ($(this).is(':checked')) {
            $(files).prop('checked', true);
        } else {
            $(files).prop('checked', false);
        }
    });
});

function executeDownload(base64dat) {
    $("#dl").prop("href", window.URL.createObjectURL(toBlob(base64dat))).prop("download", "dl_" + getfmtDate() + ".zip")[0].click();
}

function toBlob(base64) {
    var bin = atob(base64.replace(/^.*,/, ''));
    var buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
        buffer[i] = bin.charCodeAt(i);
    }
    try {
        var blob = new Blob([buffer.buffer], {
            type: 'application/zip'
        });
    } catch (e) {
        return false;
    }
    return blob;
}

function getfmtDate() {
    var dt = new Date();
    return dt.getFullYear().toString() +
        cd((dt.getMonth() + 1).toString()) +
        cd(dt.getDate().toString()) +
        "_" +
        cd(dt.getHours().toString()) +
        cd(dt.getMinutes().toString()) +
        cd(dt.getSeconds().toString());
};

function cd(dat) {
    return dat.length == 1 ? "0" + dat : dat;
};
</script>

</html>

Google Apps Script

Filename is code.gs.

var folderId = "### Folder ID ###"; // <--- Your shared folder ID

function doGet() {
    var t = HtmlService.createTemplateFromFile('index');
    t.data = getFileList();
    return t.evaluate();
}

function getparams(e) {
    return zipping(typeof(e.fileId) == "string" ? [e.fileId] : e.fileId);
}

function getFileList() {
    var folderlist = (function(folder, folderSt, results) {
        var ar = [];
        var folders = folder.getFolders();
        while (folders.hasNext()) ar.push(folders.next());
        folderSt += folder.getId() + "#_aabbccddee_#";
        var array_folderSt = folderSt.split("#_aabbccddee_#");
        array_folderSt.pop()
        results.push(array_folderSt);
        ar.length == 0 && (folderSt = "");
        for (var i in ar) arguments.callee(ar[i], folderSt, results);
        return results;
    })(DriveApp.getFolderById(folderId), "", []);
    var localTimeZone = Session.getScriptTimeZone();
    var filelist = [];
    var temp = {};
    for (var i in folderlist) {
        var folderid = folderlist[i][folderlist[i].length - 1];
        var folder = DriveApp.getFolderById(folderid);
        var files = folder.getFiles();
        while (files.hasNext()) {
            var file = files.next();
            temp = {
                folder_tree: function(folderlist, i) {
                    if (i > 0) {
                        return "/" + [DriveApp.getFolderById(folderlist[i][j]).getName() for (j in folderlist[i])
                            if (j > 0)].join("/") + "/";
                    } else {
                        return "/";
                    }
                }(folderlist, i),
                file_id: file.getId(),
                file_name: file.getName(),
                file_size: file.getBlob().getBytes().length,
                file_created: Utilities.formatDate(file.getDateCreated(), localTimeZone, "yyyy/MM/dd HH:mm:ss"),
                file_updated: Utilities.formatDate(file.getLastUpdated(), localTimeZone, "yyyy/MM/dd HH:mm:ss"),
            };
            filelist.push(temp);
            temp = {}
        }
    }
    var sortedlist = filelist.sort(function(e1, e2) {
        return (e1.folder_tree > e2.folder_tree ? 1 : -1) });
    return sortedlist;
}

function zipping(fileId) {
    var blobs = [];
    var mimeInf = [];
    fileId.forEach(function(e) {
        try {
            var file = DriveApp.getFileById(e);
            var mime = file.getMimeType();
            var name = file.getName();
        } catch (e) {
            return e
        }
        Logger.log(mime)
        var blob;
        if (mime.indexOf('google-apps') > 0) {
            mimeInf =
                mime == "application/vnd.google-apps.spreadsheet" ? ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", name + ".xlsx"] : mime == "application/vnd.google-apps.document" ? ["application/vnd.openxmlformats-officedocument.wordprocessingml.document", name + ".docx"] : mime == "application/vnd.google-apps.presentation" ? ["application/vnd.openxmlformats-officedocument.presentationml.presentation", name + ".pptx"] : ["application/pdf", name + ".pdf"];
            blob = UrlFetchApp.fetch("https://www.googleapis.com/drive/v3/files/" + e + "/export?mimeType=" + mimeInf[0], {
                method: "GET",
                headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
                muteHttpExceptions: true
            }).getBlob().setName(mimeInf[1]);
        } else {
            blob = UrlFetchApp.fetch("https://www.googleapis.com/drive/v3/files/" + e + "?alt=media", {
                method: "GET",
                headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
                muteHttpExceptions: true
            }).getBlob().setName(name);
        }
        blobs.push(blob);
    });
    var zip = Utilities.zip(blobs, Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyyMMdd_HHmmss") + '.zip');
    var bytedat = DriveApp.createFile(zip).getBlob().getBytes();
    return Utilities.base64Encode(bytedat);
}

Flow of sample script

  1. All files in a folder that owner of Google Drive decided display as a list using Web Apps.
  2. Users access to the site which was used by Web Apps using own browser.
  3. When users clicked the files from the list and pushed DOWNLOAD button, the files are converted to base64 using Google Apps Script.
  4. The converted-base64 data are transfered to the site and are converted to blob using Javascript in HTML.
  5. The blob data are compressed by ZIP, and then they are downloaded.
  6. Google Spreadsheet, Google Document and Google Slide are converted to Microsoft Excel, Word and Powerpoint, respectively. Images and PDF are not converted to other format.

Sample Folder Structure

The folder structure as a sample is as follows. sharedFolder is the top directory that owner was set. All of files and directories in the directory that owner defined is displayed as a list. At the demonstration, you can see it.

References

TOP

 Share!