forked from web-ext-experiments/logins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.js
123 lines (106 loc) · 3.5 KB
/
api.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
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
const LoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
"nsILoginInfo", "init");
const FIELDS = {
formSubmitURL: "formSubmitURL",
origin: "hostname",
realm: "httpRealm",
username: "username",
password: "password",
usernameField: "usernameField",
passwordField: "passwordField",
};
function convert(info) {
let obj = {};
for (let field of Object.keys(FIELDS)) {
obj[field] = info[FIELDS[field]];
}
return obj;
}
function match(info, search) {
return Object.keys(search).every(field => search[field] == null || search[field] == info[FIELDS[field]]);
}
function accessible(context, origin) {
let url;
try {
url = Services.io.newURI(origin, null, null);
} catch (ex) {
dump(`new uri failed ${ex.message}\n`);
// unparseable hostname, can this actually happen?
return false;
}
if (url.scheme == "addon") {
return (url.path == context.extension.id);
} else if (url.scheme == "moz-extension") {
return (url.host == context.extension.id
|| url.host == context.extension.uuid);
} else {
return (context.extension.whiteListedHosts.matches(url));
}
}
class API extends ExtensionAPI {
getAPI(context) {
// XXX only return this for background contexts?
return {
logins: {
search(query) {
let logins = Services.logins.getAllLogins()
.filter(login => accessible(context, login.hostname))
.filter(login => match(login, query))
.map(convert);
return Promise.resolve(logins);
},
store(info) {
let origin = info.origin;
function check(field) {
if (!info[field]) {
return;
}
let uri;
try {
uri = Services.io.newURI(info[field], null, null);
} catch (err) {
return Promise.reject({message: `Cannot parse ${field} as a URL`});
}
if (origin) {
if (uri.prePath != origin) {
return Promise.reject({message: `Origin does not match ${field}`});
}
} else {
origin = uri.prePath;
}
}
check("formSubmitURL");
check("realm");
if (!origin) {
return Promise.reject({message: "Must specify origin, formSubmitURL, or realm"});
}
if (!accessible(context, origin)) {
return Promise.reject({message: `Permission denied for ${origin}`});
}
let linfo = new LoginInfo(origin, info.formSubmitURL,
info.realm, info.username, info.password,
info.usernameField, info.passwordField);
try {
Services.logins.addLogin(linfo);
} catch (err) {
return Promise.reject({message: err.message});
}
return Promise.resolve();
},
remove(query) {
try {
Services.logins.getAllLogins()
.filter(login => accessible(context, login.hostname))
.filter(login => match(login, query))
.forEach(login => { Services.logins.removeLogin(login); });
} catch (err) {
return Promise.reject({message: err.message});
}
return Promise.resolve();
},
},
};
}
}