-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c3dc956
Showing
23 changed files
with
2,191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
globals: | ||
WebDAVClient: true | ||
UserChromeESOptionsStorage: true | ||
UserScriptsInitializer: true | ||
h: true | ||
parseUserScript: true | ||
|
||
parserOptions: | ||
ecmaVersion: 2017 | ||
|
||
env: | ||
webextensions: true |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
|
||
new class Background { | ||
/** | ||
* @constant {RegExp} | ||
*/ | ||
static get ALLOWED_WEBDAV_DIRECTORY_URL_PATTERN() {return /^http:\/\/localhost(?::[0-9]+)?\/([^?#]+\/)?$/;} | ||
|
||
constructor() | ||
{ | ||
this.watchWebDAVDirectorySettingChanged(); | ||
|
||
console.group('userChromeES'); | ||
this.initialize() | ||
.then(console.groupEnd) | ||
.catch(function (exception) { | ||
setTimeout(console.groupEnd, 1); | ||
throw exception; | ||
}) | ||
.then(() => UserScriptsInitializer.executeScripts(window)); | ||
} | ||
|
||
/** | ||
* @access private | ||
* @returns {Promise.<void>} | ||
*/ | ||
async initialize() | ||
{ | ||
const directory = (await UserChromeESOptionsStorage.getOptionsFromStorage()).directory; | ||
|
||
if (directory) { | ||
console.info(`${directory} からスクリプトを取得します。`); | ||
await new UserScriptsInitializer().loadScripts(await this.getScriptFileURLs(directory)); | ||
} else { | ||
console.warn('WebDAVディレクトリのURLを設定する必要があります。'); | ||
} | ||
} | ||
|
||
/** | ||
* @access private | ||
* @param {string} directory | ||
* @returns {Promise.<string[]>} | ||
*/ | ||
async getScriptFileURLs(directory) | ||
{ | ||
return (await WebDAVClient.index(directory)).filter(fileURL => /\.uc\.(?:es|js)$/.test(fileURL)); | ||
} | ||
|
||
/** | ||
* @access private | ||
*/ | ||
watchWebDAVDirectorySettingChanged(directory) | ||
{ | ||
UserChromeESOptionsStorage.getOptionsFromStorage().then(function (options) { | ||
if (options.webDAVDirectorySettingChangedIllegally) { | ||
browser.notifications.create('', { | ||
type: 'basic', | ||
title: 'userChromeES', | ||
message: 'WebDAVディレクトリのURLが、ユーザースクリプトにって不正な値に変更されたため、設定を削除し、userChromeESを再起動しました。', | ||
}); | ||
UserChromeESOptionsStorage.setOptionsToStorage({webDAVDirectorySettingChangedIllegally: false}); | ||
} | ||
}); | ||
|
||
browser.storage.onChanged.addListener(function (changes, areaName) { | ||
if (areaName === 'local') { | ||
const userChromeESOptionsStorageChnage = changes['user-chrome-es']; | ||
if (userChromeESOptionsStorageChnage) { | ||
const newDirectory = userChromeESOptionsStorageChnage.newValue.directory; | ||
if (newDirectory) { | ||
console.group('userChromeES'); | ||
if (Background.ALLOWED_WEBDAV_DIRECTORY_URL_PATTERN.test(newDirectory)) { | ||
console.info(`WebDAVディレクトリのURLが ${newDirectory} に変更されました。`); | ||
console.groupEnd(); | ||
} else { | ||
console.error(`WebDAVディレクトリのURLが、ユーザースクリプトにって不正な値 ${newDirectory} に変更されました。` | ||
+ '設定を削除し、userChromeESを再起動します。'); | ||
console.groupEnd(); | ||
browser.storage.local.set({'user-chrome-es': { | ||
directory: '', | ||
webDAVDirectorySettingChangedIllegally: true, | ||
}}).then(() => browser.runtime.reload()); | ||
} | ||
} | ||
} | ||
|
||
} | ||
}); | ||
} | ||
}(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE html> | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<title>userChromeES</title> | ||
</head> | ||
<body> | ||
<script src="/third-party/parse-meta-line.js"></script> | ||
<script src="/third-party/parse-user-script.js"></script> | ||
<script src="/options/user-chrome-es-options-storage.es"></script> | ||
<script src="webdav-client.es"></script> | ||
<script src="user-scripts-initializer.es"></script> | ||
<script src="background.es"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
|
||
window.UserScriptsInitializer = class { | ||
/** | ||
* @constant {string[]} | ||
*/ | ||
static get VALID_INCLUDE_KEY_VALUES() {return ['background', 'popup', 'options', 'devtools', 'sidebar'];} | ||
|
||
static executeScripts(win) | ||
{ | ||
win.document.body | ||
.append(UserScriptsInitializer.scripts[/^\/(.+)\/\1\.xhtml$/.exec(win.location.pathname)[1]]); | ||
} | ||
|
||
/** | ||
* @param {string[]} scriptFileURLs | ||
* @returns {Promise.<void>} | ||
*/ | ||
async loadScripts(scriptFileURLs) | ||
{ | ||
const table = {}; | ||
|
||
for (const url of scriptFileURLs) { | ||
const file = await this.getScriptFile(url); | ||
|
||
const metaData = await this.getMetaData(file); | ||
if (!this.validateMetaData(metaData, url)) { | ||
continue; | ||
} | ||
|
||
for (const value of metaData.includes) { | ||
UserScriptsInitializer.scripts[value].append(this.createScriptElement(file)); | ||
} | ||
|
||
const fileName = /[^/]*$/.exec(url)[0]; | ||
|
||
UserScriptsInitializer.scriptsInfomation.push({ | ||
name: metaData.name || fileName, | ||
url: url, | ||
}); | ||
|
||
table[fileName] = { | ||
'@name': metaData.name || null, | ||
'@description': metaData.description || null, | ||
'@include': metaData.includes.join('" "'), | ||
}; | ||
} | ||
|
||
if (Object.keys(table).length > 0) { | ||
console.table(table); | ||
console.info('以上のスクリプトを読み込みました。'); | ||
} else { | ||
console.info('スクリプトは一つも読み込まれていません。'); | ||
} | ||
} | ||
|
||
/** | ||
* @access private | ||
* @param {Blob} file | ||
* @returns {HTMLScriptElement} | ||
*/ | ||
createScriptElement(file) | ||
{ | ||
const script = document.createElement('script'); | ||
script.src = URL.createObjectURL(file); | ||
return script; | ||
} | ||
|
||
/** | ||
* @access private | ||
* @param {?Object} metaData | ||
* @param {string} url | ||
* @returns {boolean} | ||
*/ | ||
validateMetaData(metaData, url) | ||
{ | ||
if (!metaData) { | ||
console.error(`メタデータが含まれていないため、 ${url} を無視します。`); | ||
return false; | ||
} | ||
|
||
if (metaData.includes.length === 0) { | ||
console.error( | ||
`妥当な %c@include%c キーが含まれていないため、 ${url} を無視します。`, | ||
'color: black; background: rgba(255, 255, 255, 0.5); margin: 0 0.3em; padding: 0.1em 0.3em;', | ||
'' | ||
); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @access private | ||
* @see [greasemonkey/parse-user-script.js at master · greasemonkey/greasemonkey]{@link https://github.com/greasemonkey/greasemonkey/blob/master/src/parse-user-script.js} | ||
* @param {Blob} file | ||
* @returns {Promise.<Object>} | ||
*/ | ||
async getMetaData(file) | ||
{ | ||
const metaData = parseUserScript(await new Response(file).text(), 'https://dummy.invalid/', true); | ||
if (metaData) { | ||
metaData.includes | ||
= UserScriptsInitializer.VALID_INCLUDE_KEY_VALUES.filter(value => metaData.includes.includes(value)); | ||
} | ||
return metaData; | ||
} | ||
|
||
/** | ||
* @access private | ||
* @param {string} url | ||
* @returns {Promise.<Blob>} | ||
*/ | ||
async getScriptFile(url) | ||
{ | ||
const response = await fetch(url); | ||
|
||
if (response.status === 200) { | ||
return response.blob(); | ||
} | ||
|
||
return Promise.reject(new Error(`次のスクリプトの取得に失敗しました。\n${url}\n\n${await response.text()}`)); | ||
} | ||
}; | ||
|
||
/** | ||
* @type {Array.<Object.<string>>} | ||
*/ | ||
UserScriptsInitializer.scriptsInfomation = []; | ||
|
||
/** | ||
* @access private | ||
* @type {Object.<DocumentFragment>} | ||
*/ | ||
UserScriptsInitializer.scripts = {}; | ||
for (const value of UserScriptsInitializer.VALID_INCLUDE_KEY_VALUES) { | ||
UserScriptsInitializer.scripts[value] = new DocumentFragment(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
class WebDAVClient | ||
{ | ||
/** | ||
* Gets child file URLs from the specified directory URL. | ||
* @param {string} directory | ||
* @returns {Promise.<string[]>} | ||
*/ | ||
static async index(directory) | ||
{ | ||
const response = await fetch(directory, { | ||
method: 'PROPFIND', | ||
headers: {depth: '1'}, | ||
body: `<?xml version="1.0" encoding="utf-8" ?> | ||
<propfind xmlns="DAV:"> | ||
<prop /> | ||
</propfind>`, | ||
}); | ||
|
||
const responseText = await response.text(); | ||
|
||
if (response.status === 207) { | ||
const responses = new DOMParser().parseFromString(responseText, 'application/xml') | ||
.getElementsByTagNameNS('DAV:', 'response'); | ||
|
||
if (responses.length > 0) { | ||
const fileURLs = []; | ||
for (const response of Array.from(responses)) { | ||
const url = response.getElementsByTagNameNS('DAV:', 'href')[0].textContent; | ||
if (!url.endsWith('/')) { | ||
fileURLs.push(new URL(url, directory).href); | ||
} | ||
} | ||
return fileURLs; | ||
} | ||
} | ||
|
||
return Promise.reject(new Error(`ファイル一覧の取得に失敗しました。\n\n${responseText}`)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
browser.runtime.getBackgroundPage().then(win => win.UserScriptsInitializer.executeScripts(window)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE html> | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<title>userChromeES</title> | ||
</head> | ||
<body> | ||
<script src="devtools.es"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
{ | ||
"manifest_version": 2, | ||
"name": "userChromeES", | ||
"description": "uc / userChromeJS+サブスクリプトローダ 風に、ローカルに立てたWebDAVサーバーを介し、WebExtension APIを叩くユーザースクリプトを読み込みます。", | ||
"version": "0.1.1", | ||
"applications": { | ||
"gecko": { | ||
"id": "[email protected]" | ||
} | ||
}, | ||
|
||
"permissions": [ | ||
"http://localhost/*", | ||
|
||
"alarms", | ||
"background", | ||
"browserSettings", | ||
"browsingData", | ||
"contextMenus", | ||
"contentSettings", | ||
"contextualIdentities", | ||
"debugger", | ||
"downloads", | ||
"downloads.open", | ||
"find", | ||
"identity", | ||
"management", | ||
"menus", | ||
"nativeMessaging", | ||
"notifications", | ||
"pageCapture", | ||
"privacy", | ||
"proxy", | ||
"sessions", | ||
"storage", | ||
"theme", | ||
|
||
"unlimitedStorage" | ||
], | ||
"optional_permissions": [ | ||
"<all_urls>", | ||
|
||
"bookmarks", | ||
"cookies", | ||
"geolocation", | ||
"history", | ||
"idle", | ||
"tabs", | ||
"topSites", | ||
"webNavigation", | ||
"webRequest", | ||
"webRequestBlocking", | ||
|
||
"clipboardWrite", | ||
"clipboardRead" | ||
], | ||
"content_security_policy": "script-src 'self' blob:; object-src 'self' blob:", | ||
|
||
"background": { | ||
"page": "background/background.xhtml" | ||
}, | ||
"browser_action": { | ||
"browser_style": true, | ||
"default_popup": "popup/popup.xhtml" | ||
}, | ||
"options_ui": { | ||
"browser_style": true, | ||
"page": "options/options.xhtml" | ||
}, | ||
"devtools_page": "devtools/devtools.xhtml", | ||
"sidebar_action": { | ||
"browser_style": true, | ||
"default_panel": "sidebar/sidebar.xhtml" | ||
}, | ||
|
||
"author": "100の人", | ||
"homepage_url": "https://addons.mozilla.org/firefox/addon/user-chrome-es/" | ||
} |
Oops, something went wrong.