-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackground.js
More file actions
198 lines (178 loc) · 6.68 KB
/
background.js
File metadata and controls
198 lines (178 loc) · 6.68 KB
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
////////////////////////////////////////////////////////////////////////////////
// STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE //
// STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE //
// STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE STORAGE //
////////////////////////////////////////////////////////////////////////////////
// Event pages are incompatible with WebRequest events
// so we must use persistent background page anyway.
// Take adventage from this situation we can use simpler data storage
// by storing everything needed in this background page.
// When something change we just make a copy to nonvolatile
// storage without callback needed. By doing so,
// the data maybe loss but just in very rare cases.
var globalStorage;
var asyncSequence=[];
//get data from chrome storage
asyncSequence.push(function(next){
chrome.storage.local.get(function(chromeDB){
next(null, chromeDB);
});
});
//process data for prerequisite store it in globalStorage
asyncSequence.push(function(chromeDB, next){
//init value if neccessary
if(typeof(chromeDB["rules"])!=="object"){
chrome.storage.local.clear(function(){//clear storage
chrome.storage.local.set(globalStorage={//init storage
"rules":[]
}, function(){
next(null);
});//set initial value
});//clear storage
}else{
globalStorage=chromeDB;
next(null);
}
});
////////////////////////////////////////////////////////////////////////////////
// INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE //
// INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE //
// INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE //
////////////////////////////////////////////////////////////////////////////////
//message dispatcher
var messageSystem=function(request, sender, sendResponse){
if(request.command=="getRules")
sendResponse({"rules": globalStorage["rules"]});
else if(request.command=="addRule"){
//console.log(request);
chrome.storage.local.set({
"rules":request["allRules"]
}, function(){ //update compiled rule
globalStorage["rules"]=request["allRules"];
compiledRules=migrateRules(
$.extend(true, [], request["allRules"]),
compiledRules);
});
}else if(request.command=="removeRule"){ //identical to addRules for now
//console.log(request);
chrome.storage.local.set({
"rules":request["allRules"]
}, function(){ //update compiled rule
globalStorage["rules"]=request["allRules"];
compiledRules=migrateRules(
$.extend(true, [], request["allRules"]),
compiledRules);
});
}else{
console.log("unknow message command");
console.log(request);
}
}
////////////////////////////////////////////////////////////////////////////////
// COMPILATION COMPILATION COMPILATION COMPILATION COMPILATION COMPILATION //
// COMPILATION COMPILATION COMPILATION COMPILATION COMPILATION //
// COMPILATION COMPILATION COMPILATION COMPILATION COMPILATION COMPILATION //
////////////////////////////////////////////////////////////////////////////////
var compiledRules;
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function isSameRule(ruleA, ruleB){
return ((ruleA["match"]==ruleB["match"])&&
(ruleA["pattern"]==ruleB["pattern"])&&
(ruleA["type"]==ruleB["type"]));
}
var compilerMatrix={
"H,normal":(function(pattern){
var regexTmp=("^"+escapeRegExp(pattern)).replace(
/^\^?\\?\*\\?\./, "(?:^|\.)")+"$";
return new RegExp(regexTmp);
}),
"H,aggressive":(function(pattern){
var regexTmp="^"+escapeRegExp(pattern
).replace(/\\\*/g, ".*")+"$";
return new RegExp(regexTmp);
}),
"H,regex":(function(pattern){
return new RegExp(pattern);
}),
"U,normal":(function(pattern){
//alias of H,aggressive
return this["H,aggressive"](pattern);
}),
"U,regex":(function(pattern){
//alias of H,aggressive
return this["H,regex"](pattern);
}),
}
function migrateRules(newRules, formerRules){
$.each(newRules, function(uIndex, uElement){ //updatedLoop
$.each(formerRules, function(fIndex, fElement){ //formerLoop
if(isSameRule(uElement, fElement)){
uElement["compiled"]=fElement["compiled"];
return false; //break
}
return true; //continue
});
if((typeof(uElement["compiled"])!="object")||
(typeof(uElement["compiled"].test)!="function")){
uElement["compiled"]=compilerMatrix[uElement["match"]+
","+uElement["type"]](uElement["pattern"]);
}
});
return newRules;
}
asyncSequence.push(function(next){
//console.log("storage ready");
//console.log(globalStorage);
compiledRules=$.extend(true, [], globalStorage["rules"]);
//compile rules
compiledRules.map(function(rule){
rule["compiled"]=compilerMatrix[rule["match"]+
","+rule["type"]](rule["pattern"]);
return rule;
});
//start listen to message channel
chrome.runtime.onMessage.addListener(messageSystem);
//start redirection
chrome.webRequest.onBeforeRequest.addListener(redirSystem,
{urls:["http://*/*"]}, ["blocking"]);
next(null);
});
////////////////////////////////////////////////////////////////////////////////
// REDIRECTION REDIRECTION REDIRECTION REDIRECTION REDIRECTION REDIRECTION //
// REDIRECTION REDIRECTION REDIRECTION REDIRECTION REDIRECTION //
// REDIRECTION REDIRECTION REDIRECTION REDIRECTION REDIRECTION REDIRECTION //
////////////////////////////////////////////////////////////////////////////////
var hostnameExtract=/^http\:\/\/([\-\.0-9a-z]+)(?:\:[0-9]+)?\//;
var httpsApply=/^http\:\/\//;
function redirSystem(details){
var retval = {}; //do nothing
var hostname=hostnameExtract.exec(details.url); //populate hostname
if(!!hostname)hostname=hostname[1];
//console.log(details.url);
//console.log(hostname);
$.each(compiledRules, function(eachIndex, eachRule){
if(eachRule["match"]=="H"){
if((!!hostname)&&(eachRule["compiled"].test(hostname))){
retval={"redirectUrl": details.url.replace(httpsApply, "https://")};
console.log(retval);
return false; //break
}
}else if(eachRule["match"]=="U"){
if(eachRule["compiled"].test(details.url)){
retval={"redirectUrl": details.url.replace(httpsApply, "https://")};
console.log(retval);
return false; //break
}
}
return true; //continue
});
return retval;
}
////////////////////////////////////////////////////////////////////////////////
// START START START START START START START START START START START START //
// START START START START START START START START START START START //
// START START START START START START START START START START START START //
////////////////////////////////////////////////////////////////////////////////
async.waterfall(asyncSequence);