Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

> Authenticator generates 2-Step Verification codes in your browser.

## Available for Chrome, Firefox, and Microsoft Edge
## Available for Chrome, Firefox, Microsoft Edge and Safari

[<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/chrome-web-store.png" title="Chrome Web Store" width="170" height="48" />](https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai) [<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/firefox-add-ons.png" title="Firefox Add-ons" width="170" height="48" />](https://addons.mozilla.org/en-US/firefox/addon/auth-helper?src=external-github) [<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/microsoft-store.png" title="Microsoft Store" height="48">](https://microsoftedge.microsoft.com/addons/detail/ocglkepbibnalbgmbachknglpdipeoio)
[<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/chrome-web-store.png" title="Chrome Web Store" width="170" height="48" />](https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai) [<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/firefox-add-ons.png" title="Firefox Add-ons" width="170" height="48" />](https://addons.mozilla.org/en-US/firefox/addon/auth-helper?src=external-github) [<img src="https://raw.githubusercontent.com/wiki/Authenticator-Extension/Authenticator/readme-images/microsoft-store.png" title="Microsoft Store" height="48">](https://microsoftedge.microsoft.com/addons/detail/ocglkepbibnalbgmbachknglpdipeoio) [<img width="150" alt="Download on the App Store" src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg"/>](https://apps.apple.com/us/app/authen/id1602945200?mt=12)

## Build Setup

Expand All @@ -22,6 +22,8 @@ npm ci
npm run prod
```

To reproduce a build for Safari, please follow contribution guidance in [Authenticator-Extension/Authen](https://github.com/Authenticator-Extension/Authen#how-to-contribute)

## Development (Chrome)

``` bash
Expand Down
4 changes: 4 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@
"message": "High Contrast",
"description": "High Contrast theme"
},
"theme_flat": {
"message": "Flat",
"description": "Flat theme"
},
"storage_sync_info": {
"message": "Automatically backup your data to 3rd party storage services.",
"description": "3rd party backup info"
Expand Down
19 changes: 19 additions & 0 deletions sass/_ui.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ $themes: (
grey-search: #b1b1b3,
blue-menu: #f4fcff,
),
flat: (
black-1: black,
black-transparent: rgba(0, 0, 0, 0.5),
white-1: white,
white-transparent: rgba(255, 255, 255, 0.5),
grey-1: grey,
grey-2: #ccc,
grey-3: #eee,
grey-background: #eee,
blue-1: #08c,
yellow-1: #fff1ba,
yellow-2: #fff4cc,
red-1: #dd4b39,
red-2: #eea59c,
black-search: #2a2a2e,
white-search: #f9f9fa,
grey-search: #b1b1b3,
blue-menu: #f4fcff,
),
);

$theme-map: null;
Expand Down
61 changes: 61 additions & 0 deletions sass/popup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1306,3 +1306,64 @@ svg {
border: 2px solid black !important;
}
}

// Flat overrides
.theme-flat {
.header {
color: black;
background: white;
border-bottom: #f5f4f7 1px solid;
}

#codes {
background: #fcfbff;

.entry {
border: #f5f4f7 1px solid;
border-radius: 8px;
}
}

#menu {
#menuBody {
background: #fcfbff;

.menuList {
margin: 10px;
border-radius: 8px;
border: #f5f4f7 1px solid;
background: white;

p {
color: #727272;

&:not(:last-child) {
border-bottom: #f5f4f7 1px solid;
}

span svg {
fill: #727272;
}
}
}
}

#version {
bottom: 0px;
position: relative;
margin: 10px auto;
width: 100%;
color: #727272;
font-size: 0.9em;
}

#info {
border-radius: 8px;
border: #f5f4f7 1px solid;

.control-group {
border-bottom: #f5f4f7 1px solid;
}
}
}
}
18 changes: 6 additions & 12 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { getSiteName, getMatchedEntries } from "./utils";
import { CodeState } from "./models/otp";

import { getOTPAuthPerLineFromOPTAuthMigration } from "./models/migration";
import { isChrome, isFirefox } from "./browser";

let cachedPassphrase = "";
let autolockTimeout: number;
Expand Down Expand Up @@ -288,11 +289,7 @@ async function getTotp(text: string, silent = false) {
}

