From 0f65f16c56471ad16859d274c07fa92a17e52ebf Mon Sep 17 00:00:00 2001 From: Zhe Li Date: Tue, 17 Oct 2023 15:56:08 +0800 Subject: [PATCH 1/4] add favicon support --- _locales/en/messages.json | 4 ++++ manifests/manifest-chrome-testing.json | 4 +++- manifests/manifest-chrome.json | 4 +++- manifests/manifest-edge.json | 4 +++- sass/popup.scss | 7 +++++++ src/components/Popup/EntryComponent.vue | 26 +++++++++++++++++++++++- src/components/Popup/PreferencesPage.vue | 22 ++++++++++++++++++++ src/definitions/module-interface.d.ts | 1 + src/store/Menu.ts | 5 +++++ svg/medal.svg | 1 + 10 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 svg/medal.svg diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c7477122e..7a5fa582f 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -289,6 +289,10 @@ "message": "Use Autofill", "description": "Use Autofill" }, + "show_favicon": { + "message": "Show Issuer Icon", + "description": "Show Issuer Icon" + }, "use_high_contrast": { "message": "Use High Contrast", "description": "Use High Contrast" diff --git a/manifests/manifest-chrome-testing.json b/manifests/manifest-chrome-testing.json index 5f3da5880..d2087999e 100644 --- a/manifests/manifest-chrome-testing.json +++ b/manifests/manifest-chrome-testing.json @@ -57,6 +57,8 @@ "optional_permissions": [ "clipboardWrite", "contextMenus", + "favicon", + "chrome://favicon/", "https://www.google.com/", "https://*.dropboxapi.com/*", "https://www.googleapis.com/*", @@ -66,5 +68,5 @@ ], "offline_enabled": true, "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjo5++7m6mlJGqKOnlYehr9tjIqahMZBJUG7PLa7dSRk6bDUu2pVodO1TQWviHlrDTLP+zfoVbDBS8v8cjloK5Tn90nzC6a957dPzOfyC1WUNYNDlGM0BCmZKVP/MWB3d0ffOmTwaxh0L47aLH5nTW0AUmuwCWCBEEl4Acuyp7rwLNGlazBpaom1Qb5ckn29gCJVVVIZ6wudmcrG/FPTNJXQbg8N6wObGrgGOaxmowbkzJmIfKTyHlYOKLAjZ7aJi0W6jsy47/aV+ojvn4gO+ka6BcRhUeWgoQxqEky119f3OWiVP46SJVbAi0pkknThUjDvX11lATGjB5EvJZGyotwIDAQAB", - "content_security_policy": "script-src 'self' 'unsafe-eval'; font-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/ ws://localhost:9090; default-src 'none'" + "content_security_policy": "script-src 'self' 'unsafe-eval'; font-src 'self'; img-src 'self' data: chrome://favicon/; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/ ws://localhost:9090; default-src 'none'" } diff --git a/manifests/manifest-chrome.json b/manifests/manifest-chrome.json index 17f97aec4..4bee1a5fa 100644 --- a/manifests/manifest-chrome.json +++ b/manifests/manifest-chrome.json @@ -60,6 +60,8 @@ "optional_permissions": [ "clipboardWrite", "contextMenus", + "favicon", + "chrome://favicon/", "https://www.google.com/", "https://*.dropboxapi.com/*", "https://www.googleapis.com/*", @@ -68,5 +70,5 @@ "https://login.microsoftonline.com/common/oauth2/v2.0/token" ], "offline_enabled": true, - "content_security_policy": "script-src 'self'; font-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/; default-src 'none'" + "content_security_policy": "script-src 'self'; font-src 'self'; img-src 'self' data: chrome://favicon/; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/; default-src 'none'" } diff --git a/manifests/manifest-edge.json b/manifests/manifest-edge.json index c2df891ef..72217e0cb 100644 --- a/manifests/manifest-edge.json +++ b/manifests/manifest-edge.json @@ -60,6 +60,8 @@ "optional_permissions": [ "clipboardWrite", "contextMenus", + "favicon", + "chrome://favicon/", "https://www.google.com/", "https://*.dropboxapi.com/*", "https://www.googleapis.com/*", @@ -68,5 +70,5 @@ "https://login.microsoftonline.com/common/oauth2/v2.0/token" ], "offline_enabled": true, - "content_security_policy": "script-src 'self'; font-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/; default-src 'none'" + "content_security_policy": "script-src 'self'; font-src 'self'; img-src 'self' data: chrome://favicon/; style-src 'self' 'unsafe-inline'; connect-src https://www.google.com/ https://*.dropboxapi.com https://www.googleapis.com/ https://accounts.google.com/o/oauth2/revoke https://login.microsoftonline.com/common/oauth2/v2.0/token https://graph.microsoft.com/; default-src 'none'" } diff --git a/sass/popup.scss b/sass/popup.scss index 6849dd8c3..0aa75179a 100644 --- a/sass/popup.scss +++ b/sass/popup.scss @@ -212,6 +212,13 @@ svg { display: none; } + .issuerFavicon { + vertical-align: bottom; + margin-right: 5px; + height: 14px; + width: 14px; + } + &:hover { padding-right: 0; overflow-y: scroll; diff --git a/src/components/Popup/EntryComponent.vue b/src/components/Popup/EntryComponent.vue index 904feeae5..769f787a8 100644 --- a/src/components/Popup/EntryComponent.vue +++ b/src/components/Popup/EntryComponent.vue @@ -39,7 +39,15 @@
- {{ + + {{ entry.issuer.split("::")[0] + (theme === "compact" ? ` (${entry.account})` : "") }} @@ -96,6 +104,7 @@ import IconRedo from "../../../svg/redo.svg"; import IconQr from "../../../svg/qrcode.svg"; import IconBars from "../../../svg/bars.svg"; import IconPin from "../../../svg/pin.svg"; +import IconMedal from "../../../svg/medal.svg"; const computedPrototype = [ mapState("accounts", [ @@ -137,6 +146,20 @@ export default Vue.extend({ entry.type !== OTPType.steam ); }, + shouldShowFavicon() { + return ( + navigator.userAgent.indexOf("Firefox") === -1 && + this.$store.state.menu.showFavicon + ); + }, + getFaviconUrl(u: string) { + // for MV3 + // const url = new URL(chrome.runtime.getURL("/_favicon/")); + // url.searchParams.set("pageUrl", "https://" + u); + // url.searchParams.set("size", "16"); + // return url.toString(); + return "chrome://favicon/https://" + u; + }, showCode(code: string) { if (code === CodeState.Encrypted) { return this.i18n.encrypted; @@ -261,6 +284,7 @@ export default Vue.extend({ IconQr, IconBars, IconPin, + IconMedal, }, }); diff --git a/src/components/Popup/PreferencesPage.vue b/src/components/Popup/PreferencesPage.vue index 7926e33b4..40b3e1e22 100644 --- a/src/components/Popup/PreferencesPage.vue +++ b/src/components/Popup/PreferencesPage.vue @@ -43,6 +43,11 @@ @change="requireContextMenuPermission()" v-if="isSupported" /> +
{ + this.$store.commit( + "menu/setShowFavicon", + granted ? showFavicon : false + ); + } + ); + }, + }, }, data() { return { newStorageLocation: this.$store.state.menu.storageArea || localStorage.storageLocation, + isNotFirefox: navigator.userAgent.indexOf("Firefox") === -1, }; }, methods: { diff --git a/src/definitions/module-interface.d.ts b/src/definitions/module-interface.d.ts index 3dc038637..a7663a6d4 100644 --- a/src/definitions/module-interface.d.ts +++ b/src/definitions/module-interface.d.ts @@ -38,6 +38,7 @@ interface MenuState { theme: string; backupDisabled: boolean; storageArea: "sync" | "local"; + showFavicon: boolean; } interface StyleState { diff --git a/src/store/Menu.ts b/src/store/Menu.ts index e6f1428b9..15a0d0f1b 100644 --- a/src/store/Menu.ts +++ b/src/store/Menu.ts @@ -10,6 +10,7 @@ export class Menu implements Module { useAutofill: localStorage.autofill === "true", smartFilter: localStorage.smartFilter !== "false", enableContextMenu: localStorage.enableContextMenu === "true", + showFavicon: localStorage.showFavicon === "true", theme: localStorage.theme || (localStorage.highContrast === "true" @@ -47,6 +48,10 @@ export class Menu implements Module { state.enableContextMenu = enableContextMenu; localStorage.enableContextMenu = enableContextMenu; }, + setShowFavicon(state: MenuState, showFavicon: boolean) { + state.showFavicon = showFavicon; + localStorage.showFavicon = showFavicon; + }, setTheme(state: MenuState, theme: string) { state.theme = theme; localStorage.theme = theme; diff --git a/svg/medal.svg b/svg/medal.svg new file mode 100644 index 000000000..48c83d328 --- /dev/null +++ b/svg/medal.svg @@ -0,0 +1 @@ + \ No newline at end of file From 2dc7f58c8a35dfef85ff7655f0c0382d5c34c697 Mon Sep 17 00:00:00 2001 From: Zhe Li Date: Fri, 3 Nov 2023 13:36:13 +0800 Subject: [PATCH 2/4] Update _locales/en/messages.json Co-authored-by: Brendan --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7a5fa582f..41e366dfa 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -290,7 +290,7 @@ "description": "Use Autofill" }, "show_favicon": { - "message": "Show Issuer Icon", + "message": "Show Website Icon", "description": "Show Issuer Icon" }, "use_high_contrast": { From 515b8491102cd01c1ae92bd1b45804d870c44f4a Mon Sep 17 00:00:00 2001 From: Zhe Li Date: Fri, 3 Nov 2023 13:37:26 +0800 Subject: [PATCH 3/4] Update src/components/Popup/EntryComponent.vue Co-authored-by: Brendan --- src/components/Popup/EntryComponent.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Popup/EntryComponent.vue b/src/components/Popup/EntryComponent.vue index 769f787a8..e47c0e99c 100644 --- a/src/components/Popup/EntryComponent.vue +++ b/src/components/Popup/EntryComponent.vue @@ -153,7 +153,7 @@ export default Vue.extend({ ); }, getFaviconUrl(u: string) { - // for MV3 + // TODO: Switch to commented out implementation when MV3 // const url = new URL(chrome.runtime.getURL("/_favicon/")); // url.searchParams.set("pageUrl", "https://" + u); // url.searchParams.set("size", "16"); From ad64b37f2e61f24f3524a03a8737c7ee08bd0948 Mon Sep 17 00:00:00 2001 From: Zhe Li Date: Wed, 8 Nov 2023 14:23:47 +0800 Subject: [PATCH 4/4] update --- _locales/en/messages.json | 3 +++ sass/popup.scss | 28 ++++++++++++++++++------- src/components/Popup/EntryComponent.vue | 18 +++++++--------- src/store/Permissions.ts | 10 +++++++++ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 41e366dfa..47194fc28 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -505,6 +505,9 @@ "permission_onedrive_cannot_revoke": { "message": "You must disable OneDrive backup first." }, + "permission_favicon": { + "message": "Allows fetching website icons." + }, "permission_unknown_permission": { "message": "Unknown permission. If see this message, please send a bug report." } diff --git a/sass/popup.scss b/sass/popup.scss index 0aa75179a..89e9a5b09 100644 --- a/sass/popup.scss +++ b/sass/popup.scss @@ -212,13 +212,6 @@ svg { display: none; } - .issuerFavicon { - vertical-align: bottom; - margin-right: 5px; - height: 14px; - width: 14px; - } - &:hover { padding-right: 0; overflow-y: scroll; @@ -318,12 +311,23 @@ svg { .issuer { font-size: 12px; + line-height: 16px; + height: 16px; @include themify($themes) { color: themed("black-1"); } width: 80%; text-overflow: ellipsis; overflow: hidden; + + .issuerFavicon { + vertical-align: bottom; + margin-right: 5px; + height: 16px; + width: 16px; + border-radius: 3px; + border: 1px solid transparent; + } } .code { @@ -1075,6 +1079,11 @@ svg { color: #ccc; } + .issuerFavicon { + background: white; + border: 1px solid white !important; + } + ::-webkit-scrollbar { background: #1e1e1e !important; } @@ -1207,6 +1216,11 @@ svg { } } + .issuerFavicon { + background: white; + border: 1px solid white !important; + } + .showqr, .pin { svg { diff --git a/src/components/Popup/EntryComponent.vue b/src/components/Popup/EntryComponent.vue index e47c0e99c..37cdac4ee 100644 --- a/src/components/Popup/EntryComponent.vue +++ b/src/components/Popup/EntryComponent.vue @@ -41,13 +41,13 @@
- {{ + {{ entry.issuer.split("::")[0] + (theme === "compact" ? ` (${entry.account})` : "") }} @@ -98,6 +98,7 @@ import { mapState } from "vuex"; import * as QRGen from "qrcode-generator"; import { OTPEntry, OTPType, CodeState, OTPAlgorithm } from "../../models/otp"; import { EntryStorage } from "../../models/storage"; +import { isFirefox, isSafari } from "../../browser"; import IconMinusCircle from "../../../svg/minus-circle.svg"; import IconRedo from "../../../svg/redo.svg"; @@ -118,7 +119,10 @@ const computedPrototype = [ mapState("menu", ["theme"]), ]; -let computed = {}; +let computed: {} = { + shouldShowFavicon: + !isFirefox && !isSafari && mapState("menu", ["showFavicon"]).showFavicon, +}; for (const module of computedPrototype) { Object.assign(computed, module); @@ -146,12 +150,6 @@ export default Vue.extend({ entry.type !== OTPType.steam ); }, - shouldShowFavicon() { - return ( - navigator.userAgent.indexOf("Firefox") === -1 && - this.$store.state.menu.showFavicon - ); - }, getFaviconUrl(u: string) { // TODO: Switch to commented out implementation when MV3 // const url = new URL(chrome.runtime.getURL("/_favicon/")); diff --git a/src/store/Permissions.ts b/src/store/Permissions.ts index 142fdf864..ce9ebaade 100644 --- a/src/store/Permissions.ts +++ b/src/store/Permissions.ts @@ -130,6 +130,16 @@ const permissions: Permission[] = [ }, ], }, + { + id: "favicon", + description: chrome.i18n.getMessage("permission_favicon"), + revocable: true, + }, + { + id: "chrome://favicon/*", + description: chrome.i18n.getMessage("permission_favicon"), + revocable: true, + }, ]; export class Permissions implements Module {