diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 1509958f1..fb6ed3ed7 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -301,6 +301,10 @@
"message": "Use High Contrast",
"description": "Use High Contrast"
},
+ "show_favicon": {
+ "message": "Show Website Icon",
+ "description": "Show Issuer Icon"
+ },
"theme": {
"message": "Theme",
"description": "Theme"
@@ -512,6 +516,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/manifests/manifest-chrome-testing.json b/manifests/manifest-chrome-testing.json
index 96d128949..fced88ea4 100644
--- a/manifests/manifest-chrome-testing.json
+++ b/manifests/manifest-chrome-testing.json
@@ -57,7 +57,8 @@
],
"optional_permissions": [
"clipboardWrite",
- "contextMenus"
+ "contextMenus",
+ "favicon"
],
"optional_host_permissions": [
"https://www.google.com/",
diff --git a/manifests/manifest-chrome.json b/manifests/manifest-chrome.json
index e792d9c3b..7c4f291db 100644
--- a/manifests/manifest-chrome.json
+++ b/manifests/manifest-chrome.json
@@ -57,7 +57,8 @@
],
"optional_permissions": [
"clipboardWrite",
- "contextMenus"
+ "contextMenus",
+ "favicon"
],
"optional_host_permissions": [
"https://www.google.com/",
diff --git a/manifests/manifest-edge.json b/manifests/manifest-edge.json
index 9997b05a4..4d8585b44 100644
--- a/manifests/manifest-edge.json
+++ b/manifests/manifest-edge.json
@@ -56,7 +56,8 @@
],
"optional_permissions": [
"clipboardWrite",
- "contextMenus"
+ "contextMenus",
+ "favicon"
],
"optional_host_permissions": [
"https://www.google.com/",
diff --git a/sass/popup.scss b/sass/popup.scss
index 6849dd8c3..ec0d94aa1 100644
--- a/sass/popup.scss
+++ b/sass/popup.scss
@@ -317,6 +317,20 @@ svg {
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;
+ }
+ }
+
+ .issuerFavicon {
+ background-color: #fff;
+ border: 1px solid #fff;
}
.code {
diff --git a/src/components/Popup/EntryComponent.vue b/src/components/Popup/EntryComponent.vue
index 92099b5b1..3481b9a49 100644
--- a/src/components/Popup/EntryComponent.vue
+++ b/src/components/Popup/EntryComponent.vue
@@ -39,6 +39,14 @@
+
![]()
{{
entry.issuer.split("::")[0] +
(theme === "compact" ? ` (${entry.account})` : "")
@@ -90,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 { getCurrentTab, okToInjectContentScript } from "../../utils";
import IconMinusCircle from "../../../svg/minus-circle.svg";
@@ -97,6 +106,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", [
@@ -110,7 +120,11 @@ const computedPrototype = [
mapState("menu", ["theme"]),
];
-let computed = {};
+let computed = {
+ shouldShowFavicon(this: any) {
+ return !isFirefox && !isSafari && this.$store.state.menu.showFavicon;
+ },
+};
for (const module of computedPrototype) {
Object.assign(computed, module);
@@ -138,6 +152,12 @@ export default Vue.extend({
entry.type !== OTPType.steam
);
},
+ getFaviconUrl(u: string) {
+ const url = new URL(chrome.runtime.getURL("/_favicon/"));
+ url.searchParams.set("pageUrl", "https://" + u);
+ url.searchParams.set("size", "16");
+ return url.toString();
+ },
showCode(code: string) {
if (code === CodeState.Encrypted) {
return this.i18n.encrypted;
@@ -254,6 +274,7 @@ export default Vue.extend({
IconQr,
IconBars,
IconPin,
+ IconMedal,
},
});
diff --git a/src/components/Popup/PreferencesPage.vue b/src/components/Popup/PreferencesPage.vue
index 299b9d8d1..275ab2075 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
+ );
+ }
+ );
+ },
+ },
theme: {
get(): string {
return this.$store.state.menu.theme;
diff --git a/src/definitions/module-interface.d.ts b/src/definitions/module-interface.d.ts
index 494266315..ee57e2a88 100644
--- a/src/definitions/module-interface.d.ts
+++ b/src/definitions/module-interface.d.ts
@@ -36,6 +36,7 @@ interface MenuState {
useAutofill: boolean;
smartFilter: boolean;
enableContextMenu: boolean;
+ showFavicon: boolean;
theme: string;
backupDisabled: boolean;
storageArea: "sync" | "local";
diff --git a/src/models/settings.ts b/src/models/settings.ts
index aac7a84b0..9d21c3fd0 100644
--- a/src/models/settings.ts
+++ b/src/models/settings.ts
@@ -29,6 +29,7 @@ interface UserSettingsData {
enableContextMenu?: boolean;
encodedPhrase?: string;
smartFilter?: boolean;
+ showFavicon?: boolean;
theme?: string;
zoom?: number;
}
@@ -184,7 +185,8 @@ type BooleanOption =
| "oneDriveBusiness"
| "oneDriveEncrypted"
| "oneDriveRevoked"
- | "smartFilter";
+ | "smartFilter"
+ | "showFavicon";
type NumberOption = "autolock" | "lastRemindingBackupTime" | "offset" | "zoom";
@@ -202,6 +204,7 @@ function isBooleanOption(key: string): key is BooleanOption {
"oneDriveEncrypted",
"oneDriveRevoked",
"smartFilter",
+ "showFavicon",
].includes(key);
}
diff --git a/src/store/Menu.ts b/src/store/Menu.ts
index 48487d6ed..8dcad0cd6 100644
--- a/src/store/Menu.ts
+++ b/src/store/Menu.ts
@@ -13,6 +13,7 @@ export class Menu implements Module {
useAutofill: UserSettings.items.autofill === true,
smartFilter: UserSettings.items.smartFilter === true,
enableContextMenu: UserSettings.items.enableContextMenu === true,
+ showFavicon: UserSettings.items.showFavicon === true,
theme: UserSettings.items.theme || (isSafari ? "flat" : "normal"),
autolock: Number(UserSettings.items.autolock) || 30,
backupDisabled: await ManagedStorage.get("disableBackup", false),
@@ -48,6 +49,11 @@ export class Menu implements Module {
UserSettings.items.enableContextMenu = enableContextMenu;
UserSettings.commitItems();
},
+ setShowFavicon(state: MenuState, showFavicon: boolean) {
+ state.showFavicon = showFavicon;
+ UserSettings.items.showFavicon = showFavicon;
+ UserSettings.commitItems();
+ },
setTheme(state: MenuState, theme: string) {
state.theme = theme;
UserSettings.items.theme = theme;
diff --git a/src/store/Permissions.ts b/src/store/Permissions.ts
index a8d20ebca..ed3764b00 100644
--- a/src/store/Permissions.ts
+++ b/src/store/Permissions.ts
@@ -37,6 +37,11 @@ const permissions: Permission[] = [
description: chrome.i18n.getMessage("permission_context_menus"),
revocable: true,
},
+ {
+ id: "favicon",
+ description: chrome.i18n.getMessage("permission_favicon"),
+ revocable: true,
+ },
{
id: "https://www.google.com/*",
description: chrome.i18n.getMessage("permission_sync_clock"),
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