function getBackupToken(service: string) {
if (
navigator.userAgent.indexOf("Chrome") !== -1 &&
navigator.userAgent.indexOf("Edg") === -1 &&
service === "drive"
) {
if (isChrome && service === "drive") {
chrome.identity.getAuthToken(
{
interactive: true,
Expand Down Expand Up @@ -320,7 +317,7 @@ function getBackupToken(service: string) {
} else if (service === "drive") {
if (navigator.userAgent.indexOf("Edg") !== -1) {
redirUrl = encodeURIComponent("https://authenticator.cc/oauth-edge");
} else if (navigator.userAgent.indexOf("Firefox") !== -1) {
} else if (isFirefox) {
redirUrl = encodeURIComponent(chrome.identity.getRedirectURL());
} else {
redirUrl = encodeURIComponent("https://authenticator.cc/oauth");
Expand Down Expand Up @@ -415,7 +412,7 @@ function getBackupToken(service: string) {
}
} catch (error) {
console.error(error);
reject(error);
reject(error as Error);
}
}
return;
Expand Down Expand Up @@ -517,10 +514,7 @@ chrome.runtime.onInstalled.addListener(async (details) => {

let url: string | null = null;

if (
navigator.userAgent.indexOf("Chrome") !== -1 &&
navigator.userAgent.indexOf("Edg") === -1
) {
if (isChrome) {
url = "https://otp.ee/chromeissues";
}

Expand Down Expand Up @@ -664,7 +658,7 @@ function updateContextMenu() {
encodeURIComponent(tab.title);
}
let windowType;
if (navigator.userAgent.indexOf("Firefox") !== -1) {
if (isFirefox) {
windowType = "detached_panel";
} else {
windowType = "panel";
Expand Down
10 changes: 10 additions & 0 deletions src/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const userAgent = navigator.userAgent;

export const isFirefox = userAgent.indexOf("Firefox") >= 0;
export const isWebKit = userAgent.indexOf("AppleWebKit") >= 0;
export const isEdge = navigator.userAgent.indexOf("Edg") >= 0;
export const isChromium = userAgent.indexOf("Chrome") >= 0;
export const isSafari = !isChromium && userAgent.indexOf("Safari") >= 0;
export const isChrome =
navigator.userAgent.indexOf("Chrome") !== -1 &&
navigator.userAgent.indexOf("Edg") === -1;
4 changes: 3 additions & 1 deletion src/components/Popup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
theme !== 'accessibility' &&
theme !== 'dark' &&
theme !== 'simple' &&
theme !== 'compact',
theme !== 'compact' &&
theme !== 'flat',
'theme-accessibility': theme === 'accessibility',
'theme-dark': theme === 'dark',
'theme-simple': theme === 'simple',
'theme-compact': theme === 'compact',
'theme-flat': theme === 'flat',
hideoutline,
}"
v-on:mousedown="hideoutline = true"
Expand Down
59 changes: 53 additions & 6 deletions src/components/Popup/BackupPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,47 @@
<a-button-link
download="authenticator.txt"
:href="exportOneLineOtpAuthFile"
v-if="!unsupportedAccounts"
v-if="!unsupportedAccounts && isDataLinkSupported"
>{{ i18n.download_backup }}</a-button-link
>
<a-button-link download="authenticator.json" :href="exportFile" v-else>{{
i18n.download_backup
}}</a-button-link>
<button
v-on:click="downloadBackUpOneLineOtpAuthFile()"
v-if="!unsupportedAccounts && !isDataLinkSupported"
class="button"
>
{{ i18n.download_backup }}
</button>
<a-button-link
download="authenticator.json"
:href="exportFile"
v-if="unsupportedAccounts && isDataLinkSupported"
>{{ i18n.download_backup }}</a-button-link
>
<button
v-on:click="downloadBackUpExportFile()"
v-if="unsupportedAccounts && !isDataLinkSupported"
class="button"
>
{{ i18n.download_backup }}
</button>
<a-button-link
download="authenticator.json"
:href="exportEncryptedFile"
v-if="encryption.getEncryptionStatus()"
v-if="encryption.getEncryptionStatus() && isDataLinkSupported"
>{{ i18n.download_enc_backup }}</a-button-link
>
<button
v-on:click="downloadBackUpExportEncryptedFile()"
v-if="encryption.getEncryptionStatus() && !isDataLinkSupported"
class="button"
>
{{ i18n.download_enc_backup }}
</button>
</div>
<a-button-link href="import.html">{{ i18n.import_backup }}</a-button-link>
<br />
<!-- 3rd Party Backup Services -->
<div v-show="!backupDisabled">
<div v-show="!backupDisabled && isBackupServiceSupported">
<div class="text">
{{ i18n.storage_sync_info }}
</div>
Expand All @@ -46,6 +70,7 @@
</template>
<script lang="ts">
import Vue from "vue";
import { isSafari } from "../../browser";

export default Vue.extend({
data: function () {
Expand Down Expand Up @@ -73,6 +98,12 @@ export default Vue.extend({
backupDisabled: function () {
return this.$store.getters["menu/storageArea"];
},
isDataLinkSupported: function () {
return !isSafari;
},
isBackupServiceSupported: function () {
return !isSafari;
},
},
methods: {
showInfo(tab: string) {
Expand Down Expand Up @@ -123,6 +154,22 @@ export default Vue.extend({
return;
}
},
downloadBackUpOneLineOtpAuthFile() {
const exportData = this.$store.state.accounts.exportData;
const t = getOneLineOtpBackupFile(exportData);
window.open(t);
},
downloadBackUpExportFile() {
const exportData = this.$store.state.accounts.exportData;
const t = getBackupFile(exportData);
window.open(t);
},
downloadBackUpExportEncryptedFile() {
const exportEncData = this.$store.state.accounts.exportEncData;
const key = this.$store.state.accounts.key;
const t = getBackupFile(exportEncData, key);
window.open(t);
},
},
});

Expand Down
6 changes: 2 additions & 4 deletions src/components/Popup/DrivePage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
</template>
<script lang="ts">
import Vue from "vue";
import { isChrome } from "../../browser";
import { Drive } from "../../models/backup";

const service = "drive";
Expand Down Expand Up @@ -80,10 +81,7 @@ export default Vue.extend({
);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (
navigator.userAgent.indexOf("Chrome") !== -1 &&
navigator.userAgent.indexOf("Edg") === -1
) {
if (isChrome) {
chrome.identity.removeCachedAuthToken(
{ token: localStorage.driveToken },
() => {
Expand Down
5 changes: 3 additions & 2 deletions src/components/Popup/MainHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import IconScan from "../../../svg/scan.svg";
import IconPencil from "../../../svg/pencil.svg";
import IconCheck from "../../../svg/check.svg";
import IconPlus from "../../../svg/plus.svg";
import { isFirefox } from "../../browser";

const computedPrototype = [
mapState("style", ["style"]),
Expand All @@ -106,7 +107,7 @@ export default Vue.extend({
},
popOut() {
let windowType;
if (navigator.userAgent.indexOf("Firefox") !== -1) {
if (isFirefox) {
windowType = "detached_panel";
} else {
windowType = "panel";
Expand Down Expand Up @@ -152,7 +153,7 @@ export default Vue.extend({
return;
}
// Request permissions
if (navigator.userAgent.indexOf("Firefox") !== -1) {
if (isFirefox) {
await new Promise((resolve: (value: void) => void) => {
chrome.permissions.request(
{ origins: ["<all_urls>"] },
Expand Down
14 changes: 12 additions & 2 deletions src/components/Popup/MenuPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
>
<span><IconLock /></span>{{ i18n.security }}
</p>
<p v-bind:title="i18n.sync_clock" v-on:click="syncClock()">
<p
v-bind:title="i18n.sync_clock"
v-on:click="syncClock()"
v-if="isSupported"
>
<span><IconSync /></span>{{ i18n.sync_clock }}
</p>
<p
Expand Down Expand Up @@ -83,6 +87,7 @@ import IconComments from "../../../svg/comments.svg";
import IconGlobe from "../../../svg/globe.svg";
import IconCode from "../../../svg/code.svg";
import IconClipboardCheck from "../../../svg/clipboard-check.svg";
import { isFirefox, isSafari } from "../../browser";

export default Vue.extend({
components: {
Expand All @@ -103,6 +108,11 @@ export default Vue.extend({
version: function () {
return this.$store.state.menu.version;
},
isSupported: {
get(): boolean {
return !isSafari;
},
},
},
methods: {
hideMenu() {
Expand All @@ -111,7 +121,7 @@ export default Vue.extend({
openHelp() {
let url = "https://otp.ee/chromeissues";

if (navigator.userAgent.indexOf("Firefox") !== -1) {
if (isFirefox) {
url = "https://otp.ee/firefoxissues";
} else if (navigator.userAgent.indexOf("Edg") !== -1) {
url = "https://otp.ee/edgeissues";
Expand Down
Loading