diff --git a/.gitignore b/.gitignore index 42727e223..06abdbcfb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules build chrome firefox +edge .vscode .atom-build.yml ci/authenticator-build-key.enc diff --git a/.travis.yml b/.travis.yml index d9db3f865..d18a6b5ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ jobs: - stage: deploy # release tagging script: bash ci/tag.sh - if: branch = release + if: branch = release AND type != pull_request diff --git a/README.md b/README.md index 3b1212291..18c04a358 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,23 @@ > Authenticator generates 2-Step Verification codes in your browser. -## Available for Chrome and Firefox +## Available for Chrome, Firefox, and Microsoft Edge -[](https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai) [](https://addons.mozilla.org/en-US/firefox/addon/auth-helper?src=external-github) +[](https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai) [](https://addons.mozilla.org/en-US/firefox/addon/auth-helper?src=external-github) [](https://www.microsoft.com/store/apps/9P0FD39WFFMK?ocid=badge) Authenticator is one of the [featured extensions on Firefox Add-ons this month](https://blog.mozilla.org/addons/2018/07/02/julys-featured-extensions-2/)! ## Build Setup ``` bash -# install typescript -npm install -g typescript -#install gts -npm install -g gts -# install dependencies +# install typescript and gts +npm install -g typescript gts +# install development dependencies npm install -# check typescript style -gts check -# try to auto fix style issue +# fix code style issues gts fix -# compile for Chrome -npm run chrome -# compile for Firefox -npm run firefox +# compile +npm run [chrome, firefox, edge] ``` + +Note that Windows users should download [Cygwin](http://cygwin.com/) to build. Building for Edge requires the [Windows App Certification Kit](https://developer.microsoft.com/en-us/windows/develop/app-certification-kit) diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index 4b2587f6e..1443f7b87 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -1,30 +1,30 @@ { "extName": { - "message": "Ověření", + "message": "Authenticator", "description": "Extension Name." }, "extShortName": { - "message": "Ověřovatel", + "message": "Authenticator", "description": "Extension Short Name." }, "extDesc": { - "message": "Authenticator generuje kódy 2 krok ověření v prohlížeči.", + "message": "Authenticator generuje kódy dvoufázového ověření ve Vašem prohlížeči.", "description": "Extension Description." }, "added": { - "message": " byla přidána.", + "message": " byl přidán.", "description": "Added Account." }, "errorqr": { - "message": "Neznámý kód QR.", + "message": "QR kód nebyl rozpoznán.", "description": "QR Error." }, "errorsecret": { - "message": "Tajné chyba. Jen Base32 (A-Z, 2-7 a =) a HEX (0-9 a A-F) jsou podporovány. Vaše tajemství je však: ", + "message": "Chyba tajného klíče. Podporovány jsou pouze Base32(A-Z, 2-7 a =) a HEX(0-9 a A-F). Nicméně, Váš tajný klíč je: ", "description": "Secret Error." }, "add_qr": { - "message": "Načíst QR kód", + "message": "Naskenovat QR kód", "description": "Scan QR Code." }, "add_secret": { @@ -64,7 +64,7 @@ "description": "Secret." }, "updateSuccess": { - "message": "Úspěšně dokončeno.", + "message": "Úspěch.", "description": "Update Success." }, "updateFailure": { @@ -76,7 +76,7 @@ "description": "About." }, "export_import": { - "message": "Export \/ Import", + "message": "Exportovat \/ Importovat", "description": "Export and Import." }, "settings": { @@ -88,7 +88,7 @@ "description": "Security." }, "current_phrase": { - "message": "Aktuální heslo", + "message": "Stávající heslo", "description": "Current Passphrase." }, "new_phrase": { @@ -108,7 +108,7 @@ "description": "Remove entry confirmation" }, "security_warning": { - "message": "Toto heslo bude používat k šifrování váš tajný klíč. Pokud zapomenete heslo, nikdo vám nemůže pomoct.", + "message": "Toto heslo se bude používat k zašifrování vašich tajných klíčů. Pokud zapomenete heslo, nikdo vám nemůže pomoci.", "description": "Passphrase Warning." }, "update": { @@ -116,11 +116,11 @@ "description": "Update." }, "phrase_incorrect": { - "message": "Nelze přidat nový účet nebo exportovat data, pokud jsou všechny účty dešifrovány. Před dalším pokračováním zadejte správné heslo.", + "message": "Nemůžete přidat nový účet nebo exportovat data, pokud jsou všechny účty dešifrovány. Před dalším pokračováním zadejte prosím správné heslo.", "description": "Passphrase Incorrect." }, "phrase_not_match": { - "message": "Hesla nesouhlasí.", + "message": "Heslo se neshoduje.", "description": "Passphrase Not Match." }, "encrypted": { @@ -152,11 +152,11 @@ "description": "Sync Clock" }, "remember_phrase": { - "message": "Pamatovat si heslo", + "message": "Zapamatovat si heslo", "description": "Remember Passphrase" }, "clock_too_far_off": { - "message": "Pozor! Váš místní čas se velmi liší, opravte jej prosím před pokračováním.", + "message": "Pozor! Váš místní čas se velmi liší, před pokračováním jej prosím opravte.", "description": "Local Time is Too Far Off" }, "remind_backup": { @@ -172,19 +172,19 @@ "description": "Time Based" }, "based_on_counter": { - "message": "Počítadlo založeno", + "message": "Založeno na počítadle", "description": "Counter Based" }, "resize_popup_page": { - "message": "Popup obrázek", + "message": "Vyskakovací stránka", "description": "Popup Page Settings" }, "scale": { - "message": "Zvětšení", + "message": "Měřítko", "description": "Scale" }, "export_info": { - "message": "Upozornění: všechny zálohy nejsou rozšifrovány. Chcete přidat účet do jiné aplikace? Ukazatel myši nad pravý horní roh z libovolného účtu a kliknete na tlačítko skryté.", + "message": "Upozornění: všechny zálohy jsou nešifrované. Chcete přidat účet do jiné aplikace? Najeďte myší na pravý horní roh libovolného účtu a klikněte na skryté tlačítko.", "description": "Export menu info text" }, "download_backup": { @@ -200,11 +200,11 @@ "description": "Import backup file." }, "import_backup_code": { - "message": "Importovat textový soubor", + "message": "Importovat textovou zálohu", "description": "Import backup code." }, "dropbox_backup": { - "message": "Automatická záloha na Dropbox", + "message": "Automatické zálohování na Dropbox", "description": "Auto backup to Dropbox." }, "dropbox_code": { diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index f3ab60fc0..2db402bec 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -20,7 +20,7 @@ "description": "QR Error." }, "errorsecret": { - "message": "Lỗi từ khóa. Chỉ chứa các ký tự Base32(A-Z, 2-7 và =) và các ký tự mã HEX(0-9 và A-F). Khóa bạn nhập là: ", + "message": "Chuỗi khóa bị lỗi. Chỉ có các ký tự Base32 (A-Z, 2-7 và =) và HEX (0-9 và A-F) được hỗ trợ. Chuỗi khóa bạn đã nhập là: ", "description": "Secret Error." }, "add_qr": { @@ -60,7 +60,7 @@ "description": "Issuer." }, "secret": { - "message": "Từ khóa", + "message": "Chuỗi khóa", "description": "Secret." }, "updateSuccess": { @@ -76,7 +76,7 @@ "description": "About." }, "export_import": { - "message": "Xuất \/ Nhập", + "message": "Xuất \/ Nhập dữ liệu", "description": "Export and Import." }, "settings": { @@ -84,7 +84,7 @@ "description": "Settings." }, "security": { - "message": "Bảo mật", + "message": "Đặt mật khẩu bảo vệ", "description": "Security." }, "current_phrase": { @@ -104,11 +104,11 @@ "description": "Confirm Passphrase." }, "confirm_delete": { - "message": "Bạn có chắc muốn xóa từ khóa này? Việc này không thể khôi phục lại được.", + "message": "Bạn có chắc sẽ xóa chuỗi khóa này? Sau khi xóa sẽ không thể khôi phục lại được.", "description": "Remove entry confirmation" }, "security_warning": { - "message": "Mật khẩu này sẽ được dùng để mã hóa các từ khóa của bạn. Không ai có thể khôi phục lại được nếu bạn quên mật khẩu.", + "message": "Mật khẩu này sẽ được dùng để mã hóa toàn bộ dữ liệu của bạn. Không ai có thể giúp bạn khôi phục lại mật khẩu này nếu bạn quên mật khẩu.", "description": "Passphrase Warning." }, "update": { @@ -116,15 +116,15 @@ "description": "Update." }, "phrase_incorrect": { - "message": "Bạn không thể thêm tài khoản mới hoặc xuất dữ liệu đến khi tất cả các tài khoản được giải mã hết. Xin hãy nhập đúng mật khẩu để tiếp tục.", + "message": "Bạn không thể thêm tài khoản mới hoặc trích xuất dữ liệu cho đến khi tất cả các tài khoản được giải mã. Vui lòng nhập đúng mật khẩu để tiếp tục.", "description": "Passphrase Incorrect." }, "phrase_not_match": { - "message": "Mật khẩu không khớp.", + "message": "Mật khẩu không trùng nhau.", "description": "Passphrase Not Match." }, "encrypted": { - "message": "Mã hóa", + "message": "Đã mã hóa", "description": "Encrypted." }, "copied": { @@ -132,7 +132,7 @@ "description": "Copied." }, "feedback": { - "message": "Phản hồi", + "message": "Góp ý", "description": "Feedback." }, "translate": { @@ -176,7 +176,7 @@ "description": "Counter Based" }, "resize_popup_page": { - "message": "Popup Page", + "message": "Trang Popup", "description": "Popup Page Settings" }, "scale": { @@ -244,35 +244,35 @@ "description": "Remove password." }, "download_enc_backup": { - "message": "Download Password-Protected Backup", + "message": "Tải về Bản sao lưu", "description": "Download Encrypted Backup" }, "search": { - "message": "Search", + "message": "Tìm kiếm", "description": "Search" }, "popout": { - "message": "Popup mode", + "message": "Chế độ Popup", "description": "Make window turn into persistent popup" }, "lock": { - "message": "Lock", + "message": "Khóa", "description": "Lock accounts" }, "dropbox_tooltip": { - "message": "Dropbox sync enabled", + "message": "Đã kích hoạt tự động đồng bộ với Dropbox", "description": "Dropbox sync enabled" }, "edit": { - "message": "Edit", + "message": "Điều chỉnh", "description": "Edit" }, "manual_dropbox": { - "message": "Manual Sync", + "message": "Đồng bộ thủ công", "description": "Manual Dropbox sync" }, "use_autofill": { - "message": "Use Autofill", + "message": "Chế độ Điền tự động", "description": "Use Autofill" } } \ No newline at end of file diff --git a/css/popup.css b/css/popup.css index 77261e423..65d51099f 100644 --- a/css/popup.css +++ b/css/popup.css @@ -212,7 +212,13 @@ body { #codes.filter .entry[filtered], #codes.search .entry[notSearched] { - display: none; + height: 0; + margin: 0; + padding: 0; + opacity: 0; + border: none; + overflow: hidden; + position: absolute; } #filter, @@ -332,7 +338,7 @@ body { display: block; } -#codes.timeout .code:not(.hotp) { +#codes:not(.edit) .code.timeout:not(.hotp) { animation: twinkling 1s infinite ease-in-out; } @@ -563,9 +569,35 @@ body { bottom: 10px; } +@keyframes timer { + to { + stroke-dashoffset: -25.12; + } +} + +.sector svg { + width: 16px; + height: 16px; + margin: 2px; +} + +.sector circle { + fill: none; + transform: rotate(-90deg); + transform-origin: 50% 50%; + stroke: gray; + stroke-width: 8px; + stroke-dasharray: 25.12; + animation-name: timer; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + #codes.edit .sector, #codes.edit .counter { - display: none; + position: absolute; + left: -1000px; + opacity: 0; } #menu { diff --git a/edge-files/AppXManifest.xml b/edge-files/AppXManifest.xml new file mode 100644 index 000000000..beede6866 --- /dev/null +++ b/edge-files/AppXManifest.xml @@ -0,0 +1,64 @@ + + + + + + + Authenticator Extension + mymindstorm + Assets/icon_50.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edge-files/backgroundScriptsAPIBridge.js b/edge-files/backgroundScriptsAPIBridge.js new file mode 100644 index 000000000..3947f31bb --- /dev/null +++ b/edge-files/backgroundScriptsAPIBridge.js @@ -0,0 +1,1068 @@ +try { + if (!Range.prototype.hasOwnProperty("intersectsNode")) { + Range.prototype["intersectsNode"] = function (node) { + let range = document.createRange(); + range.selectNode(node); + return 0 > this.compareBoundaryPoints(Range.END_TO_START, range) + && 0 < this.compareBoundaryPoints(Range.START_TO_END, range); + }; + } +} +catch (e) { } +try { + if (!Navigator.prototype.hasOwnProperty("languages")) { + Navigator.prototype["languages"] = [navigator.language]; + } +} +catch (e) { } +var getExtensionProtocol = function () { + if (typeof browser == "undefined") { + if (typeof chrome !== "undefined") + return "chrome-extension://"; + } + else { + return "ms-browser-extension://"; + } +}; +class BridgeAlarmEvent { + constructor() { + this.listeners = new Array(); + } + addListener(callback) { + this.listeners.push(callback); + } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return this.listeners.length > 0; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeAlarms { + constructor() { + this.alarms = {}; + this.onAlarm = new BridgeAlarmEvent(); + } + create(name, alarmInfo) { + if (arguments.length < 1 || arguments.length > 2) { + throw "Unexpected set of arguments. Expecting (alarmInfo) or (name, alarmInfo)"; + } + var alarmName = ""; + var startMilliseconds = 0; + var startSet = false; + if (typeof name === "string") { + alarmName = name; + } + else if (typeof name === "object") { + alarmInfo = name; + } + else + throw "Unexpected set of arguments. Expecting (alarmInfo) or (name, alarmInfo)"; + if (!alarmInfo) { + throw "You must specify an alarmInfo argument!!"; + } + if (!alarmInfo.when && !alarmInfo.delayInMinutes && !alarmInfo.periodInMinutes) { + throw "Invalid alarmInfo argument!!"; + } + else if (alarmInfo.when && alarmInfo.delayInMinutes) { + throw "Invalid alarmInfo argument!! Either 'when' or 'delayInMinutes' but not both!!"; + } + else if (alarmInfo.when) { + startMilliseconds = alarmInfo.when; + startSet = true; + } + else if (alarmInfo.delayInMinutes) { + startMilliseconds = alarmInfo.delayInMinutes * 60 * 1000; + startSet = true; + } + else if (alarmInfo.periodInMinutes) { + startMilliseconds = alarmInfo.periodInMinutes * 60 * 1000; + startSet = true; + } + else + throw "Invalid alarmInfo argument!!"; + var timerHandle; + if (startSet) { + if (this.alarms[alarmName]) { + this.clearAlarm(alarmName); + } + var alarm = { name: alarmName, scheduledTime: Date.now() + startMilliseconds }; + var alarmAndHandle = { alarm: alarm, timerHandle: 0, startedInterval: false }; + this.alarms[alarmName] = alarmAndHandle; + if (alarmInfo.periodInMinutes) { + this.alarms[alarmName].alarm.periodInMinutes = alarmInfo.periodInMinutes; + this.alarms[alarmName].timerHandle = window.setTimeout(function (alarmName, that) { + that.soundAlarm(alarmName, that); + that.alarms[alarmName].timerHandle = window.setInterval(that.soundAlarm, alarmInfo.periodInMinutes * 60 * 1000, alarmName, that); + that.alarms[alarmName].startedInterval = true; + }, startMilliseconds, alarmName, this); + } + else { + this.alarms[alarmName].timerHandle = window.setTimeout(this.soundAlarm, startMilliseconds, alarmName, this); + } + } + } + getAll(callback) { + for (var key in this.alarms) { + if (this.alarms.hasOwnProperty(key)) { + var alarm = this.alarms[key].alarm; + callback(alarm); + } + } + } + clearAll(callback) { + var clearedAll = true; + for (var key in this.alarms) { + if (this.alarms.hasOwnProperty(key)) { + var alarm = this.alarms[key].alarm; + if (!this.clearAlarm(alarm.name)) { + clearedAll = false; + } + } + } + if (callback) { + callback(clearedAll); + } + } + clear(name, callback) { + var alarmName = ""; + if (typeof name === "string") { + alarmName = name; + } + else if (typeof name === "function") { + callback = name; + } + var wasCleared = this.clearAlarm(alarmName); + if (callback) { + callback(wasCleared); + } + } + get(name, callback) { + if (this.alarms.hasOwnProperty(name)) { + var alarm = this.alarms[name].alarm; + callback(alarm); + } + } + clearAlarm(name) { + var wasCleared = false; + if (this.alarms[name]) { + if (this.alarms[name].alarm.startedInterval) { + window.clearInterval(this.alarms[name].timerHandle); + } + else { + window.clearTimeout(this.alarms[name].timerHandle); + } + delete this.alarms[name]; + wasCleared = true; + } + return wasCleared; + } + soundAlarm(name, that) { + for (var index = 0; index < that.onAlarm.listeners.length; index++) { + var listener = that.onAlarm.listeners[index]; + listener({ name: name }); + } + } +} +class FakeEvent { + addListener(callback) { } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return false; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeHelper { + constructor() { + this.fakeEvent = new FakeEvent(); + this.alarms = new EdgeBridgeAlarms(); + } + toAbsolutePath(relativePath) { + if (relativePath.indexOf("ms-browser-extension://") == 0) { + return relativePath.replace(myBrowser.runtime.getURL(""), ""); + } + else if (relativePath.indexOf("/") != 0) { + var absolutePath = ""; + var documentPath = document.location.pathname; + absolutePath = documentPath.substring(0, documentPath.lastIndexOf("/") + 1); + absolutePath += relativePath; + return absolutePath; + } + return relativePath; + } +} +var bridgeHelper = new EdgeBridgeHelper(); +class EdgeBridgeDebugLog { + constructor() { + this.CatchOnException = true; + this.VerboseLogging = true; + this.FailedCalls = {}; + this.SuccededCalls = {}; + this.DeprecatedCalls = {}; + this.BridgedCalls = {}; + this.UnavailableApis = {}; + this.EdgeIssues = {}; + } + log(message) { + try { + if (this.VerboseLogging) { + console.log(message); + } + } + catch (e) { + } + } + info(message) { + try { + if (this.VerboseLogging) { + console.info(message); + } + } + catch (e) { + } + } + warn(message) { + try { + if (this.VerboseLogging) { + console.warn(message); + } + } + catch (e) { + } + } + error(message) { + try { + if (this.VerboseLogging) { + console.error(message); + } + } + catch (e) { + } + } + DoActionAndLog(action, name, deprecatedTo, bridgedTo) { + var result; + try { + result = action(); + this.AddToCalledDictionary(this.SuccededCalls, name); + if (typeof deprecatedTo !== "undefined") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + if (typeof bridgedTo !== "undefined") { + this.info("API Call '" + name + "' has been bridged to another Edge API: " + bridgedTo); + this.AddToCalledDictionary(this.BridgedCalls, name); + } + this.info("API Call: '" + name + "'"); + return result; + } + catch (ex) { + this.AddToCalledDictionary(this.FailedCalls, name); + if (this.CatchOnException) + this.error("API Call Failed: " + name + " - " + ex); + else + throw ex; + } + } + LogEdgeIssue(name, message) { + this.warn(message); + this.AddToCalledDictionary(this.EdgeIssues, name); + } + LogUnavailbleApi(name, deprecatedTo) { + this.warn("API Call '" + name + "' is not supported in Edge"); + this.AddToCalledDictionary(this.UnavailableApis, name); + if (typeof deprecatedTo !== "undefined") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + } + AddToCalledDictionary(dictionary, name) { + if (typeof dictionary[name] !== "undefined") { + dictionary[name]++; + } + else { + dictionary[name] = 1; + } + } +} +var bridgeLog = new EdgeBridgeDebugLog(); +class EdgeChromeAlarmBridge { + get onAlarm() { + return bridgeLog.DoActionAndLog(() => { + return bridgeHelper.alarms.onAlarm; + }, "alarms.onAlarm", undefined, "bridgeHelper.alarms.onAlarm"); + } + create(name, alarmInfo) { + bridgeLog.DoActionAndLog(() => { + bridgeHelper.alarms.create.apply(null, arguments); + }, "alarms.create", undefined, "bridgeHelper.alarms.create"); + } + getAll(callback) { + bridgeLog.DoActionAndLog(() => { + bridgeHelper.alarms.getAll.apply(null, arguments); + }, "alarms.getAll", undefined, "bridgeHelper.alarms.getAll"); + } + clearAll(callback) { + bridgeLog.DoActionAndLog(() => { + bridgeHelper.alarms.clearAll.apply(null, arguments); + }, "alarms.clearAll", undefined, "bridgeHelper.alarms.clearAll"); + } + clear(name, callback) { + bridgeLog.DoActionAndLog(() => { + bridgeHelper.alarms.clear.apply(null, arguments); + }, "alarms.clear", undefined, "bridgeHelper.alarms.clear"); + } + get(name, callback) { + bridgeLog.DoActionAndLog(() => { + bridgeHelper.alarms.get.apply(null, arguments); + }, "alarms.get", undefined, "bridgeHelper.alarms.get"); + } +} +class EdgeChromeAppBridge { + getDetails() { + return bridgeLog.DoActionAndLog(() => { + return EdgeChromeRuntimeBridge.prototype.getManifest.apply(null, arguments); + }, "app.getManifest", undefined, "runtime.getManifest"); + } + get isInstalled() { return bridgeLog.DoActionAndLog(() => { throw "app.isInstalled is not available in Edge"; }, "app.isInstalled"); } + getIsInstalled() { return bridgeLog.DoActionAndLog(() => { throw "app.getIsInstalled is not available in the Edge"; }, "app.getIsInstalled"); } + installState() { return bridgeLog.DoActionAndLog(() => { throw "app.installState is not available in Edge"; }, "app.installState"); } + runningState() { return bridgeLog.DoActionAndLog(() => { throw "app.runningState is not available in Edge"; }, "app.runningState"); } +} +class EdgeBookmarksBridge { + create(bookmark, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.create.apply(null, arguments); + }, "bookmarks.create"); + } + getTree(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.getTree.apply(null, arguments); + }, "bookmarks.getTree"); + } + move(id, destination, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.move.apply(null, arguments); + }, "bookmarks.move"); + } + remove(id, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.remove.apply(null, arguments); + }, "bookmarks.remove"); + } + removeTree(id, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.removeTree.apply(null, arguments); + }, "bookmarks.removeTree"); + } + update(id, changes, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.bookmarks.update.apply(null, arguments); + }, "bookmarks.update"); + } +} +class EdgeChromeBookmarksBridge extends EdgeBookmarksBridge { + get onRemoved() { bridgeLog.LogUnavailbleApi("bookmarks.onRemoved"); return bridgeHelper.fakeEvent; } + get onImportEnded() { bridgeLog.LogUnavailbleApi("bookmarks.onImportEnded"); return bridgeHelper.fakeEvent; } + get onImportBegan() { bridgeLog.LogUnavailbleApi("bookmarks.onImportBegan"); return bridgeHelper.fakeEvent; } + get onChanged() { bridgeLog.LogUnavailbleApi("bookmarks.onChanged"); return bridgeHelper.fakeEvent; } + get onMoved() { bridgeLog.LogUnavailbleApi("bookmarks.onMoved"); return bridgeHelper.fakeEvent; } + get onCreated() { bridgeLog.LogUnavailbleApi("bookmarks.onCreated"); return bridgeHelper.fakeEvent; } + get onChildrenReordered() { bridgeLog.LogUnavailbleApi("bookmarks.onChildrenReordered"); return bridgeHelper.fakeEvent; } + getRecent(numberOfItems, callback) { + bridgeLog.LogUnavailbleApi("bookmarks.getRecent"); + } + get(idList, callback) { + bridgeLog.LogUnavailbleApi("bookmarks.get"); + } + getChildren(id, callback) { + bridgeLog.LogUnavailbleApi("bookmarks.getChildren"); + } + getSubTree(id, callback) { + bridgeLog.LogUnavailbleApi("bookmarks.getSubTree"); + } + search(query, callback) { + bridgeLog.LogUnavailbleApi("bookmarks.search"); + } +} +class EdgeBrowserActionBridge { + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.browserAction.onClicked; }, "browserAction.onClicked"); } + disable(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.disable.apply(null, arguments); + }, "browserAction.disable"); + } + enable(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.enable.apply(null, arguments); + }, "browserAction.Enable"); + } + getBadgeBackgroundColor(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getBadgeBackgroundColor.apply(null, arguments); + }, "browserAction.getBadgeBackgroundColor"); + } + getBadgeText(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getBadgeText.apply(null, arguments); + ; + }, "browserAction.getBadgeText"); + } + getPopup(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getPopup.apply(null, arguments); + }, "browserAction.getPopup"); + } + getTitle(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getTitle.apply(null, arguments); + }, "browserAction.getTitle"); + } + setBadgeBackgroundColor(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setBadgeBackgroundColor.apply(null, arguments); + }, "browserAction.setBadgeBackgroundColor"); + } + setBadgeText(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setBadgeText.apply(null, arguments); + }, "browserAction.setBadgeText"); + } + setIcon(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setIcon.apply(null, arguments); + }, "browserAction.setIcon"); + } + setPopup(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setPopup.apply(null, arguments); + }, "browserAction.setPopup"); + } + setTitle(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setTitle.apply(null, arguments); + }, "browserAction.setTitle"); + } +} +class EdgeChromeBrowserActionBridge extends EdgeBrowserActionBridge { + getPopup(details, callback) { + if (myBrowser.browserAction.getPopup) { + EdgeBrowserActionBridge.prototype.getPopup.apply(null, arguments); + } + else { + bridgeLog.LogUnavailbleApi("browserAction.getPopup"); + } + } + getTitle(details, callback) { + if (myBrowser.browserAction.getTitle) { + EdgeBrowserActionBridge.prototype.getTitle.apply(null, arguments); + } + else { + bridgeLog.LogUnavailbleApi("browserAction.getTitle"); + } + } + setTitle(details) { + if (myBrowser.browserAction.setTitle) { + EdgeBrowserActionBridge.prototype.setTitle.apply(null, arguments); + } + else { + bridgeLog.LogUnavailbleApi("browserAction.setTitle"); + } + } +} +class EdgeChromeCommandsBridge { + get onCommand() { bridgeLog.LogUnavailbleApi("commands.onCommand"); return bridgeHelper.fakeEvent; } + getAll(callback) { + bridgeLog.LogUnavailbleApi("commands.getAll"); + } +} +class EdgeContextMenusBridge { + get ACTION_MENU_TOP_LEVEL_LIMIT() { return bridgeLog.DoActionAndLog(() => { return myBrowser.contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT; }, "contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT"); } + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.contextMenus.onClicked; }, "contextMenus.onClicked"); } + create(createProperties, callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.contextMenus.create.apply(null, arguments); + }, "contextMenus.create"); + } + remove(menuItemId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.contextMenus.remove.apply(null, arguments); + }, "contextMenus.remove"); + } + removeAll(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.contextMenus.removeAll.apply(null, arguments); + }, "contextMenus.removeAll"); + } + update(id, updateProperties, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.contextMenus.update.apply(null, arguments); + }, "contextMenus.update"); + } +} +class EdgeCookiesBridge { + get(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.get.apply(null, arguments); + }, "cookies.get"); + } + getAll(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.getAll.apply(null, arguments); + }, "cookies.getAll"); + } + remove(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.remove.apply(null, arguments); + }, "cookies.remove"); + } + set(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.set.apply(null, arguments); + }, "cookies.set"); + } +} +class EdgeChromeCookiesBridge extends EdgeCookiesBridge { + get onChanged() { bridgeLog.LogUnavailbleApi("cookies.onChanged"); return bridgeHelper.fakeEvent; } +} +class EdgeExtensionBridge { + get inIncognitoContext() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.inIncognitoContext; + }, "extension.inIncognitoContext"); + } + getBackgroundPage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getBackgroundPage.apply(null, arguments); + }, "extension.getBackgroundPage"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getURL.apply(null, arguments); + }, "extension.getURL"); + } + getViews(fetchProperties) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getViews.apply(null, arguments); + }, "extension.getViews"); + } + isAllowedIncognitoAccess(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.isAllowedIncognitoAccess.apply(null, arguments); + }, "extension.isAllowedIncognitoAccess"); + } +} +class EdgeChromeExtensionBridge extends EdgeExtensionBridge { + get onConnect() { return bridgeLog.DoActionAndLog(() => { return EdgeRuntimeBridge.prototype.onConnect; }, "extension.onConnect", "runtime.onConnect", "runtime.onConnect"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onMessage", "runtime.onMessage", "runtime.onMessage"); } + get onRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onRequest", "runtime.onMessage", "runtime.onMessage"); } + get onRequestExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "extension.onRequestExternal", "runtime.onMessageExternal", "runtime.onMessageExternal"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "extension.lastError", undefined, "runtime.lastError"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.connect.apply(null, arguments); + }, "extension.connect", "runtime.connect", "runtime.connect"); + } + sendMessage(message, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage.apply(null, arguments); + }, "extension.sendMessage", "runtime.sendMessage", "runtime.sendMessage"); + } + sendRequest(extensionId, message, options, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage.apply(null, arguments); + }, "extension.sendRequest", "runtime.sendMessage", "runtime.sendMessage"); + } + isAllowedFileSchemeAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedFileSchemeAccess"); + } + setUpdateUrlData(data) { + bridgeLog.LogUnavailbleApi("extension.setUpdateUrlData"); + } +} +class EdgeHistoryBridge { + get onVisited() { bridgeLog.LogUnavailbleApi("history.onVisited"); return bridgeHelper.fakeEvent; } + get onVisitRemoved() { bridgeLog.LogUnavailbleApi("history.onVisitRemoved"); return bridgeHelper.fakeEvent; } + addUrl(details, callback) { + bridgeLog.LogUnavailbleApi("history.addUrl"); + } + deleteAll(callback) { + bridgeLog.LogUnavailbleApi("history.deleteAll"); + } + deleteRange(range, callback) { + bridgeLog.LogUnavailbleApi("history.deleteRange"); + } + deleteUrl(details, callback) { + bridgeLog.LogUnavailbleApi("history.deleteUrl"); + } + getVisits(details, callback) { + bridgeLog.LogUnavailbleApi("history.getVisits"); + } + search(query, callback) { + bridgeLog.LogUnavailbleApi("history.search"); + } +} +class EdgeI18nBridge { + getAcceptLanguages(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getAcceptLanguages.apply(null, arguments); + }, "i18n.getAcceptLanguages"); + } + getMessage(messageName, substitutions) { + return bridgeLog.DoActionAndLog(() => { + if (messageName.indexOf("@@extension_id") > -1) { + return myBrowser.runtime.id; + } + return myBrowser.i18n.getMessage.apply(null, arguments); + }, "i18n.getMessage"); + } + getUILanguage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getUILanguage.apply(null, arguments); + }, "i18n.getUILanguage"); + } +} +class EdgeChromeIdleBridge { + get onStateChanged() { bridgeLog.LogUnavailbleApi("idle.onStateChanged"); return bridgeHelper.fakeEvent; } + queryState(detectionIntervalInSeconds, callback) { + bridgeLog.LogUnavailbleApi("idle.queryState"); + } + setDetectionInterval(intervalInSeconds) { + bridgeLog.LogUnavailbleApi("idle.setDetectionInterval"); + } +} +class EdgeNotificationBridge { + get onButtonClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.notifications.onButtonClicked; }, "notifications.onButtonClicked"); } + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.notifications.onClicked; }, "notifications.onClicked"); } + get onClosed() { return bridgeLog.DoActionAndLog(() => { return myBrowser.notifications.onClosed; }, "notifications.onClosed"); } + get onPermissionLevelChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.notifications.onPermissionLevelChanged; }, "notifications.onPermissionLevelChanged"); } + get onShowSettings() { bridgeLog.LogUnavailbleApi("notifications.onShowSettings"); return bridgeHelper.fakeEvent; } + clear(notificationId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.notifications.clear.apply(null, arguments); + }, "notifications.clear"); + } + create(notificationId, options, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.notifications.create.apply(null, arguments); + }, "notifications.create"); + } + getAll(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.notifications.getAll.apply(null, arguments); + }, "notifications.getAll"); + } + getPermissionLevel(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.notifications.getPermissionLevel.apply(null, arguments); + }, "notifications.getPermissionLevel"); + } + update(notificationId, options, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.notifications.update.apply(null, arguments); + }, "notifications.update"); + } +} +class EdgePageActionBridge { + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.pageAction.onClicked; }, "pageAction.onClicked"); } + getPopup(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.getPopup.apply(null, arguments); + }, "pageAction.getPopup"); + } + getTitle(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.getTitle.apply(null, arguments); + }, "pageAction.getTitle"); + } + hide(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.hide.apply(null, arguments); + }, "pageAction.hide"); + } + setTitle(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.setTitle.apply(null, arguments); + }, "pageAction.setTitle"); + } + setIcon(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.setIcon.apply(null, arguments); + }, "pageAction.setIcon"); + } + setPopup(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.setPopup.apply(null, arguments); + }, "pageAction.setPopup"); + } + show(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.show.apply(null, arguments); + }, "pageAction.show"); + } +} +class EdgePermissionsBridge { + get onAdded() { bridgeLog.LogUnavailbleApi("permissions.onAdded"); return bridgeHelper.fakeEvent; } + get onRemoved() { bridgeLog.LogUnavailbleApi("permissions.onRemoved"); return bridgeHelper.fakeEvent; } + contains(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.contains"); + } + getAll(callback) { + bridgeLog.LogUnavailbleApi("permissions.getAll"); + } + remove(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.remove"); + } + request(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.request"); + } +} +class EdgeRuntimeBridge { + get id() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.id; }, "runtime.id"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "runtime.lastError"); } + get onConnect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onConnect; }, "runtime.onConnect"); } + get onInstalled() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onInstalled; }, "runtime.onInstalled"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "runtime.onMessage"); } + get onMessageExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "runtime.onMessageExternal"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.connect.apply(null, arguments); + }, "runtime.connect"); + } + connectNative(application) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.connectNative.apply(null, arguments); + }, "runtime.connectNative"); + } + getBackgroundPage(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.getBackgroundPage.apply(null, arguments); + }, "runtime.getBackgroundPage"); + } + getManifest() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getManifest.apply(null, arguments); + }, "runtime.getManifest"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getURL.apply(null, arguments); + }, "runtime.getURL"); + } + reload() { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.reload.apply(null, arguments); + }, "runtime.reload"); + } + sendMessage(extensionId, message, options, responseCallback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.sendMessage.apply(null, arguments); + }, "runtime.sendMessage"); + } + sendNativeMessage(application, message, responseCallback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.sendNativeMessage.apply(null, arguments); + }, "runtime.sendNativeMessage"); + } + setUninstallURL(url, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.setUninstallURL.apply(null, arguments); + }, "runtime.setUninstallURL"); + } +} +class EdgeChromeRuntimeBridge extends EdgeRuntimeBridge { + get onConnectExternal() { bridgeLog.LogUnavailbleApi("runtime.onConnectExternal"); return bridgeHelper.fakeEvent; } + get onRestartRequired() { bridgeLog.LogUnavailbleApi("runtime.onRestartRequired"); return bridgeHelper.fakeEvent; } + get onSuspend() { bridgeLog.LogUnavailbleApi("runtime.onSuspend"); return bridgeHelper.fakeEvent; } + get onSuspendCanceled() { bridgeLog.LogUnavailbleApi("runtime.onSuspendCanceled"); return bridgeHelper.fakeEvent; } + get onUpdateAvailable() { bridgeLog.LogUnavailbleApi("runtime.onUpdateAvailable"); return bridgeHelper.fakeEvent; } + get onStartup() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onCreated; }, "runtime.onStartup", undefined, "windows.onCreated"); } + openOptionsPage(callback) { + bridgeLog.DoActionAndLog(() => { + var optionsPage = myBrowser.runtime.getManifest()["options_page"]; + var optionsPageUrl = myBrowser.runtime.getURL(optionsPage); + if (typeof callback !== "undefined") { + myBrowser.tabs.create({ url: optionsPageUrl }, callback); + } + else { + myBrowser.tabs.create({ url: optionsPageUrl }); + } + }, "runtime.openOptionsPage", undefined, "tabs.create({ url: optionsPageUrl })"); + } + setUninstallURL(url, callback) { + if (myBrowser.runtime.setUninstallURL) { + EdgeRuntimeBridge.prototype.setUninstallURL.apply(null, arguments); + } + else { + bridgeLog.LogUnavailbleApi("runtime.setUninstallURL"); + } + } + getPackageDirectoryEntry(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPackageDirectoryEntry"); + } + getPlatformInfo(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPlatformInfo"); + } + requestUpdateCheck(callback) { + bridgeLog.LogUnavailbleApi("runtime.requestUpdateCheck"); + } + restart() { + bridgeLog.LogUnavailbleApi("runtime.restart"); + } +} +class EdgeStorageBridge { + get local() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.local"); } + get sync() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.sync; }, "storage.sync"); } + get onChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.onChanged; }, "storage.onChanged"); } +} +class EdgeChromeStorageBridge extends EdgeStorageBridge { + get sync() { + if (myBrowser.storage.sync) { + return EdgeStorageBridge.prototype.sync; + } + else { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.storage.local; + }, "storage.sync", undefined, "storage.local"); + } + } + get managed() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.managed", undefined, "storage.local"); } +} +class EdgeTabsBridge { + get onActivated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onActivated; }, "tabs.onActivated"); } + get onAttached() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onAttached; }, "tabs.onAttached"); } + get onCreated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onCreated; }, "tabs.onCreated"); } + get onDetached() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onDetached; }, "tabs.onDetached"); } + get onRemoved() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onRemoved; }, "tabs.onRemoved"); } + get onReplaced() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onReplaced; }, "tabs.onReplaced"); } + get onUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onUpdated; }, "tabs.onUpdated"); } + captureVisibleTab(windowId, options, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.captureVisibleTab.apply(null, arguments); + }, "tabs.captureVisibleTab"); + } + create(createProperties, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.create.apply(null, arguments); + }, "tabs.create"); + } + detectLanguage(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.detectLanguage.apply(null, arguments); + }, "tabs.detectLanguage"); + } + executeScript(tabId, details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.executeScript.apply(null, arguments); + }, "tabs.executeScript"); + } + get(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.get.apply(null, arguments); + }, "tabs.get"); + } + getCurrent(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.getCurrent.apply(null, arguments); + }, "tabs.getCurrent"); + } + insertCSS(tabId, details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.insertCSS.apply(null, arguments); + }, "tabs.insertCSS"); + } + query(queryInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.query.apply(null, arguments); + }, "tabs.query"); + } + reload(tabId, reloadProperties, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.reload.apply(null, arguments); + }, "tabs.reload"); + } + remove(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.remove.apply(null, arguments); + }, "tabs.remove"); + } + sendMessage(tabId, message, responseCallback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.sendMessage.apply(null, arguments); + }, "tabs.sendMessage"); + } + update(tabId, updateProperties, callback) { + var updatePropertiesBridged = false; + for (var index = 0; index < arguments.length; index++) { + var argument = arguments[index]; + if (typeof argument === "object") { + if (!argument.active && (argument.highlighted || argument.selected)) { + argument.active = argument.highlighted || argument.selected; + updatePropertiesBridged = true; + } + } + } + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.update.apply(null, arguments); + }, "tabs.update", undefined, updatePropertiesBridged ? "tabs.update with UpdateProperties modified" : undefined); + } +} +class EdgeChromeTabsBridge extends EdgeTabsBridge { + get onHighlighted() { bridgeLog.LogUnavailbleApi("tabs.onHighlighted"); return bridgeHelper.fakeEvent; } + get onMoved() { bridgeLog.LogUnavailbleApi("tabs.onMoved"); return bridgeHelper.fakeEvent; } + get onSelectionChanged() { + return bridgeLog.DoActionAndLog(() => { + var fakeEvent = bridgeHelper.fakeEvent; + fakeEvent.addListener = (callback) => { + myBrowser.tabs.onActivated.addListener((activeInfo) => { + callback(activeInfo.tabId, { windowId: activeInfo.windowId }); + }); + }; + return fakeEvent; + }, "tabs.onSelectionChanged", "tabs.onActivated", "tabs.onActivated"); + } + duplicate(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + var tabGetCallback = function (tab) { + if (typeof callback !== "undefined") { + myBrowser.tabs.create({ url: tab.url }, callback); + } + else { + myBrowser.tabs.create({ url: tab.url }); + } + }; + EdgeTabsBridge.prototype.get(tabId, tabGetCallback); + }, "tabs.duplicate", undefined, "tabs.create"); + } + getAllInWindow(windowId, callback) { + bridgeLog.DoActionAndLog(() => { + EdgeTabsBridge.prototype.query({ windowId: windowId }, callback); + }, "tabs.getAllInWindow", "tabs.query", "tabs.query"); + } + getSelected(windowId, callback) { + bridgeLog.DoActionAndLog(() => { + EdgeTabsBridge.prototype.query({ active: true }, (tabs) => callback(tabs[0])); + }, "tabs.getSelected", "tabs.query", "tabs.query"); + } + sendRequest(tabId, request, responseCallback) { + bridgeLog.DoActionAndLog(() => { + EdgeTabsBridge.prototype.sendMessage.apply(null, arguments); + }, "tabs.sendRequest", "tabs.sendMessage", "tabs.sendMessage"); + } + connect(tabId, connectInfo) { + bridgeLog.LogUnavailbleApi("tabs.connect"); + return null; + } + highlight(highlightInfo, callback) { + bridgeLog.LogUnavailbleApi("tabs.highlight"); + } + move(tabId, moveProperties, callback) { + bridgeLog.LogUnavailbleApi("tabs.move"); + } +} +class EdgeWebNavigationBridge { + get onBeforeNavigate() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onBeforeNavigate; }, "webNavigation.onBeforeNavigate"); } + get onCommitted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCommitted; }, "webNavigation.onCommitted"); } + get onCompleted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCompleted; }, "webNavigation.onCompleted"); } + get onCreatedNavigationTarget() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCreatedNavigationTarget; }, "webNavigation.onCreatedNavigationTarget"); } + get onDOMContentLoaded() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onDOMContentLoaded; }, "webNavigation.onDOMContentLoaded"); } + get onErrorOccurred() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onErrorOccurred; }, "webNavigation.onErrorOccurred"); } + get onHistoryStateUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onHistoryStateUpdated; }, "webNavigation.onHistoryStateUpdated"); } + get onReferenceFragmentUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onReferenceFragmentUpdated; }, "webNavigation.onReferenceFragmentUpdated"); } + get onTabReplaced() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onTabReplaced; }, "webNavigation.onTabReplaced"); } + getAllFrames(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.webNavigation.getAllFrames.apply(null, arguments); + }, "webNavigation.getAllFrames"); + } + getFrame(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.webNavigation.getFrame.apply(null, arguments); + }, "webNavigation.getFrame"); + } +} +class EdgeWebRequestBridge { + get MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; }, "webNavigation.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"); } + get onAuthRequired() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onAuthRequired; }, "webRequest.onAuthRequired"); } + get onBeforeRedirect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeRedirect; }, "webRequest.onBeforeRedirect"); } + get onBeforeRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeRequest; }, "webRequest.onBeforeRequest"); } + get onBeforeSendHeaders() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeSendHeaders; }, "webRequest.onBeforeSendHeaders"); } + get onCompleted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onCompleted; }, "webRequest.onCompleted"); } + get onErrorOccurred() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onErrorOccurred; }, "webRequest.onErrorOccurred"); } + get onHeadersReceived() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onHeadersReceived; }, "webRequest.onHeadersReceived"); } + get onResponseStarted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onResponseStarted; }, "webRequest.onResponseStarted"); } + get onSendHeaders() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onSendHeaders; }, "webRequest.onSendHeaders"); } + handlerBehaviorChanged(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.webRequest.handlerBehaviorChanged.apply(null, arguments); + }, "webRequest.handlerBehaviorChanged"); + } +} +class EdgeWindowsBridge { + get WINDOW_ID_CURRENT() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.WINDOW_ID_CURRENT; }, "windows.WINDOW_ID_CURRENT"); } + get WINDOW_ID_NONE() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.WINDOW_ID_NONE; }, "windows.WINDOW_ID_NONE"); } + get onCreated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onCreated; }, "windows.onCreated"); } + get onFocusChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onFocusChanged; }, "windows.onFocusChanged"); } + get onRemoved() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onRemoved; }, "windows.onRemoved"); } + create(createData, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.create.apply(null, arguments); + }, "windows.create"); + } + get(windowId, getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.get.apply(null, arguments); + }, "windows.get"); + } + getAll(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getAll.apply(null, arguments); + }, "windows.getAll"); + } + getCurrent(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getCurrent.apply(null, arguments); + }, "windows.getCurrent"); + } + getLastFocused(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getLastFocused.apply(null, arguments); + }, "windows.getLastFocused"); + } + update(windowId, updateInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.update.apply(null, arguments); + }, "windows.update"); + } +} +class EdgeChromeWindowsBridge extends EdgeWindowsBridge { + remove(windowId, callback) { + bridgeLog.LogUnavailbleApi("windows.remove"); + } +} +class EdgeBackgroundBridge { + constructor() { + this.alarms = new EdgeChromeAlarmBridge(); + this.app = new EdgeChromeAppBridge(); + this.commands = new EdgeChromeCommandsBridge(); + this.idle = new EdgeChromeIdleBridge(); + this.notifications = new EdgeNotificationBridge(); + this.bookmarks = typeof browser["bookmarks"] !== "undefined" ? new EdgeChromeBookmarksBridge() : undefined; + this.browserAction = typeof browser.browserAction !== "undefined" ? new EdgeChromeBrowserActionBridge() : undefined; + this.contextMenus = typeof browser.contextMenus !== "undefined" ? new EdgeContextMenusBridge() : undefined; + this.cookies = typeof browser.cookies !== "undefined" ? new EdgeChromeCookiesBridge() : undefined; + this.extension = typeof browser.extension !== "undefined" ? new EdgeChromeExtensionBridge() : undefined; + this.history = typeof browser.history !== "undefined" ? new EdgeHistoryBridge() : undefined; + this.i18n = typeof browser.i18n !== "undefined" ? new EdgeI18nBridge() : undefined; + this.pageAction = typeof browser.pageAction !== "undefined" ? new EdgePageActionBridge() : undefined; + this.permissions = typeof browser.permissions !== "undefined" ? new EdgePermissionsBridge() : undefined; + this.runtime = typeof browser.runtime !== "undefined" ? new EdgeChromeRuntimeBridge() : undefined; + this.storage = typeof browser.storage !== "undefined" ? new EdgeChromeStorageBridge() : undefined; + this.tabs = typeof browser.tabs !== "undefined" ? new EdgeChromeTabsBridge() : undefined; + this.webNavigation = typeof browser.webNavigation !== "undefined" ? new EdgeWebNavigationBridge() : undefined; + this.webRequest = typeof browser.webRequest !== "undefined" ? new EdgeWebRequestBridge() : undefined; + this.windows = typeof browser.windows !== "undefined" ? new EdgeChromeWindowsBridge() : undefined; + } +} +var myBrowser = browser; +var chrome = new EdgeBackgroundBridge(); diff --git a/edge-files/contentScriptsAPIBridge.js b/edge-files/contentScriptsAPIBridge.js new file mode 100644 index 000000000..0a84c346b --- /dev/null +++ b/edge-files/contentScriptsAPIBridge.js @@ -0,0 +1,484 @@ +try { + if (!Range.prototype.hasOwnProperty("intersectsNode")) { + Range.prototype["intersectsNode"] = function (node) { + let range = document.createRange(); + range.selectNode(node); + return 0 > this.compareBoundaryPoints(Range.END_TO_START, range) + && 0 < this.compareBoundaryPoints(Range.START_TO_END, range); + }; + } +} +catch (e) { } +try { + if (!Navigator.prototype.hasOwnProperty("languages")) { + Navigator.prototype["languages"] = [navigator.language]; + } +} +catch (e) { } +var getExtensionProtocol = function () { + if (typeof browser == "undefined") { + if (typeof chrome !== "undefined") + return "chrome-extension://"; + } + else { + return "ms-browser-extension://"; + } +}; +class BridgeAlarmEvent { + constructor() { + this.listeners = new Array(); + } + addListener(callback) { + this.listeners.push(callback); + } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return this.listeners.length > 0; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeAlarms { + constructor() { + this.alarms = {}; + this.onAlarm = new BridgeAlarmEvent(); + } + create(name, alarmInfo) { + if (arguments.length < 1 || arguments.length > 2) { + throw "Unexpected set of arguments. Expecting (alarmInfo) or (name, alarmInfo)"; + } + var alarmName = ""; + var startMilliseconds = 0; + var startSet = false; + if (typeof name === "string") { + alarmName = name; + } + else if (typeof name === "object") { + alarmInfo = name; + } + else + throw "Unexpected set of arguments. Expecting (alarmInfo) or (name, alarmInfo)"; + if (!alarmInfo) { + throw "You must specify an alarmInfo argument!!"; + } + if (!alarmInfo.when && !alarmInfo.delayInMinutes && !alarmInfo.periodInMinutes) { + throw "Invalid alarmInfo argument!!"; + } + else if (alarmInfo.when && alarmInfo.delayInMinutes) { + throw "Invalid alarmInfo argument!! Either 'when' or 'delayInMinutes' but not both!!"; + } + else if (alarmInfo.when) { + startMilliseconds = alarmInfo.when; + startSet = true; + } + else if (alarmInfo.delayInMinutes) { + startMilliseconds = alarmInfo.delayInMinutes * 60 * 1000; + startSet = true; + } + else if (alarmInfo.periodInMinutes) { + startMilliseconds = alarmInfo.periodInMinutes * 60 * 1000; + startSet = true; + } + else + throw "Invalid alarmInfo argument!!"; + var timerHandle; + if (startSet) { + if (this.alarms[alarmName]) { + this.clearAlarm(alarmName); + } + var alarm = { name: alarmName, scheduledTime: Date.now() + startMilliseconds }; + var alarmAndHandle = { alarm: alarm, timerHandle: 0, startedInterval: false }; + this.alarms[alarmName] = alarmAndHandle; + if (alarmInfo.periodInMinutes) { + this.alarms[alarmName].alarm.periodInMinutes = alarmInfo.periodInMinutes; + this.alarms[alarmName].timerHandle = window.setTimeout(function (alarmName, that) { + that.soundAlarm(alarmName, that); + that.alarms[alarmName].timerHandle = window.setInterval(that.soundAlarm, alarmInfo.periodInMinutes * 60 * 1000, alarmName, that); + that.alarms[alarmName].startedInterval = true; + }, startMilliseconds, alarmName, this); + } + else { + this.alarms[alarmName].timerHandle = window.setTimeout(this.soundAlarm, startMilliseconds, alarmName, this); + } + } + } + getAll(callback) { + for (var key in this.alarms) { + if (this.alarms.hasOwnProperty(key)) { + var alarm = this.alarms[key].alarm; + callback(alarm); + } + } + } + clearAll(callback) { + var clearedAll = true; + for (var key in this.alarms) { + if (this.alarms.hasOwnProperty(key)) { + var alarm = this.alarms[key].alarm; + if (!this.clearAlarm(alarm.name)) { + clearedAll = false; + } + } + } + if (callback) { + callback(clearedAll); + } + } + clear(name, callback) { + var alarmName = ""; + if (typeof name === "string") { + alarmName = name; + } + else if (typeof name === "function") { + callback = name; + } + var wasCleared = this.clearAlarm(alarmName); + if (callback) { + callback(wasCleared); + } + } + get(name, callback) { + if (this.alarms.hasOwnProperty(name)) { + var alarm = this.alarms[name].alarm; + callback(alarm); + } + } + clearAlarm(name) { + var wasCleared = false; + if (this.alarms[name]) { + if (this.alarms[name].alarm.startedInterval) { + window.clearInterval(this.alarms[name].timerHandle); + } + else { + window.clearTimeout(this.alarms[name].timerHandle); + } + delete this.alarms[name]; + wasCleared = true; + } + return wasCleared; + } + soundAlarm(name, that) { + for (var index = 0; index < that.onAlarm.listeners.length; index++) { + var listener = that.onAlarm.listeners[index]; + listener({ name: name }); + } + } +} +class FakeEvent { + addListener(callback) { } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return false; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeHelper { + constructor() { + this.fakeEvent = new FakeEvent(); + this.alarms = new EdgeBridgeAlarms(); + } + toAbsolutePath(relativePath) { + if (relativePath.indexOf("ms-browser-extension://") == 0) { + return relativePath.replace(myBrowser.runtime.getURL(""), ""); + } + else if (relativePath.indexOf("/") != 0) { + var absolutePath = ""; + var documentPath = document.location.pathname; + absolutePath = documentPath.substring(0, documentPath.lastIndexOf("/") + 1); + absolutePath += relativePath; + return absolutePath; + } + return relativePath; + } +} +var bridgeHelper = new EdgeBridgeHelper(); +class EdgeBridgeDebugLog { + constructor() { + this.CatchOnException = true; + this.VerboseLogging = true; + this.FailedCalls = {}; + this.SuccededCalls = {}; + this.DeprecatedCalls = {}; + this.BridgedCalls = {}; + this.UnavailableApis = {}; + this.EdgeIssues = {}; + } + log(message) { + try { + if (this.VerboseLogging) { + console.log(message); + } + } + catch (e) { + } + } + info(message) { + try { + if (this.VerboseLogging) { + console.info(message); + } + } + catch (e) { + } + } + warn(message) { + try { + if (this.VerboseLogging) { + console.warn(message); + } + } + catch (e) { + } + } + error(message) { + try { + if (this.VerboseLogging) { + console.error(message); + } + } + catch (e) { + } + } + DoActionAndLog(action, name, deprecatedTo, bridgedTo) { + var result; + try { + result = action(); + this.AddToCalledDictionary(this.SuccededCalls, name); + if (typeof deprecatedTo !== "undefined") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + if (typeof bridgedTo !== "undefined") { + this.info("API Call '" + name + "' has been bridged to another Edge API: " + bridgedTo); + this.AddToCalledDictionary(this.BridgedCalls, name); + } + this.info("API Call: '" + name + "'"); + return result; + } + catch (ex) { + this.AddToCalledDictionary(this.FailedCalls, name); + if (this.CatchOnException) + this.error("API Call Failed: " + name + " - " + ex); + else + throw ex; + } + } + LogEdgeIssue(name, message) { + this.warn(message); + this.AddToCalledDictionary(this.EdgeIssues, name); + } + LogUnavailbleApi(name, deprecatedTo) { + this.warn("API Call '" + name + "' is not supported in Edge"); + this.AddToCalledDictionary(this.UnavailableApis, name); + if (typeof deprecatedTo !== "undefined") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + } + AddToCalledDictionary(dictionary, name) { + if (typeof dictionary[name] !== "undefined") { + dictionary[name]++; + } + else { + dictionary[name] = 1; + } + } +} +var bridgeLog = new EdgeBridgeDebugLog(); +class EdgeExtensionBridge { + get inIncognitoContext() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.inIncognitoContext; + }, "extension.inIncognitoContext"); + } + getBackgroundPage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getBackgroundPage.apply(null, arguments); + }, "extension.getBackgroundPage"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getURL.apply(null, arguments); + }, "extension.getURL"); + } + getViews(fetchProperties) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getViews.apply(null, arguments); + }, "extension.getViews"); + } + isAllowedIncognitoAccess(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.isAllowedIncognitoAccess.apply(null, arguments); + }, "extension.isAllowedIncognitoAccess"); + } +} +class EdgeChromeExtensionBridge extends EdgeExtensionBridge { + get onConnect() { return bridgeLog.DoActionAndLog(() => { return EdgeRuntimeBridge.prototype.onConnect; }, "extension.onConnect", "runtime.onConnect", "runtime.onConnect"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onMessage", "runtime.onMessage", "runtime.onMessage"); } + get onRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onRequest", "runtime.onMessage", "runtime.onMessage"); } + get onRequestExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "extension.onRequestExternal", "runtime.onMessageExternal", "runtime.onMessageExternal"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "extension.lastError", undefined, "runtime.lastError"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.connect.apply(null, arguments); + }, "extension.connect", "runtime.connect", "runtime.connect"); + } + sendMessage(message, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage.apply(null, arguments); + }, "extension.sendMessage", "runtime.sendMessage", "runtime.sendMessage"); + } + sendRequest(extensionId, message, options, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage.apply(null, arguments); + }, "extension.sendRequest", "runtime.sendMessage", "runtime.sendMessage"); + } + isAllowedFileSchemeAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedFileSchemeAccess"); + } + setUpdateUrlData(data) { + bridgeLog.LogUnavailbleApi("extension.setUpdateUrlData"); + } +} +class EdgeI18nBridge { + getAcceptLanguages(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getAcceptLanguages.apply(null, arguments); + }, "i18n.getAcceptLanguages"); + } + getMessage(messageName, substitutions) { + return bridgeLog.DoActionAndLog(() => { + if (messageName.indexOf("@@extension_id") > -1) { + return myBrowser.runtime.id; + } + return myBrowser.i18n.getMessage.apply(null, arguments); + }, "i18n.getMessage"); + } + getUILanguage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getUILanguage.apply(null, arguments); + }, "i18n.getUILanguage"); + } +} +class EdgeRuntimeBridge { + get id() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.id; }, "runtime.id"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "runtime.lastError"); } + get onConnect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onConnect; }, "runtime.onConnect"); } + get onInstalled() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onInstalled; }, "runtime.onInstalled"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "runtime.onMessage"); } + get onMessageExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "runtime.onMessageExternal"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.connect.apply(null, arguments); + }, "runtime.connect"); + } + connectNative(application) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.connectNative.apply(null, arguments); + }, "runtime.connectNative"); + } + getBackgroundPage(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.getBackgroundPage.apply(null, arguments); + }, "runtime.getBackgroundPage"); + } + getManifest() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getManifest.apply(null, arguments); + }, "runtime.getManifest"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getURL.apply(null, arguments); + }, "runtime.getURL"); + } + reload() { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.reload.apply(null, arguments); + }, "runtime.reload"); + } + sendMessage(extensionId, message, options, responseCallback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.sendMessage.apply(null, arguments); + }, "runtime.sendMessage"); + } + sendNativeMessage(application, message, responseCallback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.sendNativeMessage.apply(null, arguments); + }, "runtime.sendNativeMessage"); + } + setUninstallURL(url, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.setUninstallURL.apply(null, arguments); + }, "runtime.setUninstallURL"); + } +} +class EdgeChromeRuntimeBridge extends EdgeRuntimeBridge { + get onConnectExternal() { bridgeLog.LogUnavailbleApi("runtime.onConnectExternal"); return bridgeHelper.fakeEvent; } + get onRestartRequired() { bridgeLog.LogUnavailbleApi("runtime.onRestartRequired"); return bridgeHelper.fakeEvent; } + get onSuspend() { bridgeLog.LogUnavailbleApi("runtime.onSuspend"); return bridgeHelper.fakeEvent; } + get onSuspendCanceled() { bridgeLog.LogUnavailbleApi("runtime.onSuspendCanceled"); return bridgeHelper.fakeEvent; } + get onUpdateAvailable() { bridgeLog.LogUnavailbleApi("runtime.onUpdateAvailable"); return bridgeHelper.fakeEvent; } + get onStartup() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onCreated; }, "runtime.onStartup", undefined, "windows.onCreated"); } + openOptionsPage(callback) { + bridgeLog.DoActionAndLog(() => { + var optionsPage = myBrowser.runtime.getManifest()["options_page"]; + var optionsPageUrl = myBrowser.runtime.getURL(optionsPage); + if (typeof callback !== "undefined") { + myBrowser.tabs.create({ url: optionsPageUrl }, callback); + } + else { + myBrowser.tabs.create({ url: optionsPageUrl }); + } + }, "runtime.openOptionsPage", undefined, "tabs.create({ url: optionsPageUrl })"); + } + setUninstallURL(url, callback) { + if (myBrowser.runtime.setUninstallURL) { + EdgeRuntimeBridge.prototype.setUninstallURL.apply(null, arguments); + } + else { + bridgeLog.LogUnavailbleApi("runtime.setUninstallURL"); + } + } + getPackageDirectoryEntry(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPackageDirectoryEntry"); + } + getPlatformInfo(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPlatformInfo"); + } + requestUpdateCheck(callback) { + bridgeLog.LogUnavailbleApi("runtime.requestUpdateCheck"); + } + restart() { + bridgeLog.LogUnavailbleApi("runtime.restart"); + } +} +class EdgeStorageBridge { + get local() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.local"); } + get sync() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.sync; }, "storage.sync"); } + get onChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.onChanged; }, "storage.onChanged"); } +} +class EdgeChromeStorageBridge extends EdgeStorageBridge { + get sync() { + if (myBrowser.storage.sync) { + return EdgeStorageBridge.prototype.sync; + } + else { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.storage.local; + }, "storage.sync", undefined, "storage.local"); + } + } + get managed() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.managed", undefined, "storage.local"); } +} +class EdgeContentBridge { + constructor() { + this.extension = typeof browser.extension !== "undefined" ? new EdgeChromeExtensionBridge() : undefined; + this.i18n = typeof browser.i18n !== "undefined" ? new EdgeI18nBridge() : undefined; + this.runtime = typeof browser.runtime !== "undefined" ? new EdgeChromeRuntimeBridge() : undefined; + this.storage = typeof browser.storage !== "undefined" ? new EdgeChromeStorageBridge() : undefined; + } +} +var myBrowser = browser; +var chrome = new EdgeContentBridge(); diff --git a/edge-files/icon_150.png b/edge-files/icon_150.png new file mode 100644 index 000000000..177f3ea80 Binary files /dev/null and b/edge-files/icon_150.png differ diff --git a/edge-files/icon_44.png b/edge-files/icon_44.png new file mode 100644 index 000000000..50e53f41e Binary files /dev/null and b/edge-files/icon_44.png differ diff --git a/edge-files/icon_50.png b/edge-files/icon_50.png new file mode 100644 index 000000000..c23c7d0ea Binary files /dev/null and b/edge-files/icon_50.png differ diff --git a/js/README.md b/js/README.md index a54f326e7..afba87c9b 100644 --- a/js/README.md +++ b/js/README.md @@ -1,6 +1,6 @@ ## Minified Sources -File | Sourcre | Source Code +File | Source | Source Code -----|---------|------------ [aes.js](aes.js) | CryptoJS v3.1.2 | [Source](https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/crypto-js/CryptoJS%20v3.1.2.zip) [md5.js](md5.js) | CryptoJS v3.1.2 | [Source](https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/crypto-js/CryptoJS%20v3.1.2.zip) diff --git a/manifest-chrome.json b/manifest-chrome.json index b65d3029f..4a84374bc 100644 --- a/manifest-chrome.json +++ b/manifest-chrome.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_extShortName__", - "version": "5.1.0", + "version": "5.1.1", "default_locale": "en", "description": "__MSG_extDesc__", "icons": { @@ -52,7 +52,8 @@ "permissions": [ "activeTab", "storage", - "identity" + "identity", + "file://*/*" ], "optional_permissions": [ "clipboardWrite", diff --git a/manifest-edge.json b/manifest-edge.json new file mode 100644 index 000000000..b7f6b445f --- /dev/null +++ b/manifest-edge.json @@ -0,0 +1,66 @@ +{ + "author": "Authenticator Extension", + "background": { + "scripts": [ + "js/jsqrcode/grid.js", + "js/jsqrcode/version.js", + "js/jsqrcode/detector.js", + "js/jsqrcode/formatinf.js", + "js/jsqrcode/errorlevel.js", + "js/jsqrcode/bitmat.js", + "js/jsqrcode/datablock.js", + "js/jsqrcode/bmparser.js", + "js/jsqrcode/datamask.js", + "js/jsqrcode/rsdecoder.js", + "js/jsqrcode/gf256poly.js", + "js/jsqrcode/gf256.js", + "js/jsqrcode/decoder.js", + "js/jsqrcode/qrcode.js", + "js/jsqrcode/findpat.js", + "js/jsqrcode/alignpat.js", + "js/jsqrcode/databr.js", + "js/md5.js", + "js/aes.js", + "js/sha.js", + "js/qrcode.js", + "build/models/encryption.js", + "build/models/interface.js", + "build/models/otp.js", + "build/models/storage.js", + "build/background.js" + ], + "persistent": false + }, + "browser_action": { + "default_icon": { + "19": "images/icon19.png", + "38": "images/icon38.png" + }, + "default_title": "__MSG_extShortName__", + "default_popup": "view/popup.html" + }, + "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; default-src 'none'", + "default_locale": "en", + "description": "__MSG_extDesc__", + "icons": { + "16": "images/icon16.png", + "48": "images/icon48.png", + "128": "images/icon128.png" + }, + "manifest_version": 2, + "name": "__MSG_extName__", + "permissions": [ + "", + "storage" + ], + "short_name": "__MSG_extShortName__", + "version": "5.1.1", + "web_accessible_resources": [ + "view/qr.html", + "images/scan.gif" + ], + "-ms-preload": { + "backgroundScript": "edge-files/backgroundScriptsAPIBridge.js", + "contentScript": "edge-files/contentScriptsAPIBridge.js" + } +} diff --git a/manifest-firefox.json b/manifest-firefox.json index 397398711..5c3f500d5 100644 --- a/manifest-firefox.json +++ b/manifest-firefox.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_extShortName__", - "version": "5.1.0", + "version": "5.1.1", "default_locale": "en", "description": "__MSG_extDesc__", "applications": { diff --git a/package.json b/package.json index 4baf4575e..b7041f046 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,17 @@ "clean": "gts clean", "copyChrome": "cp -r src build css images js _locales LICENSE view chrome", "copyFirefox": "cp -r src build css images js _locales LICENSE view firefox", + "copyEdge": "cp -r src build css images js _locales LICENSE view edge-files edge/Extension && mv edge/Extension/edge-files/AppXManifest.xml edge && mv edge/Extension/edge-files/icon*.png edge/Assets", + "packageEdge": "cmd /C \"\"C:\\Program Files (x86)\\Windows Kits\\10\\App Certification Kit\\makeappx.exe\" pack /h SHA256 /d edge /p edge/Authenticator.appx\"", + "installEdge": "rm -rf edge && npm run edge && powershell -Command \"Add-AppxPackage -Path edge\\AppxManifest.xml -Register\"", "compile": "gts clean && tsc -p .", "fix": "gts fix", "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", "chrome": "node ensureDir.js chrome && npm run compile && npm run copyChrome && cp manifest-chrome.json chrome/manifest.json", - "firefox": "node ensureDir.js firefox && npm run compile && npm run copyFirefox && cp manifest-firefox.json firefox/manifest.json" + "firefox": "node ensureDir.js firefox && npm run compile && npm run copyFirefox && cp manifest-firefox.json firefox/manifest.json", + "edge": "node ensureDir.js edge && node ensureDir.js edge/Extension && node ensureDir.js edge/Assets && npm run compile && npm run copyEdge && cp manifest-edge.json edge/Extension/manifest.json" }, "repository": { "type": "git", @@ -33,5 +37,6 @@ "fs-extra": "^5.0.0", "gts": "^0.5.2", "typescript": "^2.6.1" - } + }, + "dependencies": {} } diff --git a/src/background.ts b/src/background.ts index 48c6362a0..c1116a4d1 100644 --- a/src/background.ts +++ b/src/background.ts @@ -80,6 +80,7 @@ async function getTotp(text: string, passphrase: string) { let account = ''; let secret = ''; let issuer = ''; + let period: number|undefined = undefined; try { label = decodeURIComponent(label); @@ -106,6 +107,12 @@ async function getTotp(text: string, passphrase: string) { } else if (parameter[0].toLowerCase() === 'counter') { let counter = Number(parameter[1]); counter = (isNaN(counter) || counter < 0) ? 0 : counter; + } else if (parameter[0].toLowerCase() === 'period') { + period = Number(parameter[1]); + period = (isNaN(period) || period < 0 || period > 60 || + 60 % period !== 0) ? + undefined : + period; } }); @@ -136,6 +143,9 @@ async function getTotp(text: string, passphrase: string) { index: 0, counter: 0 }; + if (period) { + entryData[hash].period = period; + } await EntryStorage.import(encryption, entryData); chrome.tabs.sendMessage(id, {action: 'added', account}); } @@ -198,6 +208,9 @@ chrome.runtime.onInstalled.addListener((details) => { } else if (navigator.userAgent.indexOf('Firefox') !== -1) { url = 'https://github.com/Authenticator-Extension/Authenticator/wiki/Firefox-Issues'; + } else if (navigator.userAgent.indexOf('Edge') !== -1) { + url = + 'https://github.com/Authenticator-Extension/Authenticator/wiki/Edge-Issues'; } if (url) { diff --git a/src/models/encryption.ts b/src/models/encryption.ts index b539321a9..639e1e89f 100644 --- a/src/models/encryption.ts +++ b/src/models/encryption.ts @@ -42,7 +42,6 @@ class Encryption { !/^[0-9a-f]+$/i.test(decryptedSecret) && !/^blz\-/.test(decryptedSecret) && !/^bliz\-/.test(decryptedSecret) && !/^stm\-/.test(decryptedSecret)) { - console.log(decryptedSecret); return 'Encrypted'; } diff --git a/src/models/interface.ts b/src/models/interface.ts index b7e48e995..b7a0eceeb 100644 --- a/src/models/interface.ts +++ b/src/models/interface.ts @@ -19,6 +19,7 @@ interface OTP { hash: string; counter: number; code: string; + period: number; create(encryption: Encryption): Promise; update(encryption: Encryption): Promise; next(encryption: Encryption): Promise; @@ -35,6 +36,7 @@ interface OTPStorage { secret: string; type: string; counter: number; + period?: number; } /* tslint:disable-next-line:interface-name */ diff --git a/src/models/key-utilities.ts b/src/models/key-utilities.ts index 470b9f0bd..db1ee509b 100644 --- a/src/models/key-utilities.ts +++ b/src/models/key-utilities.ts @@ -92,7 +92,8 @@ class KeyUtilities { return output; } - static generate(type: OTPType, secret: string, counter: number) { + static generate( + type: OTPType, secret: string, counter: number, period: number) { secret = secret.replace(/\s/g, ''); let len = 6; let b26 = false; @@ -128,7 +129,7 @@ class KeyUtilities { if (localStorage.offset) { epoch = epoch + Number(localStorage.offset); } - counter = Math.floor(epoch / 30); + counter = Math.floor(epoch / period); } const time = this.leftpad(this.dec2hex(counter), 16, '0'); diff --git a/src/models/otp.ts b/src/models/otp.ts index 4f8b4ad27..3125e30d1 100644 --- a/src/models/otp.ts +++ b/src/models/otp.ts @@ -12,11 +12,12 @@ class OTPEntry implements OTP { account: string; hash: string; counter: number; + period: number; code = '••••••'; constructor( type: OTPType, issuer: string, secret: string, account: string, - index: number, counter: number, hash?: string) { + index: number, counter: number, period?: number, hash?: string) { this.type = type; this.index = index; this.issuer = issuer; @@ -26,6 +27,11 @@ class OTPEntry implements OTP { hash : CryptoJS.MD5(secret).toString(); this.counter = counter; + if (this.type === OTPType.totp && period) { + this.period = period; + } else { + this.period = 30; + } if (this.type !== OTPType.hotp && this.type !== OTPType.hhex) { this.generate(); } @@ -61,7 +67,8 @@ class OTPEntry implements OTP { this.code = 'Encrypted'; } else { try { - this.code = KeyUtilities.generate(this.type, this.secret, this.counter); + this.code = KeyUtilities.generate( + this.type, this.secret, this.counter, this.period); } catch (error) { this.code = 'Invalid'; if (parent) { diff --git a/src/models/storage.ts b/src/models/storage.ts index f538fa11a..346824670 100644 --- a/src/models/storage.ts +++ b/src/models/storage.ts @@ -143,6 +143,11 @@ class EntryStorage { data[hash].issuer = data[hash].issuer || ''; data[hash].type = data[hash].type || OTPType[OTPType.totp]; data[hash].counter = data[hash].counter || 0; + const period = data[hash].period; + if (data[hash].type !== OTPType[OTPType.totp] || + period && (isNaN(period) || period <= 0)) { + delete data[hash].period; + } if (/^(blz\-|bliz\-)/.test(data[hash].secret)) { const secretMatches = @@ -306,6 +311,12 @@ class EntryStorage { needMigrate = true; } + let period = 30; + if (entryData.type === OTPType[OTPType.totp] && + entryData.period && entryData.period > 0) { + period = entryData.period; + } + entryData.secret = entryData.encrypted ? encryption.getDecryptedSecret(entryData.secret, hash) : entryData.secret; @@ -354,7 +365,7 @@ class EntryStorage { const entry = new OTPEntry( type, entryData.issuer, entryData.secret, entryData.account, entryData.index, entryData.counter, - entryData.hash); + period, entryData.hash); data.push(entry); // we need correct the hash diff --git a/src/popup.ts b/src/popup.ts index 3cc0b1ba2..a3fadf618 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -109,14 +109,22 @@ async function init() { } }); + if (ui.instance.isPopup()) { + ui.instance.fixPopupSize(); + } + return; } -chrome.permissions.contains( - {origins: ['https://www.google.com/']}, (hasPermission) => { - if (hasPermission) { - syncTimeWithGoogle(); - } - }); +if (navigator.userAgent.indexOf('Edge') !== -1) { + syncTimeWithGoogle(); +} else { + chrome.permissions.contains( + {origins: ['https://www.google.com/']}, (hasPermission) => { + if (hasPermission) { + syncTimeWithGoogle(); + } + }); +} init(); diff --git a/src/ui/entry.ts b/src/ui/entry.ts index c252567d5..d015fb900 100644 --- a/src/ui/entry.ts +++ b/src/ui/entry.ts @@ -14,43 +14,44 @@ async function getEntries(encryption: Encryption) { async function updateCode(app: any) { let second = new Date().getSeconds(); if (localStorage.offset) { - second += Number(localStorage.offset) + 30; + // prevent second from negative + second += Number(localStorage.offset) + 60; } - second = second % 30; - app.sector = getSector(second); - if (second > 25) { - app.class.timeout = true; - } else { - app.class.timeout = false; - } - if (second < 1) { - const entries = app.entries as OTP[]; - for (let i = 0; i < entries.length; i++) { - if (entries[i].type !== OTPType.hotp && - entries[i].type !== OTPType.hhex) { - entries[i].generate(); - } - } + + second = second % 60; + app.second = second; + + // only when sector is not started (timer is not initialized), + // passphrase box should not be shown (no passphrase set) or + // there are entiries shown and passphrase box isn't shown (the user has + // already provided password) + if (!app.sectorStart && + (!app.shouldShowPassphrase || + app.entries.length > 0 && app.info !== 'passphrase')) { + app.sectorStart = true; + app.sectorOffset = -second; } -} -function getSector(second: number) { - const canvas = document.createElement('canvas'); - canvas.width = 40; - canvas.height = 40; - const ctx = canvas.getContext('2d'); - if (!ctx) { - return; + // if (second > 25) { + // app.class.timeout = true; + // } else { + // app.class.timeout = false; + // } + // if (second < 1) { + // const entries = app.entries as OTP[]; + // for (let i = 0; i < entries.length; i++) { + // if (entries[i].type !== OTPType.hotp && + // entries[i].type !== OTPType.hhex) { + // entries[i].generate(); + // } + // } + // } + const entries = app.entries as OTP[]; + for (let i = 0; i < entries.length; i++) { + if (entries[i].type !== OTPType.hotp && entries[i].type !== OTPType.hhex) { + entries[i].generate(); + } } - ctx.fillStyle = '#888'; - ctx.beginPath(); - ctx.moveTo(20, 20); - ctx.arc( - 20, 20, 16, second / 30 * Math.PI * 2 - Math.PI / 2, Math.PI * 3 / 2, - false); - ctx.fill(); - const url = canvas.toDataURL(); - return `url(${url}) center / 20px 20px`; } function getBackupFile(entryData: {[hash: string]: OTPStorage}) { @@ -231,6 +232,9 @@ async function entry(_ui: UI) { exportEncryptedFile, getFilePassphrase: false, sector: '', + sectorStart: false, + sectorOffset: 0, + second: 0, notification: '', notificationTimeout: 0, filter: true, @@ -277,6 +281,8 @@ async function entry(_ui: UI) { } if (entry.issuer.toLowerCase().includes( + _ui.instance.searchText.toLowerCase()) || + entry.account.toLowerCase().includes( _ui.instance.searchText.toLowerCase())) { return true; } else { @@ -484,47 +490,87 @@ async function entry(_ui: UI) { return; } - chrome.permissions.request( - {permissions: ['clipboardWrite']}, async (granted) => { - if (granted) { - const codeClipboard = document.getElementById( - 'codeClipboard') as HTMLInputElement; - if (!codeClipboard) { - return; - } + if (navigator.userAgent.indexOf('Edge') !== -1) { + const codeClipboard = + document.getElementById('codeClipboard') as HTMLInputElement; + if (!codeClipboard) { + return; + } - if (_ui.instance.useAutofill) { - await insertContentScript(); + if (_ui.instance.useAutofill) { + await insertContentScript(); - chrome.tabs.query( - {active: true, lastFocusedWindow: true}, (tabs) => { - const tab = tabs[0]; - if (!tab || !tab.id) { - return; - } + chrome.tabs.query( + {active: true, lastFocusedWindow: true}, (tabs) => { + const tab = tabs[0]; + if (!tab || !tab.id) { + return; + } - chrome.tabs.sendMessage( - tab.id, {action: 'pastecode', code: entry.code}); - }); - } + chrome.tabs.sendMessage( + tab.id, {action: 'pastecode', code: entry.code}); + }); + } - codeClipboard.value = entry.code; - codeClipboard.focus(); - codeClipboard.select(); - document.execCommand('Copy'); - _ui.instance.notification = _ui.instance.i18n.copied; - clearTimeout(_ui.instance.notificationTimeout); - _ui.instance.class.notificationFadein = true; - _ui.instance.class.notificationFadeout = false; - _ui.instance.notificationTimeout = setTimeout(() => { - _ui.instance.class.notificationFadein = false; - _ui.instance.class.notificationFadeout = true; - setTimeout(() => { - _ui.instance.class.notificationFadeout = false; - }, 200); - }, 1000); - } - }); + codeClipboard.value = entry.code; + codeClipboard.focus(); + codeClipboard.select(); + document.execCommand('Copy'); + _ui.instance.notification = _ui.instance.i18n.copied; + clearTimeout(_ui.instance.notificationTimeout); + _ui.instance.class.notificationFadein = true; + _ui.instance.class.notificationFadeout = false; + _ui.instance.notificationTimeout = setTimeout(() => { + _ui.instance.class.notificationFadein = false; + _ui.instance.class.notificationFadeout = true; + setTimeout(() => { + _ui.instance.class.notificationFadeout = false; + }, 200); + }, 1000); + } else { + chrome.permissions.request( + {permissions: ['clipboardWrite']}, async (granted) => { + if (granted) { + const codeClipboard = + document.getElementById('codeClipboard') as + HTMLInputElement; + if (!codeClipboard) { + return; + } + + if (_ui.instance.useAutofill) { + await insertContentScript(); + + chrome.tabs.query( + {active: true, lastFocusedWindow: true}, (tabs) => { + const tab = tabs[0]; + if (!tab || !tab.id) { + return; + } + + chrome.tabs.sendMessage( + tab.id, {action: 'pastecode', code: entry.code}); + }); + } + + codeClipboard.value = entry.code; + codeClipboard.focus(); + codeClipboard.select(); + document.execCommand('Copy'); + _ui.instance.notification = _ui.instance.i18n.copied; + clearTimeout(_ui.instance.notificationTimeout); + _ui.instance.class.notificationFadein = true; + _ui.instance.class.notificationFadeout = false; + _ui.instance.notificationTimeout = setTimeout(() => { + _ui.instance.class.notificationFadein = false; + _ui.instance.class.notificationFadeout = true; + setTimeout(() => { + _ui.instance.class.notificationFadeout = false; + }, 200); + }, 1000); + } + }); + } return; }, } diff --git a/src/ui/menu.ts b/src/ui/menu.ts index 8439cbcf1..c98200ef1 100644 --- a/src/ui/menu.ts +++ b/src/ui/menu.ts @@ -56,12 +56,12 @@ function openHelp() { let url = 'https://github.com/Authenticator-Extension/Authenticator/wiki/Chrome-Issues'; - if (navigator.userAgent.indexOf('Chrome') !== -1) { - url = - 'https://github.com/Authenticator-Extension/Authenticator/wiki/Chrome-Issues'; - } else if (navigator.userAgent.indexOf('Firefox') !== -1) { + if (navigator.userAgent.indexOf('Firefox') !== -1) { url = 'https://github.com/Authenticator-Extension/Authenticator/wiki/Firefox-Issues'; + } else if (navigator.userAgent.indexOf('Edge') !== -1) { + url = + 'https://github.com/Authenticator-Extension/Authenticator/wiki/Edge-Issues'; } window.open(url, '_blank'); @@ -80,6 +80,10 @@ async function menu(_ui: UI) { window.open(url, '_blank'); return; }, + createWindow: (url: string) => { + chrome.windows.create({type: 'normal', url}); + return; + }, showMenu: () => { _ui.instance.class.slidein = true; _ui.instance.class.slideout = false; @@ -104,6 +108,17 @@ async function menu(_ui: UI) { return false; } }, + isEdge: () => { + if (navigator.userAgent.indexOf('Edge') !== -1) { + return true; + } else { + return false; + } + }, + showEdgeBugWarning: () => { + _ui.instance.alert( + 'Due to a bug in Edge, downloading backups is not supported at this time. More info on feedback page.'); + }, saveAutofill: () => { localStorage.autofill = _ui.instance.useAutofill; useAutofill = @@ -116,20 +131,27 @@ async function menu(_ui: UI) { return; }, syncClock: async () => { - chrome.permissions.request( - {origins: ['https://www.google.com/']}, async (granted) => { - if (granted) { - const message = await syncTimeWithGoogle(); - _ui.instance.alert(_ui.instance.i18n[message]); - } - return; - }); + if (navigator.userAgent.indexOf('Edge') !== -1) { + const message = await syncTimeWithGoogle(); + _ui.instance.alert(_ui.instance.i18n[message]); + } else { + chrome.permissions.request( + {origins: ['https://www.google.com/']}, async (granted) => { + if (granted) { + const message = await syncTimeWithGoogle(); + _ui.instance.alert(_ui.instance.i18n[message]); + } + return; + }); + } return; }, popOut: () => { let windowType; if (navigator.userAgent.indexOf('Firefox') !== -1) { windowType = 'detached_panel'; + } else if (navigator.userAgent.indexOf('Edge') !== -1) { + windowType = 'popup'; } else { windowType = 'panel'; } @@ -145,6 +167,18 @@ async function menu(_ui: UI) { new URLSearchParams(document.location.search.substring(1)); return params.get('popup'); }, + fixPopupSize: () => { + const zoom = Number(localStorage.zoom) / 100 || 1; + const correctHeight = 480 * zoom; + const correctWidth = 320 * zoom; + if (window.innerHeight !== correctHeight || + window.innerWidth !== correctWidth) { + chrome.windows.getCurrent((currentWindow) => { + chrome.windows.update( + currentWindow.id, {height: correctHeight, width: correctWidth}); + }); + } + }, dropboxUpload: async () => { const dbox = new Dropbox(); const response = await dbox.upload(_ui.instance.encryption); diff --git a/src/ui/qr.ts b/src/ui/qr.ts index ad21bddfc..65d477955 100644 --- a/src/ui/qr.ts +++ b/src/ui/qr.ts @@ -19,6 +19,9 @@ async function getQrUrl(entry: OTPEntry) { (entry.issuer ? ('&issuer=' + entry.issuer.split('::')[0]) : '') + ((entry.type === OTPType.hotp || entry.type === OTPType.hhex) ? ('&counter=' + entry.counter) : + '') + + (entry.type === OTPType.totp && entry.period ? + ('&period=' + entry.period) : ''); /* tslint:disable-next-line:no-unused-expression */ new QRCode( diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 8d4285d06..069e1e69a 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -67,11 +67,17 @@ class UI { return; }); }; + this.instance = new Vue(this.ui); - this.instance.updateCode(); - setInterval(async () => { - await this.instance.updateCode(); - }, 1000); + + // wait for all modules loaded + setTimeout(() => { + this.instance.updateCode(); + setInterval(async () => { + await this.instance.updateCode(); + }, 1000); + }, 0); + return this.instance; } } diff --git a/view/popup.html b/view/popup.html index c13a9395b..314ee1215 100644 --- a/view/popup.html +++ b/view/popup.html @@ -32,7 +32,7 @@
{{ i18n.show_all_entries }}