diff --git a/manifest-chrome.json b/manifest-chrome.json
index 1437764a2..36c166329 100644
--- a/manifest-chrome.json
+++ b/manifest-chrome.json
@@ -18,6 +18,9 @@
"default_title": "__MSG_extShortName__",
"default_popup": "view/popup.html"
},
+ "storage": {
+ "managed_schema": "schema.json"
+ },
"oauth2": {
"client_id": "292457304165-u8ve4j79gag5o231n5u2pdtdrbfdo1hh.apps.googleusercontent.com",
"scopes": [
diff --git a/schema-chrome.json b/schema-chrome.json
new file mode 100644
index 000000000..f852f93ae
--- /dev/null
+++ b/schema-chrome.json
@@ -0,0 +1,29 @@
+{
+ "type": "object",
+
+ "properties": {
+ "disableInstallHelp": {
+ "title": "Disable opening help page on install",
+ "description": "If set to true then help page will not be opened on install.",
+ "type": "boolean"
+ },
+
+ "disableBackup": {
+ "title": "Disable 3rd party backup",
+ "description": "If set to true then 3rd party backup options will be hidden. If 3rd party backup is already configured for a user this will not stop it.",
+ "type": "boolean"
+ },
+
+ "storageArea": {
+ "title": "Storage area",
+ "description": "Set to 'sync' or 'local'. If set will force user to use specified storage area. This setting will not check if a user is currently using another storage space and may hide data.",
+ "type": "string"
+ },
+
+ "feedbackURL": {
+ "title": "Feedback URL",
+ "description": "Change the URL the feedback button opens.",
+ "type": "string"
+ }
+ }
+}
diff --git a/scripts/build.sh b/scripts/build.sh
index 215908866..6ae95f287 100644
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -58,6 +58,9 @@ if [[ $PLATFORM = "edge" ]]; then
else
cp -r build css images js _locales LICENSE view $PLATFORM
cp manifest-$PLATFORM.json $PLATFORM/manifest.json
+ if [[ $PLATFORM = "chrome" ]]; then
+ cp schema-chrome.json $PLATFORM/schema.json
+ fi
fi
echo -e "\033[0;32mDone!\033[0m"
diff --git a/src/background.ts b/src/background.ts
index 60e8c990b..53a50aa61 100644
--- a/src/background.ts
+++ b/src/background.ts
@@ -265,9 +265,11 @@ function getBackupToken(service: string) {
}
// Show issue page after first install
-chrome.runtime.onInstalled.addListener((details) => {
+chrome.runtime.onInstalled.addListener(async (details) => {
if (details.reason !== 'install') {
return;
+ } else if (await ManagedStorage.get('disableInstallHelp')) {
+ return;
}
let url: string|null = null;
diff --git a/src/models/storage.ts b/src/models/storage.ts
index f5e46ec61..a928d56d1 100644
--- a/src/models/storage.ts
+++ b/src/models/storage.ts
@@ -4,8 +4,18 @@
///
class BrowserStorage {
- private static getStorageLocation() {
- if (localStorage.storageLocation !== 'sync' &&
+ private static async getStorageLocation() {
+ const managedLocation = await ManagedStorage.get('storageArea');
+ if (managedLocation === 'sync' || managedLocation === 'local') {
+ return new Promise((resolve) => {
+ if (localStorage.storageLocation !== managedLocation) {
+ localStorage.storageLocation = managedLocation;
+ }
+ resolve(managedLocation);
+ return;
+ });
+ } else if (
+ localStorage.storageLocation !== 'sync' &&
localStorage.storageLocation !== 'local') {
return new Promise((resolve, reject) => {
let amountSync: number;
@@ -144,7 +154,7 @@ class EntryStorage {
}
}
- static async hasEncryptedEntry() {
+ static hasEncryptedEntry() {
return new Promise(
(resolve: (value: boolean) => void,
reject: (reason: Error) => void) => {
@@ -163,7 +173,7 @@ class EntryStorage {
});
}
- static async getExport(encryption: Encryption, encrypted?: boolean) {
+ static getExport(encryption: Encryption, encrypted?: boolean) {
return new Promise(
(resolve: (value: {[hash: string]: OTPStorage}) => void,
reject: (reason: Error) => void) => {
@@ -201,8 +211,7 @@ class EntryStorage {
});
}
- static async import(
- encryption: Encryption, data: {[hash: string]: OTPStorage}) {
+ static import(encryption: Encryption, data: {[hash: string]: OTPStorage}) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
@@ -285,7 +294,7 @@ class EntryStorage {
});
}
- static async add(encryption: Encryption, entry: OTPEntry) {
+ static add(encryption: Encryption, entry: OTPEntry) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
@@ -306,7 +315,7 @@ class EntryStorage {
});
}
- static async update(encryption: Encryption, entry: OTPEntry) {
+ static update(encryption: Encryption, entry: OTPEntry) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
@@ -327,7 +336,7 @@ class EntryStorage {
});
}
- static async set(encryption: Encryption, entries: OTPEntry[]) {
+ static set(encryption: Encryption, entries: OTPEntry[]) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
@@ -347,7 +356,7 @@ class EntryStorage {
});
}
- static async get(encryption: Encryption) {
+ static get(encryption: Encryption) {
return new Promise(
(resolve: (value: OTPEntry[]) => void,
reject: (reason: Error) => void) => {
@@ -491,14 +500,14 @@ class EntryStorage {
});
}
- static async remove(hash: string) {
+ static remove(hash: string) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
return BrowserStorage.remove(hash, resolve);
});
}
- static async delete(entry: OTPEntry) {
+ static delete(entry: OTPEntry) {
return new Promise(
(resolve: () => void, reject: (reason: Error) => void) => {
try {
@@ -519,3 +528,21 @@ class EntryStorage {
});
}
}
+
+class ManagedStorage {
+ static get(key: string) {
+ return new Promise((resolve: (result: boolean|string) => void) => {
+ chrome.storage.managed.get((data) => {
+ if (chrome.runtime.lastError) {
+ resolve(false);
+ }
+ if (data) {
+ if (data[key]) {
+ resolve(data[key]);
+ }
+ }
+ resolve(false);
+ });
+ });
+ }
+}
diff --git a/src/ui/menu.ts b/src/ui/menu.ts
index d1a40ca08..46aa47afb 100644
--- a/src/ui/menu.ts
+++ b/src/ui/menu.ts
@@ -53,7 +53,7 @@ function resize(zoom: number) {
}
}
-function openHelp() {
+async function openHelp() {
let url =
'https://github.com/Authenticator-Extension/Authenticator/wiki/Chrome-Issues';
@@ -65,9 +65,25 @@ function openHelp() {
'https://github.com/Authenticator-Extension/Authenticator/wiki/Edge-Issues';
}
- window.open(url, '_blank');
+ const feedbackURL = await ManagedStorage.get('feedbackURL');
+ if (typeof feedbackURL === 'string' && feedbackURL) {
+ url = feedbackURL;
+ }
+
+ chrome.tabs.create({url});
}
+let backupDisabled: boolean|string;
+let storageArea: boolean|string;
+
+ManagedStorage.get('disableBackup').then((value) => {
+ backupDisabled = value;
+});
+
+ManagedStorage.get('storageArea').then((value) => {
+ storageArea = value;
+});
+
async function menu(_ui: UI) {
const version = getVersion();
const zoom = Number(localStorage.zoom) || 100;
@@ -81,7 +97,9 @@ async function menu(_ui: UI) {
zoom,
useAutofill,
useHighContrast,
- newStorageLocation: localStorage.storageLocation
+ newStorageLocation: localStorage.storageLocation,
+ backupDisabled,
+ storageArea
},
methods: {
openLink: (url: string) => {
diff --git a/view/popup.html b/view/popup.html
index 5798e0af7..8fb18a20f 100644
--- a/view/popup.html
+++ b/view/popup.html
@@ -203,15 +203,15 @@
{{ i18n.storage_location_info }}
-