casdoor 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/content-script.js +53 -11
package/package.json
CHANGED
package/src/content-script.js
CHANGED
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
skip: "不用了",
|
|
34
34
|
saved: "已保存到 Casdoor",
|
|
35
35
|
close: "关闭",
|
|
36
|
+
missingSelector: "管理员配置的{field}选择器“{selector}”在这个页面上没有找到,已改用自动识别",
|
|
37
|
+
usernameField: "用户名输入框",
|
|
38
|
+
passwordField: "密码输入框",
|
|
39
|
+
submitField: "登录按钮",
|
|
36
40
|
}
|
|
37
41
|
: {
|
|
38
42
|
filled: "Casdoor filled in the account {user} of {app}",
|
|
@@ -44,6 +48,10 @@
|
|
|
44
48
|
skip: "No thanks",
|
|
45
49
|
saved: "Saved to Casdoor",
|
|
46
50
|
close: "Close",
|
|
51
|
+
missingSelector: "The {field} selector \"{selector}\" set by the admin matches nothing on this page, so it was found automatically",
|
|
52
|
+
usernameField: "username input",
|
|
53
|
+
passwordField: "password input",
|
|
54
|
+
submitField: "sign-in button",
|
|
47
55
|
};
|
|
48
56
|
|
|
49
57
|
function format(text, values) {
|
|
@@ -78,19 +86,36 @@
|
|
|
78
86
|
return element.getClientRects().length > 0;
|
|
79
87
|
}
|
|
80
88
|
|
|
89
|
+
// a class attribute pasted as it is, like "el-button login-btn el-button--primary", is taken as those classes
|
|
90
|
+
function selectorCandidates(selector) {
|
|
91
|
+
const value = selector.trim();
|
|
92
|
+
const candidates = [value];
|
|
93
|
+
if (/^[\w-]+(\s+[\w-]+)*$/.test(value)) {
|
|
94
|
+
candidates.push("." + value.split(/\s+/).join("."));
|
|
95
|
+
}
|
|
96
|
+
return candidates;
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
function query(selector) {
|
|
82
|
-
if (!selector) {
|
|
100
|
+
if (!selector || !selector.trim()) {
|
|
83
101
|
return null;
|
|
84
102
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
for (const candidate of selectorCandidates(selector)) {
|
|
104
|
+
try {
|
|
105
|
+
const element = document.querySelector(candidate);
|
|
106
|
+
if (element) {
|
|
107
|
+
return element;
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
// not a valid selector, try the next way of reading it
|
|
111
|
+
}
|
|
89
112
|
}
|
|
113
|
+
return null;
|
|
90
114
|
}
|
|
91
115
|
|
|
92
116
|
const usernameHints = /user|login|account|email|mail|phone|mobile|tel|name|uid|uname|loginid|工号|账号|帳號|用户|用戶|手机|邮箱/i;
|
|
93
|
-
|
|
117
|
+
// "登录", "登录系统", "立即登录", "Sign in", ...
|
|
118
|
+
const submitHints = /^\s*(?:(?:立即|马上|安全|用户|账号)?\s*(?:登\s*录|登\s*入|登\s*陆)\s*(?:系统|平台)?|进入系统|log\s*in|log\s*on|sign\s*in|login|logon|signin|submit|确\s*定|提\s*交)\s*$/i;
|
|
94
119
|
|
|
95
120
|
function findPassword(site) {
|
|
96
121
|
const configured = query(site.passwordSelector);
|
|
@@ -136,8 +161,14 @@
|
|
|
136
161
|
return button;
|
|
137
162
|
}
|
|
138
163
|
}
|
|
139
|
-
|
|
140
|
-
|
|
164
|
+
// buttons first, so that a link or a tab with the same words loses to the real button
|
|
165
|
+
for (const selector of ["button, input[type=button], input[type=submit]", "[role=button]", "a, div[onclick], span[onclick]"]) {
|
|
166
|
+
const found = [...document.querySelectorAll(selector)].find((element) => isVisible(element) && submitHints.test(element.value || element.textContent || ""));
|
|
167
|
+
if (found) {
|
|
168
|
+
return found;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
141
172
|
}
|
|
142
173
|
|
|
143
174
|
function setValue(input, value) {
|
|
@@ -154,8 +185,11 @@
|
|
|
154
185
|
for (const type of ["keydown", "keypress", "keyup"]) {
|
|
155
186
|
input.dispatchEvent(new KeyboardEvent(type, {key: "Enter", code: "Enter", keyCode: 13, which: 13, bubbles: true}));
|
|
156
187
|
}
|
|
157
|
-
|
|
158
|
-
|
|
188
|
+
// a single-page app (Vue, React, ...) signs in from its own Enter handler, submitting its <form> would only reload
|
|
189
|
+
// the page; a server-side form says where it goes
|
|
190
|
+
const form = input.form;
|
|
191
|
+
if (form && (form.hasAttribute("action") || form.hasAttribute("method"))) {
|
|
192
|
+
form.requestSubmit();
|
|
159
193
|
}
|
|
160
194
|
}
|
|
161
195
|
|
|
@@ -187,6 +221,7 @@
|
|
|
187
221
|
title.style.cssText = "font-weight:600;font-size:12px;color:#5c6ac4;margin-bottom:4px;";
|
|
188
222
|
title.textContent = "Casdoor";
|
|
189
223
|
const body = document.createElement("div");
|
|
224
|
+
body.style.whiteSpace = "pre-line";
|
|
190
225
|
body.textContent = text;
|
|
191
226
|
box.append(title, body);
|
|
192
227
|
if (buttons.length > 0) {
|
|
@@ -239,7 +274,14 @@
|
|
|
239
274
|
showNotice(strings.retry, buttons, 0);
|
|
240
275
|
return;
|
|
241
276
|
}
|
|
242
|
-
|
|
277
|
+
// the admin's selectors that match nothing, so that a wrong one doesn't go unnoticed
|
|
278
|
+
const missing = [
|
|
279
|
+
[site.usernameSelector, strings.usernameField],
|
|
280
|
+
[site.passwordSelector, strings.passwordField],
|
|
281
|
+
[site.autoSubmit ? site.submitSelector : "", strings.submitField],
|
|
282
|
+
].filter(([selector]) => selector && selector.trim() && !query(selector));
|
|
283
|
+
const warnings = missing.map(([selector, field]) => format(strings.missingSelector, {field, selector}));
|
|
284
|
+
showNotice([format(strings.filled, {app: site.displayName, user: account.username}), ...warnings].join("\n"), buttons, warnings.length > 0 ? 15000 : 8000);
|
|
243
285
|
|
|
244
286
|
if (site.autoSubmit && !username) {
|
|
245
287
|
await sleep(400);
|