Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
65a3b49
fix: improve hostname parsing logic in getSiteName function
Hank076 May 6, 2025
e7c0320
fix: improve hostname parsing logic in getSiteName function
Hank076 May 6, 2025
0af8308
fix(storage): parse type & algorithm enums correctly on import
Hank076 Jun 21, 2026
ac1501d
fix(popup): keep countdown second non-negative for any clock offset
Hank076 Jun 21, 2026
8ce1acb
fix(import): accept any positive-integer TOTP period
Hank076 Jun 21, 2026
7c2efb3
fix(preferences): only show smart-filter hint when enabling it
Hank076 Jun 21, 2026
17a7da4
fix(advisor): don't warn about autolock when using the 30-min default
Hank076 Jun 21, 2026
d815f3e
fix(add-account): apply selected algorithm and digits immediately
Hank076 Jun 21, 2026
02e06a2
fix(onedrive): send token-exchange parameters in the request body
Hank076 Jun 21, 2026
0b0e182
fix(popup): show search box on load, not only after clearing a filter
Hank076 Jun 21, 2026
4e3e462
feat(import): support andOTP plain-JSON backups
Hank076 Jun 21, 2026
afecff9
fix(qr): keep the issuer:account colon literal in exported QR codes
Hank076 Jun 21, 2026
b9b43a6
fix(autofill): skip hidden inputs when pasting the code
Hank076 Jun 21, 2026
64f9822
fix(reorder): map drag indices through the displayed order
Hank076 Jun 21, 2026
598ebe7
fix(edit): stop arrow keys in entry fields from navigating the list
Hank076 Jun 21, 2026
247d946
fix(import): detect failed migration imports instead of always succee…
Hank076 Jun 21, 2026
1f955c8
fix(storage): surface sync write failures instead of dropping entries
Hank076 Jun 21, 2026
2af9666
fix(autofill): anchor domain match and ignore page title when pasting…
Hank076 Jun 21, 2026
1a873b1
fix(hotp): restore the 3s refresh debounce and disabled state
Hank076 Jun 21, 2026
5a9b7c6
fix(backup): don't mutate live export state when building the .txt ba…
Hank076 Jun 21, 2026
221124b
fix(migration): validate bounds and fields when parsing otpauth-migra…
Hank076 Jun 21, 2026
1357e84
fix(notification): remove the confirm listener after it fires
Hank076 Jun 21, 2026
b19fee3
fix(unlock): recover the UI when unlocking throws
Hank076 Jun 21, 2026
8e3ac75
fix(argon): correlate sandbox responses and stop leaking listeners
Hank076 Jun 21, 2026
f6b15e9
chore(deps): move crypto-js to dependencies and @types/lodash to dev
Hank076 Jun 21, 2026
b3086c4
build(prod): don't emit source maps in production builds
Hank076 Jun 21, 2026
87fbf21
build: don't block on an interactive keypress for forks
Hank076 Jun 21, 2026
93a3a5e
fix(import): skip a corrupt encrypted entry instead of aborting the i…
Hank076 Jun 21, 2026
d652b34
fix(synctime): report failure on an unparseable date header
Hank076 Jun 21, 2026
239d0b3
fix(backup): treat a non-2xx Dropbox response as a failed upload
Hank076 Jun 21, 2026
25605b3
fix(storage): use commitItems on sync->local migration and zero-pad t…
Hank076 Jun 21, 2026
6a9f0f4
fix(background): ignore runtime messages not from this extension
Hank076 Jun 21, 2026
1d0bd8a
fix(backup): log scheduled backup failures instead of swallowing them
Hank076 Jun 21, 2026
c2994cb
refactor(entry): render the code with text interpolation, drop v-html
Hank076 Jun 21, 2026
308ed90
refactor(store): route Accounts state changes through mutations
Hank076 Jun 21, 2026
816369e
refactor(store): convert async Advisor/Permissions mutations to actions
Hank076 Jun 21, 2026
7765118
feat(store): enable Vuex strict mode in development builds
Hank076 Jun 21, 2026
a175e19
refactor(store): move deferred animation/alert resets out of mutations
Hank076 Jun 21, 2026
3f4c83a
fix(messaging): don't return true from listeners that send no response
Hank076 Jun 21, 2026
cff9cf8
fix(popup): re-sync the timer circle after pinning or reordering
Hank076 Jun 21, 2026
490bb94
perf(content): reuse one willReadFrequently canvas context for QR cap…
Hank076 Jun 21, 2026
83a0996
feat(encryption): encrypt with authenticated AES-GCM, read legacy CBC
Hank076 Jun 21, 2026
f5794c2
refactor: await the now-async encryption across read/write paths
Hank076 Jun 21, 2026
6f7a3b6
fix(import): detect otpauth text backups instead of JSON-parsing them
Hank076 Jun 21, 2026
b708c6c
fix(import): detect otpauth text in the paste-import box too
Hank076 Jun 21, 2026
f4ac338
build(vue3): upgrade to Vue 3 / Vuex 4 toolchain
Hank076 Jun 21, 2026
c56b4c8
refactor(vue3): convert entry points to createApp / createStore
Hank076 Jun 21, 2026
3720ee4
test(vue3): migrate unit tests to @vue/test-utils v2
Hank076 Jun 21, 2026
d20d59a
refactor(vue3): migrate components and swap dragula for vuedraggable
Hank076 Jun 21, 2026
3078ae8
fix(vue3): guard empty dynamic component and define Vue feature flags
Hank076 Jun 21, 2026
a41a44d
fix(vue3): bind filtered/notSearched as classes so entries stay visible
Hank076 Jun 22, 2026
5570b8d
fix(vue3): keep set-password/unlock strict-safe under Vuex 4
Hank076 Jun 22, 2026
983e70d
fix(popup): read lastError when locking so it isn't an unchecked warning
Hank076 Jun 22, 2026
c54b5ba
fix(qr): scan via sender.tab so MV3 worker recycling can't break it
Hank076 Jun 22, 2026
4806c3d
fix(qr): guard qrDecode against empty capture / degenerate selection
Hank076 Jun 22, 2026
a959dbf
fix(qr): stable drag-select and quieter non-QR scans
Hank076 Jun 22, 2026
d7ea7f9
fix(qr): prevent native drag so the selection box is draggable
Hank076 Jun 22, 2026
0b5c96f
fix(qr): dismiss capture overlay on autolock across MV3 worker recycling
Hank076 Jun 22, 2026
c598cc6
fix(security): encrypt manually-added account secret (Map.get not bra…
Hank076 Jun 22, 2026
5095a51
test(AddAccountPage): assert raw encryption to avoid chai+reactive crash
Hank076 Jun 22, 2026
47034ea
test(vue3): fix migrated EnterPasswordPage/MenuPage tests for test-ut…
Hank076 Jun 22, 2026
8c12da5
fix(gitignore): anchor root test/ build dir with /test (was invalid .…
Hank076 Jun 22, 2026
5c75d8d
i18n(zh_TW): proofread Traditional Chinese for Taiwan usage
Hank076 Jun 22, 2026
c271202
i18n(zh_TW): add missing space after QR Code in import warning
Hank076 Jun 22, 2026
538b84a
fix(backup): correct encryption toggle in cloud backup pages
Hank076 Jun 22, 2026
f836928
fix(preferences): restore storage-migration error handler
Hank076 Jun 22, 2026
a7fc008
fix(backup): repair broken promise paths in cloud providers
Hank076 Jun 22, 2026
c41c5c6
fix(store): await UserSettings in Backup module init
Hank076 Jun 22, 2026
4b22c63
refactor(advisor): drop `this.` prefix in component templates
Hank076 Jun 22, 2026
c1c8afa
refactor(encryption): simplify boolean return
Hank076 Jun 22, 2026
8ab7528
refactor(key-utilities): remove dead hex2str, use String.padStart
Hank076 Jun 22, 2026
174a40c
refactor(advisor): remove no-op InsightLevel cast
Hank076 Jun 22, 2026
39a89e7
refactor(menu): remove dead icon import, simplify isSupported
Hank076 Jun 22, 2026
985f9d4
refactor(permissions): drop redundant Promise.all over resolved values
Hank076 Jun 22, 2026
8092df4
refactor(accounts): tidy session lookup, dead comment, dedupe regex
Hank076 Jun 22, 2026
9a30756
fix(otp): stop generate() racing a code with offset 0
Hank076 Jun 22, 2026
b50bdee
fix(migration): skip MD5 and bound the HOTP counter read correctly
Hank076 Jun 22, 2026
f7542e8
fix(backup): harden Drive/OneDrive upload result handling
Hank076 Jun 22, 2026
d849394
refactor(backup): send Drive OAuth refresh params in the POST body
Hank076 Jun 22, 2026
e9dac23
fix(permissions): resolve revoke promise without a dangling timer
Hank076 Jun 22, 2026
b9bbf2e
refactor(advisor): extract parseIgnoreList helper
Hank076 Jun 22, 2026
db40732
refactor(i18n): load bundled messages with fetch
Hank076 Jun 22, 2026
2abe325
refactor(synctime): reuse the already-computed offset
Hank076 Jun 22, 2026
06172c4
refactor(import): remove no-op try/catch
Hank076 Jun 22, 2026
c8ea145
refactor(accounts): use a Set for linkedKeys
Hank076 Jun 22, 2026
aeb6e82
refactor(storage): drop stale TODO on already-async get()
Hank076 Jun 22, 2026
908c0e3
style: apply prettier formatting
Hank076 Jun 22, 2026
231fc0a
feat(menu): point external links at the Hank076 fork
Hank076 Jun 22, 2026
9b4de0a
Merge branch 'feature/code-review-cleanup' into dev
Hank076 Jun 22, 2026
182d7d0
feat(i18n): add strings for the redesigned UI
Hank076 Jun 23, 2026
7760f8b
feat(ui): redesign the extension with a CSS custom-property design sy…
Hank076 Jun 23, 2026
3edc3b3
Merge branch 'feature/ui-redesign' into dev
Hank076 Jun 23, 2026
82a3413
feat(autofill): require a host match before injecting a code
Hank076 Jun 23, 2026
11d4566
Merge branch 'feature/host-bound-autofill' into dev
Hank076 Jun 23, 2026
320930f
feat(backup): require a master password before cloud backup
Hank076 Jun 23, 2026
9219344
Merge branch 'feature/require-password-for-cloud-backup' into dev
Hank076 Jun 23, 2026
a5e4eb1
feat(import): redesign the import page with interactive tabs
Hank076 Jun 23, 2026
a98110f
fix(backup): open import in a new tab
Hank076 Jun 23, 2026
7650bc4
Merge branch 'feature/import-redesign' into dev
Hank076 Jun 23, 2026
8ac473b
fix(storage): preserve bound host when reloading entries
Hank076 Jun 23, 2026
15f948b
Merge branch 'fix/host-persistence' into dev
Hank076 Jun 23, 2026
2bb5d5d
feat: rebrand extension to OTPilot Authenticator
Hank076 Jun 24, 2026
d4e5423
feat(backup): add Dropbox OAuth app key
Hank076 Jun 24, 2026
56e5d2c
fix(backup): make Dropbox upload work in the MV3 service worker
Hank076 Jun 24, 2026
3f5e411
fix(backup): repair cloud connect flow and encryption UX
Hank076 Jun 24, 2026
c13391e
feat(i18n): apply OTPilot brand name across all locales
Hank076 Jun 25, 2026
713698c
feat(backup): wire up Google Drive OAuth with a pinned extension id
Hank076 Jun 25, 2026
6a46c75
fix(import): enable drag-and-drop on the backup dropzone
Hank076 Jun 25, 2026
b3cfd2e
feat(i18n): translate priority locales and unify brand to OTPilot
Hank076 Jun 25, 2026
27ffa7c
fix: quiet wrong-passphrase logging and accept boolean SelectInput value
Hank076 Jun 25, 2026
70da0ce
fix(backup): make Google Drive backup work under the new OAuth rules
Hank076 Jun 25, 2026
c6995f7
feat(backup): redesign the Google Drive connect and connected pages
Hank076 Jun 25, 2026
4b26a15
fix(ui): disable OneDrive and align brand icons
Hank076 Jun 25, 2026
e9875d6
docs: add privacy policy for Chrome Web Store submission
Hank076 Jun 26, 2026
59ddee3
feat(i18n): refine Traditional Chinese import and lock wording
Hank076 Jun 26, 2026
4affee0
Merge remote-tracking branch 'origin/dev' into dev
Hank076 Jun 26, 2026
c4f6d3f
docs: fill in privacy policy date and contact email
Hank076 Jun 26, 2026
6f80b6d
fix(i18n): restore zh_TW import and lock wording
Hank076 Jun 26, 2026
2a16cca
fix(import): prevent JSON parse errors from surfacing in error panel
Hank076 Jun 26, 2026
c659df2
feat(import): add drag highlight, drop-to-import, and file-import entry
Hank076 Jun 26, 2026
7954375
refactor(import): rename to OTPAuth URI and unify passphrase field
Hank076 Jun 26, 2026
a0c1371
feat(popup): make empty-state icon trigger add-account
Hank076 Jun 26, 2026
c68cf74
feat(backup): encode bound host as issuer::host in all exports
Hank076 Jun 26, 2026
5db30ee
fix(otp): reject invalid base32 secrets instead of silent garbage codes
Hank076 Jul 2, 2026
a6e4109
fix(backup): split issuer::host at last separator to allow :: in issuer
Hank076 Jul 2, 2026
ea2defa
fix(advisor): await commitItems before refreshing insights
Hank076 Jul 2, 2026
69d56b3
fix(import): parse otpauth query params with URLSearchParams
Hank076 Jul 2, 2026
a73b3c7
build: rename webpack output dir from dist to js
Hank076 Jul 2, 2026
ee3528a
feat(backup): PKCE for Dropbox, remove Google Drive in-client OAuth
Hank076 Jul 6, 2026
4352127
docs: update privacy policy to Dropbox-only cloud backup
Hank076 Jul 7, 2026
b9614f4
chore(manifest): remove unused Google Drive and OneDrive host permiss…
Hank076 Jul 7, 2026
23020d2
chore(issue-template): point links to this fork and add triage fields
Hank076 Jul 10, 2026
d8bad2c
fix(i18n): add errorissuer to zh_TW, prune 19 unused message keys
Hank076 Jul 10, 2026
49cba52
chore(i18n): sync all locales to zh_TW canonical key set
Hank076 Jul 10, 2026
5da48ea
fix(i18n): proofread & correct machine translations across 42 locales
Hank076 Jul 10, 2026
45c842f
fix(i18n): apply verifier corrections to high-frequency locales
Hank076 Jul 10, 2026
c33456d
chore(i18n): replace dead Crowdin tooling with locale key-parity check
Hank076 Jul 10, 2026
b68635c
fix(backup): decrypt EncOTPStorage entries for plaintext export
Hank076 Jul 10, 2026
daf4b68
fix(backup): harden decrypt validation and Dropbox logout
Hank076 Jul 10, 2026
07979fa
docs(readme): rewrite for OTPilot Authenticator fork
Hank076 Jul 10, 2026
113549e
chore(git): stop tracking docs/
Hank076 Jul 10, 2026
e7f79a2
chore(git): tidy .gitignore for current project state
Hank076 Jul 10, 2026
869bb1b
ci(test): use puppeteer bundled Chrome for Testing instead of system …
Hank076 Jul 10, 2026
89a8b97
ci: upgrade actions to current supported majors
Hank076 Jul 10, 2026
70d21aa
ci: remove release and tagging workflows
Hank076 Jul 10, 2026
f7debf0
ci: add tag-triggered Chrome extension ZIP release
Hank076 Jul 11, 2026
d070b98
ci(release): take release notes from the annotated tag message
Hank076 Jul 11, 2026
e6c707e
chore(release): bump chrome version to 8.0.3
Hank076 Jul 11, 2026
43557dd
ci(release): re-fetch tag annotation before creating the release
Hank076 Jul 11, 2026
a2c443b
ci: bump checkout and setup-node to v5 (Node 24 runtime)
Hank076 Jul 11, 2026
898b4e5
ci(release): prefix release asset with OTPilot-Authenticator
Hank076 Jul 11, 2026
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
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node_modules
dist
js
firefox
chrome
scripts
Expand Down
4 changes: 0 additions & 4 deletions .github/ISSUE_TEMPLATE.md

This file was deleted.

19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,22 @@ body:
description: The extension version is found by clicking the cog at the top left and looking at the bottom of the page.
validations:
required: true
- type: dropdown
attributes:
label: Affected area
description: Optional — helps us triage which part of the extension is involved.
options:
- Not sure / general
- Generating codes
- Cloud backup (Dropbox)
- Autofill on websites
- Import / export
- Security advisor
validations:
required: false
- type: textarea
attributes:
label: Console errors
description: Optional. Open the extension page, press F12 → Console, and paste any red errors. Remove any OTP codes or secrets before posting.
validations:
required: false
5 changes: 1 addition & 4 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
contact_links:
- name: Feature Request
url: https://github.com/Authenticator-Extension/Authenticator/discussions/new
url: https://github.com/Hank076/Authenticator/discussions/new
about: Please request features here.
- name: Translation Issues
url: https://crowdin.com/project/authenticator-firefox
about: Please correct translation issues on Crowdin.
40 changes: 8 additions & 32 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,18 @@ jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
uses: actions/checkout@v5

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
16 changes: 5 additions & 11 deletions .github/workflows/i18n.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
name: i18n

on:
push:
branches: [ dev ]
on: [push, pull_request]

jobs:
i18n-strings:
key-parity:
runs-on: ubuntu-latest
name: Process new i18n strings

name: Check locale key parity
steps:
- uses: actions/checkout@v2

- run: bash scripts/i18n.sh
env:
DEPLOY_KEY_PASSWORD: ${{ secrets.DEPLOY_KEY_PASSWORD }}
- uses: actions/checkout@v5
- run: node scripts/check-i18n.js
26 changes: 15 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ jobs:
name: Style checks

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5

- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
uses: actions/setup-node@v5
with:
node-version: 22

- name: Install dependencies
run: |
Expand All @@ -29,10 +31,13 @@ jobs:
platform: ["chrome", "firefox"]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5

- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
uses: actions/setup-node@v5
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci
Expand All @@ -45,17 +50,16 @@ jobs:
needs: [build]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5

- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
uses: actions/setup-node@v5
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true"

- name: Test code
uses: mymindstorm/puppeteer-headful@8f745c770f7f4c0f9f332d7c43a775f90e53779a
with:
args: npm test
run: xvfb-run --auto-servernum -- npm test
59 changes: 27 additions & 32 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,40 @@ name: Release

on:
push:
tags:
- 'v*'
tags:
- "v*"

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
name: Publish release build
name: Build and publish Chrome extension ZIP

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5

- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2

uses: actions/setup-node@v5
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build
run: bash scripts/release.sh
env:
CREDS_FILE_PASSWORD: ${{ secrets.CREDS_FILE_PASSWORD }}

- name: Create a release
id: create_release
uses: actions/create-release@v1.1.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
PUPPETEER_SKIP_DOWNLOAD: "true"

- name: Build
run: npm run chrome

- name: Package
run: cd chrome && zip -r "../OTPilot-Authenticator-chrome-${GITHUB_REF_NAME}.zip" .

- name: Create release
run: |
git fetch --force origin "refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
gh release create "$GITHUB_REF_NAME" "OTPilot-Authenticator-chrome-${GITHUB_REF_NAME}.zip" --title "$GITHUB_REF_NAME" --notes-from-tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./release.tar.gz
asset_name: release.tar.gz
asset_content_type: application/gzip
GH_TOKEN: ${{ github.token }}
17 changes: 0 additions & 17 deletions .github/workflows/tagging.yml

This file was deleted.

32 changes: 25 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
# dependencies
node_modules

# build output
build
chrome*
firefox*
edge*
dist
.vscode
.atom-build.yml
scripts/authenticator-build-key.enc
cert.pfx
js
css
/test
.license-gen-tmp
view/licenses.html
./test
scripts/test-runner.js

# release credentials
scripts/authenticator-build-key
scripts/test-runner.js
scripts/authenticator-build-key.enc
cert.pfx

# local docs / AI working notes
docs/

# editor & local tool settings
.vscode
.claude/settings.local.json

# OS
Thumbs.db
Desktop.ini
.DS_Store

# npm logs
npm-debug.log*
68 changes: 35 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
# Authenticator [![Build Status](https://travis-ci.com/Authenticator-Extension/Authenticator.svg?branch=dev)](https://travis-ci.com/Authenticator-Extension/Authenticator) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/authenticator-firefox/localized.svg)](https://crowdin.com/project/authenticator-firefox) <img align="right" width="100" height="100" src="https://github.com/Authenticator-Extension/Authenticator/raw/dev/images/icon.svg">
# OTPilot Authenticator <img align="right" width="100" height="100" src="https://github.com/Hank076/Authenticator/blob/dev/images/icon.svg">

> Authenticator generates 2-Step Verification codes in your browser.
> OTPilot Authenticator generates 2-Step Verification (OTP) codes in your browser.

## Available for Chrome, Firefox, and Microsoft Edge
[**Install from the Chrome Web Store**](https://chromewebstore.google.com/detail/otpilot-authenticator/compmlfocdmifebgiecbajaidkmgkonc)

[<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)
This is a fork of [Authenticator-Extension/Authenticator](https://github.com/Authenticator-Extension/Authenticator) ([source of this fork](https://github.com/Hank076/Authenticator)). On top of upstream, this fork adds:


### Safari Edition

A Safari edition of Authenticator is available on the App Store. We do not provide official support for the Safari edition.

[<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)
- **Encrypted cloud backup to Dropbox** — OAuth Authorization Code + PKCE via `chrome.identity.launchWebAuthFlow`; no client secret ships in the extension. (Google Drive backup was removed in 2026-07; OneDrive is a disabled placeholder.)
- **Advisor** — security recommendations for your accounts.
- **Host-bound autofill** — codes are only injected when the page host matches the account.
- **Redesigned import flow** and a CSS custom-property design system (`sass/_tokens.scss`).

## Build Setup

``` bash
# install development dependencies
npm install
# compile
npm run [chrome, firefox, prod]
```

To reproduce a build:

``` bash
```bash
# install dependencies (~2 min, downloads puppeteer Chromium)
npm ci
npm run prod

# build for a target
npm run [chrome, firefox, edge, prod]
```

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

- Build output goes to `chrome/` (bundles under `chrome/js/`); these directories are gitignored.
- `npm run prod` aborts if `src/models/credentials.ts` is empty (OAuth credentials are kept out of the repo). `chrome`/`test` builds only warn — everything works except live cloud backup.
- **Windows**: builds run through `bash scripts/build.sh`, so use a full [Git Bash](https://git-scm.com/download/win) (with complete coreutils). Running `npm test` from plain PowerShell fails with `'bash' is not recognized`.

## Development (Chrome)

``` bash
# install development dependencies
npm install
# compiles the Chrome extension to the `./test/chrome` directory
```bash
# watch build
npm run dev:chrome
# load the unpacked extension from the `./test/chrome/ directory in Chrome
# then load the unpacked extension from the `chrome/` directory
```

Note that Windows users should download a tool like [Git Bash](https://git-scm.com/download/win) or [Cygwin](http://cygwin.com/) to build.
## Testing

## Acknowledgment
```bash
npm test
```

Runs the extension in a real browser via puppeteer with in-browser mocha (`headless: false`, so a GUI is required).

We would like to extend our heartfelt thanks to Laurent, the Chief Information Security Officer (CISO) of the University of Luxembourg, for the invaluable support and contribution to this project. During the development process, the CISO team provided critical security recommendations that helped us identify and address potential vulnerabilities, significantly enhancing the security and reliability of the project.
## i18n

We especially want to acknowledge the University of Luxembourg's information security team for their selfless contribution, which not only facilitated the progress of this project but also had a positive impact on the broader open-source community. We recognize that the success of open-source software depends heavily on collaboration and support from various stakeholders, and the involvement of the University of Luxembourg has allowed us to offer a more secure and dependable product to a wider audience.
`_locales/en/messages.json` is the source of truth for keys. Crowdin is no longer used; other locales are maintained by hand. All locales must have the exact same key set as `en`, enforced by:

We understand that while open-source software is free, maintaining and improving these projects requires significant resources. The University of Luxembourg’s information security team has demonstrated their strong commitment to the open-source community, contributing not just within their university but to users and developers globally. We hope this acknowledgment will help them continue to secure the support and resources necessary to further advance open-source initiatives.
```bash
node scripts/check-i18n.js
```

## Acknowledgment

Once again, we express our sincere gratitude to the University of Luxembourg's CISO team for their valuable advice and assistance.
We would like to extend our heartfelt thanks to Laurent, the Chief Information Security Officer (CISO) of the University of Luxembourg, and the university's information security team for their invaluable security recommendations to the upstream project.
Loading