I am writing a chrome extension that will intercept certain downloads (currently .doc and .docx files) and instead take those files and automatically upload them to your Google driver folder. Here is my manifest:
{
// Default manifest crap.
"manifest_version": 2,
"name": "App",
"description": "SpartaHack 2016 application",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
// Content security needed to access gapi script.
"content_security_policy": "script-src 'self' https://apis.google.com; object-src 'self'",
// Need to view downloads, and identity for obvious reasons.
// The other two permissions allow the script to access files that are outside our domain.
"permissions": [
"downloads",
"identity",
"http://*/",
"https://*/"
],
// Gives us the auth information.
"oauth2": {
"client_id": "id",
"scopes": [
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/userinfo.profile"
]
},
// Scripts that are always running.
// Client.js has the gapi script, eventPage is our code.
"background": {
"scripts": ["client.js", "eventPage.js"]
}
}
I have also written the following method that preforms authorization, if needed:
chrome.identity.getAuthToken({
"interactive": true
}, sendAuthToken);
function sendAuthToken(token) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + token, true);
xhr.onload = function() {
console.log(xhr.response);
}
//TODO:
xhr.send();
console.log(token);
watchDownloads();
}
This snippet I found from an example somewhere. It seemed it wasn't enough to just preform authorization, but that I had to send a request for the user's information using this token as well. This part doesn't give me any trouble - the token is logged fine, and the response that is logged shows all of my information as expected.
Here is what watchDownloads() looks like:
function watchDownloads() {
chrome.downloads.onCreated.addListener(function(download) {
if(download.url.endsWith(".doc") || download.url.endsWith(".docx")) {
// Get blob from URL
var xhr = new XMLHttpRequest();
xhr.open("GET", download.url, true);
xhr.responseType = "blob";
xhr.onload = function(error) {
if(this.status == 200) {
insertFile(this.response, function(resp) {
console.log(resp);
});
}
};
xhr.send();
}
});
}
In short, it looks for the two file extensions I am concerned with, and if it sees them it should then get that file using another HTTP request directly to the file's url, and then upload it into drive for us using this method, which has been mostly pieced together from online samples:
function insertFile(fileData, callback) {
const boundary = "-------314159265358979323846";
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delimiter = "\r\n--" + boundary + "--";
//TODO: Remove
console.log(fileData);
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(error) {
var contentType = fileData.type || "application/octet-stream";
var metadata = {
// "title": fileData.filename,
"title": "Potato",
"mimeType": contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
"Content-Type: application/json\r\n\r\n" +
JSON.stringify(metadata) +
delimiter +
"Content-Type: " + contentType + "\r\n" +
"Content-Transfer-Encoding: base64\r\n\r\n" +
base64Data +
close_delimiter;
//TODO: Remove
console.log(multipartRequestBody);
var request = gapi.client.request({
"path": "/upload/drive/v3/files",
"method": "POST",
"params": {
"key": "key",
"uploadType": "multipart"
},
"headers": {
"Content-Type": 'multipart/mixed; boundary="' + boundary + '"'
},
"body": multipartRequestBody
});
//TODO: Remove
console.log(request);
if(!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
This is where it fails. I can't seem to get this to work, as the following error appears each time:
What do I have to do to have the proper login here? I have tried adding an Authorization
property in the header, but get the same error.
This might help others stumbling upon this question.
If you did authorise using JWT, make sure to include auth: <your jwtClient>
in your API call, like:
First, get the token:
// Configure JWT auth client
var privatekey = require("./<secret>.json")
var jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
['https://www.googleapis.com/auth/drive']
);
// Authenticate request
jwtClient.authorize(function (err, tokens) {
if (err) {
return;
} else {
console.log("Google autorization complete");
}
});
Then, call the API (but don't forget the auth:jwtClient
part)
drive.files.create({
auth: jwtClient,
resource: {<fileMetadata>},
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
} else {
// Success is much harder to handle
}
});
Google Drive API (and other Google products as well) uses oAuth2.0 for its authorization protocol. All requests that will be made are to be authorized.
The detailed steps in authorizing your application to use the Drive API can be found in the documentation.
You can use https://www.googleapis.com/auth/drive
if you want full access to the user's files, or a specific one listed on the page as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With