diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000..31354ec --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..a31ede1 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/bin/sh +. "$(dirname $0)/_/husky.sh" + +npm run format +git add -A diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..bac5ad4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +# Some prettier-specific files so it doesn't die. +**/*.png +**/*.ico +LICENSE +.gitignore + +node_modules +out/ +dist +ts-out/ +ts-out \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c7a71d6..fed925e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,13 @@ { "name": "ArmCord", - "version": "3.0.4", + "version": "3.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ArmCord", - "version": "3.0.4", + "version": "3.1.0", + "hasInstallScript": true, "license": "OSL-3.0", "dependencies": { "electron-context-menu": "^3.1.2", @@ -21,6 +22,8 @@ "copyfiles": "^2.4.1", "electron": "^17.1.0", "electron-builder": "^22.14.13", + "husky": "^7.0.4", + "prettier": "^2.5.1", "typescript": "^4.5.4" } }, @@ -2020,6 +2023,21 @@ "node": ">= 6" } }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -2724,6 +2742,18 @@ "node": ">=4" } }, + "node_modules/prettier": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5191,6 +5221,12 @@ "debug": "4" } }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, "iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -5728,6 +5764,12 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "prettier": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 3a4808d..3b616e9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "build": "tsc && copyfiles -u 1 src/**/*.html src/**/**/*.css ts-out/ && copyfiles package.json ts-out/ && copyfiles assets/** ts-out/", "watch": "tsc -w", "start": "npm run build && electron ./ts-out/main.js", - "package": "npm run build && electron-builder" + "package": "npm run build && electron-builder", + "format": "prettier --write **/*", + "postinstall": "husky install" }, "repository": { "type": "git", @@ -25,6 +27,8 @@ "copyfiles": "^2.4.1", "electron": "^17.1.0", "electron-builder": "^22.14.13", + "husky": "^7.0.4", + "prettier": "^2.5.1", "typescript": "^4.5.4" }, "dependencies": { diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..d8902c1 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,14 @@ +module.exports = { + printWidth: 120, + tabWidth: 4, + useTabs: false, + semi: true, + singleQuote: false, + quoteProps: "as-needed", + jsxSingleQuote: false, + trailingComma: "none", + bracketSpacing: false, + jsxBracketSameLine: false, + arrowParens: "always", + endOfLine: "auto" +}; diff --git a/src/content/css/discord.css b/src/content/css/discord.css index 4e29030..1b49a8b 100644 --- a/src/content/css/discord.css +++ b/src/content/css/discord.css @@ -1,12 +1,12 @@ .info-3pQQBb:last-child:before { - content: "ArmCord Version: 3.1.0"!important; - height: auto; - line-height: 16px; - text-align: center; - color: var(--text-muted); - font-size: 12px; - text-transform: none; + content: "ArmCord Version: 3.1.0" !important; + height: auto; + line-height: 16px; + text-align: center; + color: var(--text-muted); + font-size: 12px; + text-transform: none; } .notice-2HEN-u { display: none; -} \ No newline at end of file +} diff --git a/src/content/css/setup.css b/src/content/css/setup.css index b138257..d848205 100644 --- a/src/content/css/setup.css +++ b/src/content/css/setup.css @@ -2,68 +2,68 @@ @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); :root { - background-color: #2c2f33 !important; - --header-secondary: #b9bbbe !important; - --header-primary: #fff !important; - --background-tertiary: #202225 !important; + background-color: #2c2f33 !important; + --header-secondary: #b9bbbe !important; + --header-primary: #fff !important; + --background-tertiary: #202225 !important; } body { - background-color: #2c2f33; - color: white; + background-color: #2c2f33; + color: white; } p { - color: white; - text-align: center; - font-weight: 100; - font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; - text-rendering: optimizeLegibility; + color: white; + text-align: center; + font-weight: 100; + font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; + text-rendering: optimizeLegibility; } .logo { - font-size: 0px; - text-align: center; - transform: translateY(-105%); + font-size: 0px; + text-align: center; + transform: translateY(-105%); } .logo:before { - content: "ARM"; - color: #7289da; - font-weight: normal; - font-family: Helvetica, sans-serif; - font-size: 32px; + content: "ARM"; + color: #7289da; + font-weight: normal; + font-family: Helvetica, sans-serif; + font-size: 32px; } .logo:after { - content: "Cord"; - color: #ffffff; - font-weight: normal; - font-family: Discordinated; - font-size: 32px; + content: "Cord"; + color: #ffffff; + font-weight: normal; + font-family: Discordinated; + font-size: 32px; } span { - text-align: center; + text-align: center; } .logo { - display: block; - margin-left: auto; - margin-right: auto; - max-height: 204px; - max-width: 204px; - transform: translateY(5%); + display: block; + margin-left: auto; + margin-right: auto; + max-height: 204px; + max-width: 204px; + transform: translateY(5%); } .container { - position: fixed; - top: 50%; - left: 50%; - color: #fff; - transform: translate(-50%, -50%); + position: fixed; + top: 50%; + left: 50%; + color: #fff; + transform: translate(-50%, -50%); } button#express { - margin-right: 84px; + margin-right: 84px; } button { background-color: #7289da; @@ -72,13 +72,13 @@ button { padding: 4px; border-radius: 5px; margin-top: 5px; - + text-align: center; border-style: none; outline: none; } .setup-ask { - font-size: 20px; + font-size: 20px; } button:hover { background-color: #687dc6; @@ -87,25 +87,25 @@ button:hover { cursor: pointer; } select { - -webkit-appearance: button; - -moz-appearance: button; - -webkit-padding-end: 20px; - -moz-padding-end: 20px; - -webkit-padding-start: 2px; - -moz-padding-start: 2px; - background-color: #2c2f33; - background-position: center right; - background-repeat: no-repeat; - border: 1px solid #aaa; - border-radius: 2px; - box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); - color: #fff; - font-size: inherit; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + -webkit-appearance: button; + -moz-appearance: button; + -webkit-padding-end: 20px; + -moz-padding-end: 20px; + -webkit-padding-start: 2px; + -moz-padding-start: 2px; + background-color: #2c2f33; + background-position: center right; + background-repeat: no-repeat; + border: 1px solid #aaa; + border-radius: 2px; + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); + color: #fff; + font-size: inherit; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .center { - text-align: center; -} \ No newline at end of file + text-align: center; +} diff --git a/src/content/css/splash.css b/src/content/css/splash.css index 710813e..88af543 100644 --- a/src/content/css/splash.css +++ b/src/content/css/splash.css @@ -20,95 +20,95 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ :root { - --background-primary: #282b30; - --background-secondary: rgba(255, 255, 255, 0.1); - --brand-experiment: #5865f2; - --header-primary: #fff; - --text-muted: #72767d; + --background-primary: #282b30; + --background-secondary: rgba(255, 255, 255, 0.1); + --brand-experiment: #5865f2; + --header-primary: #fff; + --text-muted: #72767d; } @font-face { - font-family: Whitney; - font-weight: 400; - font-style: normal; - src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); + font-family: Whitney; + font-weight: 400; + font-style: normal; + src: url(https://armcord.smartfridge.space/whitney_400.woff) format("woff"); } html, body { - -webkit-app-region: drag; - overflow: hidden; + -webkit-app-region: drag; + overflow: hidden; - margin: 0; - padding: 0; - width: 100%; - height: 100%; + margin: 0; + padding: 0; + width: 100%; + height: 100%; - background: var(--background-primary); + background: var(--background-primary); - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } * { - font-family: "Whitney", sans-serif; + font-family: "Whitney", sans-serif; - box-sizing: border-box; - -webkit-user-select: none; - cursor: default; + box-sizing: border-box; + -webkit-user-select: none; + cursor: default; } video { - width: 200px; - height: 150px; - object-fit: cover; + width: 200px; + height: 150px; + object-fit: cover; } #text-splashscreen { - font-size: 7vw; - text-align: center; + font-size: 7vw; + text-align: center; - color: var(--header-primary); - font-weight: 400; - font-style: italic; - font-size: 16px; + color: var(--header-primary); + font-weight: 400; + font-style: italic; + font-size: 16px; - text-transform: uppercase; + text-transform: uppercase; - width: 100%; + width: 100%; } #bar-container, #bar-fill { - width: 180px; - height: 8px; + width: 180px; + height: 8px; - border-radius: 4px; + border-radius: 4px; - visibility: hidden; + visibility: hidden; } #bar-container { - background-color: var(--background-secondary); + background-color: var(--background-secondary); - position: relative; - margin-top: 12px; + position: relative; + margin-top: 12px; } #bar-fill { - background-color: var(--brand-experiment); - width: 0; + background-color: var(--brand-experiment); + width: 0; } #debug { - position: absolute; - bottom: 6px; - right: 6px; + position: absolute; + bottom: 6px; + right: 6px; - text-align: right; - font-size: 10px; - color: var(--text-muted); - white-space: pre; + text-align: right; + font-size: 10px; + color: var(--text-muted); + white-space: pre; } diff --git a/src/content/css/tabs.css b/src/content/css/tabs.css index 5813278..fe88f80 100644 --- a/src/content/css/tabs.css +++ b/src/content/css/tabs.css @@ -1,53 +1,53 @@ @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); :root { - --window-buttons: var(--header-secondary); - --cord-color: var(--header-primary); - --armcord-color: #7289da; - --titlebar-color: var(--background-tertiary); + --window-buttons: var(--header-secondary); + --cord-color: var(--header-primary); + --armcord-color: #7289da; + --titlebar-color: var(--background-tertiary); } .tabs { - display: block; - top: 0; - left: 0; - right: 0; - flex-shrink: 0; - overflow: hidden; - zoom: 1; - box-sizing: border-box; - width: 100%; - clear: both; - height: 30px; - line-height: 30px; - background-color: #202225; - -webkit-app-region: drag; - width: 100%; - user-select: none; - -webkit-user-select: none; - position: fixed; - z-index: 99999; + display: block; + top: 0; + left: 0; + right: 0; + flex-shrink: 0; + overflow: hidden; + zoom: 1; + box-sizing: border-box; + width: 100%; + clear: both; + height: 30px; + line-height: 30px; + background-color: #202225; + -webkit-app-region: drag; + width: 100%; + user-select: none; + -webkit-user-select: none; + position: fixed; + z-index: 99999; } .tabs #tabs-controls-container { - float: left; - width: 150px; - height: 100%; - line-height: 30px; - background-color: #202225; - -webkit-app-region: no-drag; + float: left; + width: 150px; + height: 100%; + line-height: 30px; + background-color: #202225; + -webkit-app-region: no-drag; } .tabs-buttons { - color: white; - background-color: inherit; - float: left; - border: none; - outline: none; - cursor: pointer; - transition: 0.3s; - font-size: 20px; + color: white; + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + transition: 0.3s; + font-size: 20px; } .tabs-buttons:hover { - background-color: #4e515a; + background-color: #4e515a; } .withFrame-haYltI { - height: 30px !important; + height: 30px !important; } diff --git a/src/content/css/titlebar.css b/src/content/css/titlebar.css index 6060d56..d29f54f 100644 --- a/src/content/css/titlebar.css +++ b/src/content/css/titlebar.css @@ -1,108 +1,108 @@ @import url("https://armcord.smartfridge.space/logofont.css"); :root { - --window-buttons: var(--header-secondary); - --cord-color: var(--header-primary); - --armcord-color: #7289da; - --titlebar-color: var(--background-tertiary); + --window-buttons: var(--header-secondary); + --cord-color: var(--header-primary); + --armcord-color: #7289da; + --titlebar-color: var(--background-tertiary); } .titlebar { - display: block; - top: 0; - left: 0; - right: 0; - flex-shrink: 0; - overflow: hidden; - zoom: 1; - box-sizing: border-box; - width: 100%; - clear: both; - height: 30px; - line-height: 30px; - background-color: #202225; - -webkit-app-region: drag; - width: 100%; - user-select: none; - -webkit-user-select: none; - position: fixed; - z-index: 99999; + display: block; + top: 0; + left: 0; + right: 0; + flex-shrink: 0; + overflow: hidden; + zoom: 1; + box-sizing: border-box; + width: 100%; + clear: both; + height: 30px; + line-height: 30px; + background-color: #202225; + -webkit-app-region: drag; + width: 100%; + user-select: none; + -webkit-user-select: none; + position: fixed; + z-index: 99999; } .titlebar #window-title { - width: 30%; - height: 100%; - line-height: 30px; - float: left; - padding: 0 0 0 1em; + width: 30%; + height: 100%; + line-height: 30px; + float: left; + padding: 0 0 0 1em; } .titlebar #window-controls-container { - float: right; - width: 150px; - height: 100%; - line-height: 30px; - background-color: #202225; - -webkit-app-region: no-drag; + float: right; + width: 150px; + height: 100%; + line-height: 30px; + background-color: #202225; + -webkit-app-region: no-drag; } .titlebar #window-controls-container #minimize, .titlebar #window-controls-container #maximize, .titlebar #window-controls-container #quit { - float: left; - height: 100%; - width: 33%; - text-align: center; - color: #f7f7f7; - cursor: default; + float: left; + height: 100%; + width: 33%; + text-align: center; + color: #f7f7f7; + cursor: default; } .titlebar #window-controls-container #minimize:hover { - background-color: #99aab5; + background-color: #99aab5; } .titlebar #window-controls-container #maximize:hover { - background-color: #99aab5; + background-color: #99aab5; } .titlebar #window-controls-container #quit:hover { - background-color: #f04747; + background-color: #f04747; } .titlebar #window-controls-container #quit { - background-color: #f7f7f7; - -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; - mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; + background-color: #f7f7f7; + -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; + mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.279 5.5L11 10.221l-.779.779L5.5 6.279.779 11 0 10.221 4.721 5.5 0 .779.779 0 5.5 4.721 10.221 0 11 .779 6.279 5.5z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; } .titlebar #window-controls-container #minimize { - background-color: #f7f7f7; - -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; - mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; + background-color: #f7f7f7; + -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; + mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 4.399V5.5H0V4.399h11z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; } .titlebar #window-controls-container #maximize { - background-color: #f7f7f7; - -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; - mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") - no-repeat 50% 50%; + background-color: #f7f7f7; + -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; + mask: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='11' viewBox='0 0 11 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 0v11H0V0h11zM9.899 1.101H1.1V9.9h8.8V1.1z' fill='%23000'/%3E%3C/svg%3E") + no-repeat 50% 50%; } .window-title:after { - content: "Cord"; - color: var(--cord-color) !important; - font-weight: normal; - font-size: 14px; - font-family: Discordinated; + content: "Cord"; + color: var(--cord-color) !important; + font-weight: normal; + font-size: 14px; + font-family: Discordinated; } .window-title:before { - content: "ARM"; - color: var(--armcord-color); - font-weight: normal; - font-size: 14px; - font-family: Helvetica, sans-serif; + content: "ARM"; + color: var(--armcord-color); + font-weight: normal; + font-size: 14px; + font-family: Helvetica, sans-serif; } .window-title { - font-size: 0px !important; - margin-left: initial !important; - transform: translate(10px, 0px); + font-size: 0px !important; + margin-left: initial !important; + transform: translate(10px, 0px); } .withFrame-haYltI { - height: 30px !important; + height: 30px !important; } diff --git a/src/content/setup.html b/src/content/setup.html index ecc47f4..cdca768 100644 --- a/src/content/setup.html +++ b/src/content/setup.html @@ -1,64 +1,60 @@ - - - - ArmCord Setup - - + + + + ArmCord Setup + + - -
-

