-
Notifications
You must be signed in to change notification settings - Fork 0
/
background.js
206 lines (196 loc) · 9.54 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
var QD = (function () {
//INTERNAL FUNCTIONS AND VARIABLES
var _update_settings,
_account_actions,
_download_url,
_build_filename,
qd_settings = null,
active_downloads = {},
queued_callbacks = {},
MIME_TYPES = {"application/msword": "doc","application/pdf": "pdf","application/rtf": "rtf","application/vnd.ms-excel": "xls","application/vnd.ms-powerpoint": "ppt","application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx","application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx","application/x-chrome-extension": "crx","application/x-gzip": "gzip","application/x-pdf": "pdf","application/zip": "zip",
"audio/mp4": "mp4","audio/mpeg": "mp3","audio/ogg": "ogg","audio/vnd.wave": "wav","image/gif": "gif","image/jpeg": "jpg","image/pjpeg": "jpg","image/png": "png","image/svg+xml": "svg","image/tiff": "tif","image/vnd.microsoft.icon": "ico","text/css": "css","text/csv": "csv","text/html": "html","text/mhtml": "mht","text/plain": "txt","text/tsv": "tsv","text/xml": "xml","video/mp4": "mp4","video/mpeg": "mpg","video/ogg": "ogg"},
ELEMENT_TYPES = {'img':1, 'audio':1, 'video':1};
_build_filename = function(domain, content_type) {
var today = new Date();
return domain.replace('.', '_') + "-" + today.getFullYear() +"_"+ (today.getMonth()+1) +"_"+ today.getDay() + "." + (content_type.toLowerCase() in MIME_TYPES ? MIME_TYPES[content_type.toLowerCase()] : "unknown");
};
//SAVE URL TO MEMORY AND CALLBACK
_download_url = function(data, error_callback, callback) {
var reader, xhr = new XMLHttpRequest();
xhr.open('GET', data.object_url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e){
if (this.status == 200) {
data.content_type = this.getResponseHeader('content-type');
data.blob = new Blob([this.response], {type:data.content_type});
reader = new FileReader();
reader.readAsDataURL(data.blob);
reader.onloadend = function(e){
data.raw_data = reader.result;
data.file_name = _build_filename(data.citation_domain, data.content_type);
callback(data);
}
} else { error_callback({success:false, alert:"Error Downloading File"}); }
};
xhr.send();
};
//ACCOUNT ACTIONS - WHERE BEHAVIOR SPECIFIC TO AN ACCOUNT GOES
_account_actions = {
s3: function(data, callback) {
if('s3' in qd_settings.accounts && qd_settings.accounts.s3.active && qd_settings.accounts.s3.bucket) {
AWS.config.update({accessKeyId:qd_settings.accounts.s3.access_key, secretAccessKey:qd_settings.accounts.s3.secret_key});
_download_url(data, callback, function(data) {
var s3 = new AWS.S3();
s3.upload({Bucket: qd_settings.accounts.s3.bucket, Key: data.file_name, ContentType: data.content_type, ACL:"public-read", Body: data.blob},
function (err, data) {
console.error(arguments);
callback({success:err, alert:err ? "S3 Error" : "Uploaded to S3"});
});
});
}
},
dropbox: function(data, callback) {
//DROPBOX SAVER DROPIN MUST BE TRIGGERED FROM A NON-EXTENSION DOM,
//BUT IT MUST BE TRIGGERED FROM A PRE-APPROVED DOMAIN.
//STEP 1: DROP AN IFRAME IN THE CURRENT TAB THAT LOADS A RANDOM ERROR PAGE ON DROPOXUSERCONTENT.cOM
//STEP 2: MANIFEST.JSON SPECIFIES A CONTENT SCRIPT TO RUN IN THAT PAGE, INJECTING THE SAVER SCRIPTS
//STEP 3: AT THAT POINT THE CALLBACK CHAIN IS BROKEN, QUEUE CALLBACK IN BACKGROUND AND WAIT FOR A MESSAGE FROM DOM
_download_url(data, callback, function(data) {
chrome.contentSettings.popups.set({primaryPattern:data.citation_protocol + "//" + data.citation_domain + "/*", setting:"allow" });
var uid = +new Date();
chrome.tabs.executeScript(data.sender.tab.id, {
code: `var qd_iframe = document.createElement("iframe");
qd_iframe.setAttribute("style", "position:fixed; top:-4000px; left:-4000px;");
qd_iframe.src = "https://dl.dropboxusercontent.com/emptypage?url=` + encodeURIComponent(data.object_url) + `&filename=` + data.file_name + `&uid=` + uid + `&extension_id=` + chrome.runtime.id + `";
document.body.appendChild(qd_iframe);
function removeQDIframe(event){
if (event.data=="removeQDIframe") document.body.removeChild(qd_iframe);
}
window.addEventListener("message", removeQDIframe, false);`
});
queued_callbacks[uid] = callback;
});
},
google_drive: function(data, callback) {
_download_url(data, callback, function(data) {
//CREATE DRIVE UPLOAD REQUEST
var bound = 287032396531387;
var parts = [];
//PART 1 IS METADATA
parts.push('--' + bound);
parts.push('Content-Type: application/json');
parts.push('');
parts.push(JSON.stringify({title: data.file_name, mimeType:data.content_type, description:data.description + " - Found on " + data.citation_url, indexableText:{text:data.description}}));
parts.push('--' + bound);
//PART 2 IS IMAGE
parts.push('Content-Type: ' + data.content_type);
parts.push('Content-Transfer-Encoding: base64');
parts.push('');
parts.push(data.raw_data.replace(/^data:[^;]+;base64,/, ""));
parts.push('--' + bound + '--');
parts.push('');
chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart", true);
xhr.setRequestHeader("Authorization", "Bearer " + token);
xhr.setRequestHeader("Content-Type", "multipart/mixed; boundary=" + bound);
xhr.onload = function(e){
callback({success:true, alert:"Uploaded to Drive"});
};
xhr.send(parts.join("\r\n"));
});
});
},
local: function(data, callback) {
_download_url(data, callback, function(data) {
chrome.downloads.setShelfEnabled(false);
chrome.downloads.download({
url: data.object_url,
filename: (qd_settings.accounts.local.directory) + data.file_name
}, function(download_id) {
active_downloads[download_id] = callback;
});
});
},
twitter: function(data, callback) {
// if(data.)
},
pocket: function(data, callback) {
QD_pocket.add({url:data.citation_url, title:data.description}, function(status) {
if(status === 1) { callback({success:true, alert:'Added to Pocket'}); }
});
}
};
_update_settings = function(data) {
if(!('version' in data)) {
//UPDATE CODE
chrome.tabs.create({url:"chrome://extensions/?options=" + chrome.runtime.id}); //TODO - LOOK TO SEE IF EXTENSIONS TAB IS ALREADY OPEN
} else {
qd_settings = qd_settings || {'accounts':{}};
if(data.sections) {
for(var section_name of data.sections) {
if(section_name in data.content && 'options' in data.content[section_name] && data.content[section_name].options instanceof Array) {
var ptr = ('class' in data.content[section_name] && data.content[section_name].class === "account" ? qd_settings['accounts'] : qd_settings);
ptr[section_name] = {'title':data.content[section_name].title || ""};
if('create_index' in data.content[section_name]) { ptr[section_name].index = []; }
for(var option of data.content[section_name].options) {
if('name' in option) {
if('id' in option && option.value) ptr[section_name][option.name] = option.id;
} else if('id' in option) {
ptr[section_name][option.id] = option.value;
if( 'index' in ptr[section_name]) { ptr[section_name].index.push(option.id); }
if('required' in option && option.required === true && option.value === '') {
ptr[section_name]['active'] = false;
}
}
}
}
}
}
}
};
return {
//EXPOSE UPDATE SETTINGS AS PUBLIC
update_settings: function(data) { _update_settings(data); },
//HANDLES MESSAGES FROM BROWSER (AS A RESULT OF DRAG/DROP ACTIONS, REQUESTS FOR SETTINGS, OTHER EXTERNAL MESSAGES)
message_router: function(message, sender, sendResponse) {
console.log(message);
//ROUTE TO ACCOUNT-SPECIFIC FUNCTION IF APPLICABLE
message.sender = sender;
if('action' in message && message.action in _account_actions) { _account_actions[message.action](message, sendResponse); }
//BROWSER SCRIPT CAN REQUEST CURRENT CONFIGURATION
else if ('accountRequest' in message) { sendResponse(qd_settings); }
//DROPBOX FOLLOW-UP MESSAGE FROM IFRAME DOM
else if('dropbox' in message) {
if('uid' in message && message.uid in queued_callbacks) {
queued_callbacks[message.uid]({success:message.success, alert:message.alert});
delete queued_callbacks[message.uid];
chrome.contentSettings.popups.clear({});
sendResponse({});
}
}
return true;
},
settings_watcher: function(changes, namespace) {
if ("content" in changes) {
chrome.storage.sync.get(null, _update_settings);
}
},
download_watcher: function(download_item) {
if(download_item.id in active_downloads && ('state' in download_item && download_item.state.current === "complete")) {
//CALLBACK
active_downloads[download_item.id]({success:true, alert:"Saved"});
//REMOVE FROM ACTIVE DOWNLOADS
delete active_downloads[download_item.id];
//RE-ENABLE THE DOWNLOAD SHELF FOR REGULAR BROWSING
chrome.downloads.setShelfEnabled(true);
}
},
get_settings: function() { return qd_settings; }
}
})();
chrome.runtime.onMessage.addListener( QD.message_router );
chrome.downloads.onChanged.addListener( QD.download_watcher );
chrome.storage.onChanged.addListener( QD.settings_watcher );
chrome.storage.sync.get(null, QD.update_settings);
chrome.runtime.onMessageExternal.addListener( QD.message_router );