-
-

Select what kind of setup you want to perform:

- - -
-
- - + document.getElementById("next").addEventListener("click", function () { + var mod = document.getElementById("mod").value; + window.armcordinternal.saveSettings({ + windowStyle: "default", + channel: branch, + armcordCSP: true, + minimizeToTray: true, + automaticPatches: false, + mods: mod, + blurType: "acrylic" + }); + fade(document.getElementById("setup")); + setTimeout(function () { + window.armcordinternal.restart(); + }, 5000); + }); + } else { + window.armcordinternal.saveSettings({ + windowStyle: "default", + channel: branch, + armcordCSP: true, + minimizeToTray: true, + automaticPatches: false, + mods: "none", + blurType: "acrylic" + }); + fade(document.getElementById("setup")); + setTimeout(function () { + window.armcordinternal.restart(); + }, 5000); + } + }); + }); + } + + diff --git a/src/content/splash.html b/src/content/splash.html index ba0327d..5d6f18c 100644 --- a/src/content/splash.html +++ b/src/content/splash.html @@ -1,68 +1,63 @@ - - - ArmCord - - + + + ArmCord + + - -
- -

-
- - + +
+ +

+
+ + diff --git a/src/extensions/mods.ts b/src/extensions/mods.ts index 6dfc5d6..4872cfb 100644 --- a/src/extensions/mods.ts +++ b/src/extensions/mods.ts @@ -11,59 +11,55 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI import electron from "electron"; import * as storage from "electron-json-storage"; const otherMods = { - generic: { - electronProxy: require("util").types.isProxy(electron), // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord) - }, + generic: { + electronProxy: require("util").types.isProxy(electron) // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord) + } }; const unstrictCSP = () => { - console.log("Setting up CSP unstricter..."); + console.log("Setting up CSP unstricter..."); - const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; + const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; - const corsAllowUrls = [ - "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js", - "https://github-releases.githubusercontent.com/", - "https://api.goosemod.com/inject.js", - "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", - "https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js", - "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js", - ]; + const corsAllowUrls = [ + "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js", + "https://github-releases.githubusercontent.com/", + "https://api.goosemod.com/inject.js", + "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js", + "https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js", + "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js" + ]; - electron.session.defaultSession.webRequest.onHeadersReceived( - ({ responseHeaders, url }, done) => { - let csp = responseHeaders!["content-security-policy"]; + electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => { + let csp = responseHeaders!["content-security-policy"]; - if (otherMods.generic.electronProxy) { - // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods - delete responseHeaders!["content-security-policy"]; - csp = []; - } - - if (csp) { - for (let p of cspAllowAll) { - csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs + if (otherMods.generic.electronProxy) { + // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods + delete responseHeaders!["content-security-policy"]; + csp = []; } - // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?) - csp[0] = csp[0].replace(/'nonce-.*?' /, ""); - } + if (csp) { + for (let p of cspAllowAll) { + csp[0] = csp[0].replace(`${p}`, `${p} * blob: data:`); // * does not include data: URIs + } - if (corsAllowUrls.some((x) => url.startsWith(x))) { - responseHeaders!["access-control-allow-origin"] = ["*"]; - } + // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?) + csp[0] = csp[0].replace(/'nonce-.*?' /, ""); + } - done({ responseHeaders }); - } - ); + if (corsAllowUrls.some((x) => url.startsWith(x))) { + responseHeaders!["access-control-allow-origin"] = ["*"]; + } + + done({responseHeaders}); + }); }; storage.get("settings", function (error, data: any) { - if (error) throw error; - if (data.armcordCSP) { - unstrictCSP(); - } else { - console.log( - "ArmCord CSP is disabled. The CSP should be managed by third-party plugin." - ); - } + if (error) throw error; + if (data.armcordCSP) { + unstrictCSP(); + } else { + console.log("ArmCord CSP is disabled. The CSP should be managed by third-party plugin."); + } }); diff --git a/src/extensions/plugin.ts b/src/extensions/plugin.ts index 18d85f2..cb1a064 100644 --- a/src/extensions/plugin.ts +++ b/src/extensions/plugin.ts @@ -1,26 +1,20 @@ -import * as fs from 'fs'; -import { app, session } from 'electron'; +import * as fs from "fs"; +import {app, session} from "electron"; const userDataPath = app.getPath("userData"); const pluginFolder = userDataPath + "/plugins/"; if (!fs.existsSync(pluginFolder)) { fs.mkdirSync(pluginFolder); console.log("Created missing plugin folder"); - } +} app.whenReady().then(() => { - fs.readdirSync(pluginFolder).forEach((file) => { - try { - const manifest = fs.readFileSync( - `${userDataPath}/plugins/${file}/manifest.json`, - "utf8" - ); - var pluginFile = JSON.parse(manifest); - session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); - console.log( - `%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, - "color:red" - ); - } catch (err) { - console.error(err); - } - }); + fs.readdirSync(pluginFolder).forEach((file) => { + try { + const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8"); + var pluginFile = JSON.parse(manifest); + session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); + console.log(`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, "color:red"); + } catch (err) { + console.error(err); + } + }); }); diff --git a/src/ipc.ts b/src/ipc.ts index 5b50bec..f5cbcc2 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -1,83 +1,81 @@ //ipc stuff -import { app, ipcMain, shell, desktopCapturer } from "electron"; -import { createTabsGuest, mainWindow } from "./window"; -import { saveSettings, getVersion } from "./utils"; -import { settings, customTitlebar, tabs } from "./main"; -import { createSettingsWindow } from "./settings/main"; +import {app, ipcMain, shell, desktopCapturer} from "electron"; +import {createTabsGuest, mainWindow} from "./window"; +import {saveSettings, getVersion} from "./utils"; +import {settings, customTitlebar, tabs} from "./main"; +import {createSettingsWindow} from "./settings/main"; export function registerIpc() { - ipcMain.on("get-app-path", (event, arg) => { - event.reply("app-path", app.getAppPath()); - }); - ipcMain.on("openTab", (event, number: number) => { - createTabsGuest(number); - }); - ipcMain.on("open-external-link", (event, href: string) => { - shell.openExternal(href); - }); - ipcMain.on("win-maximize", (event, arg) => { - mainWindow.maximize(); - }); - ipcMain.on("win-isMaximized", (event, arg) => { - event.returnValue = mainWindow.isMaximized(); - }); - ipcMain.on("win-minimize", (event, arg) => { - mainWindow.minimize(); - }); - ipcMain.on("win-unmaximize", (event, arg) => { - mainWindow.unmaximize(); - }); - ipcMain.on("win-show", (event, arg) => { - mainWindow.show(); - }); - ipcMain.on("win-hide", (event, arg) => { - mainWindow.hide(); - }); - ipcMain.on("win-quit", (event, arg) => { - app.exit(); - }); - ipcMain.on("get-app-version", (event) => { - event.returnValue = getVersion(); - }); - ipcMain.on("splashEnd", (event, arg) => { - mainWindow.setSize(800, 600); - }); - ipcMain.on("restart", (event, arg) => { - app.relaunch(); - app.exit(); - }); - ipcMain.on("saveSettings", (event, args) => { - saveSettings(args); - }); - ipcMain.on("minimizeToTray", (event) => { - console.log(settings.minimizeToTray); - event.returnValue = settings.minimizeToTray; - }); - ipcMain.on("channel", (event) => { - event.returnValue = settings.channel; - }); - ipcMain.on("clientmod", (event, arg) => { - event.returnValue = settings.mods; - }); - ipcMain.on("titlebar", (event, arg) => { - event.returnValue = customTitlebar; - }); - ipcMain.on("tabs", (event, arg) => { - event.returnValue = tabs; - }); - ipcMain.on("shouldPatch", (event, arg) => { - event.returnValue = settings.automaticPatches; - }); - ipcMain.on("openSettingsWindow", (event, arg) => { - createSettingsWindow(); - }); - ipcMain.on("setting-armcordCSP", (event) => { - if (settings.armcordCSP) { - event.returnValue = true; - } else { - event.returnValue = false; - } - }); - ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => - desktopCapturer.getSources(opts) - ); + ipcMain.on("get-app-path", (event, arg) => { + event.reply("app-path", app.getAppPath()); + }); + ipcMain.on("openTab", (event, number: number) => { + createTabsGuest(number); + }); + ipcMain.on("open-external-link", (event, href: string) => { + shell.openExternal(href); + }); + ipcMain.on("win-maximize", (event, arg) => { + mainWindow.maximize(); + }); + ipcMain.on("win-isMaximized", (event, arg) => { + event.returnValue = mainWindow.isMaximized(); + }); + ipcMain.on("win-minimize", (event, arg) => { + mainWindow.minimize(); + }); + ipcMain.on("win-unmaximize", (event, arg) => { + mainWindow.unmaximize(); + }); + ipcMain.on("win-show", (event, arg) => { + mainWindow.show(); + }); + ipcMain.on("win-hide", (event, arg) => { + mainWindow.hide(); + }); + ipcMain.on("win-quit", (event, arg) => { + app.exit(); + }); + ipcMain.on("get-app-version", (event) => { + event.returnValue = getVersion(); + }); + ipcMain.on("splashEnd", (event, arg) => { + mainWindow.setSize(800, 600); + }); + ipcMain.on("restart", (event, arg) => { + app.relaunch(); + app.exit(); + }); + ipcMain.on("saveSettings", (event, args) => { + saveSettings(args); + }); + ipcMain.on("minimizeToTray", (event) => { + console.log(settings.minimizeToTray); + event.returnValue = settings.minimizeToTray; + }); + ipcMain.on("channel", (event) => { + event.returnValue = settings.channel; + }); + ipcMain.on("clientmod", (event, arg) => { + event.returnValue = settings.mods; + }); + ipcMain.on("titlebar", (event, arg) => { + event.returnValue = customTitlebar; + }); + ipcMain.on("tabs", (event, arg) => { + event.returnValue = tabs; + }); + ipcMain.on("shouldPatch", (event, arg) => { + event.returnValue = settings.automaticPatches; + }); + ipcMain.on("openSettingsWindow", (event, arg) => { + createSettingsWindow(); + }); + ipcMain.on("setting-armcordCSP", (event) => { + if (settings.armcordCSP) { + event.returnValue = true; + } else { + event.returnValue = false; + } + }); + ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => desktopCapturer.getSources(opts)); } diff --git a/src/main.ts b/src/main.ts index bb9893e..3970428 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,114 +1,108 @@ // Modules to control application life and create native browser window -import { - app, - BrowserWindow, - session, -} from "electron"; +import {app, BrowserWindow, session} from "electron"; import * as path from "path"; import "v8-compile-cache"; import * as storage from "electron-json-storage"; -import { getConfigUnsafe, setup } from "./utils"; +import {getConfigUnsafe, setup} from "./utils"; import "./extensions/mods"; import "./extensions/plugin"; import "./tray"; -import { mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost } from "./window"; +import {mainWindow, createCustomWindow, createNativeWindow, createGlasstronWindow, createTabsHost} from "./window"; import "./shortcuts"; export var contentPath: string; var channel: string; export var settings: any; export var customTitlebar: boolean; export var tabs: boolean; -async function appendSwitch(){ - if (await getConfigUnsafe("windowStyle") == "glasstron") { - console.log("Enabling transparency visuals."); - app.commandLine.appendSwitch("enable-transparent-visuals"); - } +async function appendSwitch() { + if ((await getConfigUnsafe("windowStyle")) == "glasstron") { + console.log("Enabling transparency visuals."); + app.commandLine.appendSwitch("enable-transparent-visuals"); + } } appendSwitch(); - storage.has("settings", function (error, hasKey) { +storage.has("settings", function (error, hasKey) { if (error) throw error; if (!hasKey) { - console.log("First run of the ArmCord. Starting setup."); - setup(); - contentPath = path.join(__dirname, "/content/setup.html"); - if (!contentPath.includes("ts-out")) { - contentPath = path.join(__dirname, "/ts-out/content/setup.html"); - } + console.log("First run of the ArmCord. Starting setup."); + setup(); + contentPath = path.join(__dirname, "/content/setup.html"); + if (!contentPath.includes("ts-out")) { + contentPath = path.join(__dirname, "/ts-out/content/setup.html"); + } } else { - console.log("ArmCord has been run before. Skipping setup."); - contentPath = path.join(__dirname, "/content/splash.html"); - if (!contentPath.includes("ts-out")) { - contentPath = path.join(__dirname, "/ts-out/content/splash.html"); - } + console.log("ArmCord has been run before. Skipping setup."); + contentPath = path.join(__dirname, "/content/splash.html"); + if (!contentPath.includes("ts-out")) { + contentPath = path.join(__dirname, "/ts-out/content/splash.html"); + } } - }); +}); storage.get("settings", function (error, data: any) { - if (error) throw error; - console.log(data); - channel = data.channel; - settings = data; + if (error) throw error; + console.log(data); + channel = data.channel; + settings = data; }); app.whenReady().then(async () => { - switch (await getConfigUnsafe("windowStyle")) { - case "default": - createCustomWindow(); - customTitlebar = true; - break; - case "native": - createNativeWindow(); - break; - case "glasstron": - setTimeout( - createGlasstronWindow, - process.platform == "linux" ? 1000 : 0 - // Electron has a bug on linux where it - // won't initialize properly when using - // transparency. To work around that, it - // is necessary to delay the window - // spawn function. - ); - break; - case "tabs": - createTabsHost(); - tabs = true; - break; - default: - createCustomWindow(); - customTitlebar = true; - break; - } - session - .fromPartition("some-partition") - .setPermissionRequestHandler((webContents, permission, callback) => { - if (permission === "notifications") { - // Approves the permissions request - callback(true); - } - if (permission === "media") { - // Approves the permissions request - callback(true); - } - }); - app.on("activate", async function () { - if (BrowserWindow.getAllWindows().length === 0) - switch (await getConfigUnsafe("windowStyle")) { + switch (await getConfigUnsafe("windowStyle")) { case "default": - createCustomWindow(); - break; + createCustomWindow(); + customTitlebar = true; + break; case "native": - createNativeWindow(); - break; + createNativeWindow(); + break; case "glasstron": - createGlasstronWindow(); - break; + setTimeout( + createGlasstronWindow, + process.platform == "linux" ? 1000 : 0 + // Electron has a bug on linux where it + // won't initialize properly when using + // transparency. To work around that, it + // is necessary to delay the window + // spawn function. + ); + break; + case "tabs": + createTabsHost(); + tabs = true; + break; default: - createCustomWindow(); - break; - } - }); + createCustomWindow(); + customTitlebar = true; + break; + } + session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => { + if (permission === "notifications") { + // Approves the permissions request + callback(true); + } + if (permission === "media") { + // Approves the permissions request + callback(true); + } + }); + app.on("activate", async function () { + if (BrowserWindow.getAllWindows().length === 0) + switch (await getConfigUnsafe("windowStyle")) { + case "default": + createCustomWindow(); + break; + case "native": + createNativeWindow(); + break; + case "glasstron": + createGlasstronWindow(); + break; + default: + createCustomWindow(); + break; + } + }); }); app.on("window-all-closed", function () { - if (process.platform !== "darwin") app.quit(); + if (process.platform !== "darwin") app.quit(); }); diff --git a/src/preload/bridge.ts b/src/preload/bridge.ts index 5b9ba2c..23fe888 100644 --- a/src/preload/bridge.ts +++ b/src/preload/bridge.ts @@ -1,33 +1,30 @@ -import { contextBridge, ipcRenderer } from "electron"; -import { getDisplayMediaSelector } from "./capturer"; -import { injectTitlebar } from "./titlebar"; +import {contextBridge, ipcRenderer} from "electron"; +import {getDisplayMediaSelector} from "./capturer"; +import {injectTitlebar} from "./titlebar"; contextBridge.exposeInMainWorld("armcord", { - window: { - show: () => ipcRenderer.send("win-show"), - hide: () => ipcRenderer.send("win-hide"), - minimize: () => ipcRenderer.send("win-minimize"), - maximize: () => ipcRenderer.send("win-maximize"), - }, - titlebar: { - injectTitlebar: () => injectTitlebar(), - isTitlebar: ipcRenderer.sendSync("titlebar"), - }, - electron: process.versions.electron, - channel: ipcRenderer.sendSync("channel"), - openTab: (number: number) => ipcRenderer.sendSync("openTab", number), - version: ipcRenderer.sendSync("get-app-version", "app-version"), - getDisplayMediaSelector: getDisplayMediaSelector, - openSettingsWindow: () => ipcRenderer.send("openSettingsWindow"), + window: { + show: () => ipcRenderer.send("win-show"), + hide: () => ipcRenderer.send("win-hide"), + minimize: () => ipcRenderer.send("win-minimize"), + maximize: () => ipcRenderer.send("win-maximize") + }, + titlebar: { + injectTitlebar: () => injectTitlebar(), + isTitlebar: ipcRenderer.sendSync("titlebar") + }, + electron: process.versions.electron, + channel: ipcRenderer.sendSync("channel"), + openTab: (number: number) => ipcRenderer.sendSync("openTab", number), + version: ipcRenderer.sendSync("get-app-version", "app-version"), + getDisplayMediaSelector: getDisplayMediaSelector, + openSettingsWindow: () => ipcRenderer.send("openSettingsWindow") }); //to be only used inside armcord internal setup/splash etc -if ( - window.location.href.indexOf("splash.html") > -1 || - window.location.href.indexOf("setup.html") > -1 -) { - contextBridge.exposeInMainWorld("armcordinternal", { - restart: () => ipcRenderer.send("restart"), - saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args), - splashEnd: () => ipcRenderer.send("splashEnd"), - }); -} \ No newline at end of file +if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) { + contextBridge.exposeInMainWorld("armcordinternal", { + restart: () => ipcRenderer.send("restart"), + saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args), + splashEnd: () => ipcRenderer.send("splashEnd") + }); +} diff --git a/src/preload/capturer.ts b/src/preload/capturer.ts index b3fc1d9..2f6d8ed 100644 --- a/src/preload/capturer.ts +++ b/src/preload/capturer.ts @@ -1,37 +1,36 @@ //Fixed context isolation version https://github.com/getferdi/ferdi/blob/develop/src/webview/screenshare.ts //original https://github.com/electron/electron/issues/16513#issuecomment-602070250 -import { ipcRenderer } from 'electron'; -import {addStyle, addScript} from '../utils'; +import {ipcRenderer} from "electron"; +import {addStyle, addScript} from "../utils"; const desktopCapturer = { - getSources: (opts: any) => - ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts), + getSources: (opts: any) => ipcRenderer.invoke("DESKTOP_CAPTURER_GET_SOURCES", opts) }; -const CANCEL_ID = 'desktop-capturer-selection__cancel'; +const CANCEL_ID = "desktop-capturer-selection__cancel"; interface IPCSources { - id: string; - name: string; - thumbnail: HTMLCanvasElement; + id: string; + name: string; + thumbnail: HTMLCanvasElement; } export async function getDisplayMediaSelector() { - const sources: IPCSources[] = await desktopCapturer.getSources({ - types: ['screen', 'window'], - }); - return `
+ const sources: IPCSources[] = await desktopCapturer.getSources({ + types: ["screen", "window"] + }); + return `
`; - elem.classList.add("withFrame-haYltI"); - if (document.getElementById("app-mount") == null) { - document.body.appendChild(elem); - } else { - document.getElementById("app-mount")!.prepend(elem); - } - const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); - addStyle(fs.readFileSync(cssPath, "utf8")); -})} \ No newline at end of file + elem.classList.add("withFrame-haYltI"); + if (document.getElementById("app-mount") == null) { + document.body.appendChild(elem); + } else { + document.getElementById("app-mount")!.prepend(elem); + } + const cssPath = path.join(__dirname, "../", "/content/css/tabs.css"); + addStyle(fs.readFileSync(cssPath, "utf8")); + }); +} diff --git a/src/preload/titlebar.ts b/src/preload/titlebar.ts index f1d5560..5e103ef 100644 --- a/src/preload/titlebar.ts +++ b/src/preload/titlebar.ts @@ -1,11 +1,11 @@ -import { ipcRenderer } from "electron"; -import { addStyle } from "../utils"; +import {ipcRenderer} from "electron"; +import {addStyle} from "../utils"; import * as fs from "fs"; import * as path from "path"; export function injectTitlebar() { - document.addEventListener("DOMContentLoaded", function (event) { - var elem = document.createElement("div"); - elem.innerHTML = `