Compare commits

..

12 Commits

Author SHA1 Message Date
Leendert de Borst
bd82037d8c Bump version to 0.18.1 2025-06-02 23:39:08 +02:00
Leendert de Borst
9615634bf9 Add docker build and push back to release.yml (#887) 2025-06-02 23:38:54 +02:00
Leendert de Borst
dfd2b534e6 Add iOS build workflow action (#887) 2025-06-02 23:30:40 +02:00
Leendert de Borst
314c757fe6 Refactor build android step to reusable action (#887) 2025-06-02 23:30:40 +02:00
Leendert de Borst
771abe9cc1 Update bump version script to also bump browser package.json (#887) 2025-06-02 23:30:40 +02:00
Leendert de Borst
22aaf17cd1 Refactor browser extension build to reusable workflow (#887) 2025-06-02 23:30:40 +02:00
Leendert de Borst
2134b61a78 Make release app build use the correct file location (#887) 2025-06-02 23:30:40 +02:00
Leendert de Borst
0059e31892 Update README.md 2025-06-02 17:14:26 +02:00
Leendert de Borst
2f7a4370b7 Improve sanity checks for if biometrics are not available (#880) 2025-06-02 14:21:43 +02:00
Leendert de Borst
5fc2889a03 Make username case insensitive for mobile apps (#884) 2025-06-02 11:56:43 +02:00
Leendert de Borst
f43bc402ba Make username case insensitive during login for browser extension (#884) 2025-06-02 11:56:43 +02:00
Leendert de Borst
2e6d4fbe20 Update README.md 2025-06-01 11:06:26 +02:00
23 changed files with 637 additions and 477 deletions

View File

@@ -0,0 +1,132 @@
name: "Build Android App"
description: "Builds Android APK/AAB, optionally signs and uploads to GitHub Release"
inputs:
run_tests:
description: "Whether to run Android unit tests"
required: false
default: "false"
signed:
description: "Whether to sign the Android build"
required: false
default: "false"
upload_to_release:
description: "Whether to upload the APK to GitHub Release"
required: false
default: "false"
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
shell: bash
working-directory: apps/mobile-app
- name: Extract version
run: |
VERSION=$(node -p "require('./app.json').expo.version")
echo "VERSION=$VERSION" >> $GITHUB_ENV
shell: bash
working-directory: apps/mobile-app
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Build JS bundle (Expo)
run: |
mkdir -p build
npx expo export \
--dev \
--output-dir ./build \
--platform android
shell: bash
working-directory: apps/mobile-app
- name: Run Android Unit Tests
if: ${{ inputs.run_tests == 'true' }}
run: |
cd android
./gradlew :app:testDebugUnitTest --tests "net.aliasvault.app.*"
shell: bash
working-directory: apps/mobile-app
- name: Upload Android Test Reports
if: ${{ inputs.run_tests == 'true' }}
uses: actions/upload-artifact@v4
with:
name: android-test-reports
path: apps/mobile-app/android/app/build/reports/tests/testDebugUnitTest/
retention-days: 7
- name: Decode keystore
if: ${{ inputs.signed == 'true' }}
run: echo "${{ env.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
shell: bash
working-directory: apps/mobile-app
- name: Configure signing
if: ${{ inputs.signed == 'true' }}
run: |
cat >> android/gradle.properties <<EOF
ALIASVAULT_UPLOAD_STORE_FILE=keystore.jks
ALIASVAULT_UPLOAD_KEY_ALIAS=${{ env.ANDROID_KEY_ALIAS }}
ALIASVAULT_UPLOAD_STORE_PASSWORD=${{ env.ANDROID_KEYSTORE_PASSWORD }}
ALIASVAULT_UPLOAD_KEY_PASSWORD=${{ env.ANDROID_KEY_PASSWORD }}
EOF
shell: bash
working-directory: apps/mobile-app
- name: Build APK & AAB (Release only if signed)
if: ${{ inputs.signed == 'true' }}
run: |
cd android
./gradlew bundleRelease
./gradlew assembleRelease
shell: bash
working-directory: apps/mobile-app
- name: Rename APK and AAB files
if: ${{ inputs.signed == 'true' }}
run: |
mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/aliasvault-${VERSION}-android.apk
mv android/app/build/outputs/bundle/release/app-release.aab android/app/build/outputs/bundle/release/aliasvault-${VERSION}-android.aab
shell: bash
working-directory: apps/mobile-app
- name: Upload AAB as artifact
if: ${{ inputs.signed == 'true' }}
uses: actions/upload-artifact@v4
with:
name: aliasvault-${{ env.VERSION }}-android.aab
path: apps/mobile-app/android/app/build/outputs/bundle/release/aliasvault-${{ env.VERSION }}-android.aab
retention-days: 14
- name: Upload APK as artifact
if: ${{ inputs.signed == 'true' }}
uses: actions/upload-artifact@v4
with:
name: aliasvault-${{ env.VERSION }}-android.apk
path: apps/mobile-app/android/app/build/outputs/apk/release/aliasvault-${{ env.VERSION }}-android.apk
retention-days: 14
- name: Upload APK to release
if: ${{ inputs.upload_to_release == 'true' }}
uses: softprops/action-gh-release@v2
with:
files: apps/mobile-app/android/app/build/outputs/apk/release/aliasvault-${{ env.VERSION }}-android.apk
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}

View File

@@ -0,0 +1,104 @@
name: "Build Browser Extension"
description: "Builds, tests, lints, zips, and optionally uploads a browser extension"
inputs:
browser:
description: "Target browser to build for (chrome, firefox, edge)"
required: true
upload_to_release:
description: "Whether to upload the resulting zip to GitHub Release"
required: false
default: "false"
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/browser-extension/package-lock.json
- name: Install dependencies
run: npm ci
shell: bash
working-directory: apps/browser-extension
- name: Build extension
run: npm run build:${{ inputs.browser }}
shell: bash
working-directory: apps/browser-extension
- name: Run tests
run: npm run test
shell: bash
working-directory: apps/browser-extension
- name: Run linting
run: npm run lint
shell: bash
working-directory: apps/browser-extension
- name: Zip Extension
run: npm run zip:${{ inputs.browser }}
shell: bash
working-directory: apps/browser-extension
- name: Extract version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "VERSION=$VERSION" >> $GITHUB_ENV
shell: bash
working-directory: apps/browser-extension
- name: Unzip extension
run: |
mkdir -p dist/${{ inputs.browser }}-unpacked
unzip dist/aliasvault-browser-extension-${{ env.VERSION }}-${{ inputs.browser }}.zip -d dist/${{ inputs.browser }}-unpacked
shell: bash
working-directory: apps/browser-extension
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: aliasvault-${{ env.VERSION }}-${{ inputs.browser }}
path: apps/browser-extension/dist/${{ inputs.browser }}-unpacked
- name: Unzip and upload Firefox sources
if: ${{ inputs.browser == 'firefox' }}
run: |
mkdir -p dist/sources-unpacked
unzip dist/aliasvault-browser-extension-${{ env.VERSION }}-sources.zip -d dist/sources-unpacked
shell: bash
working-directory: apps/browser-extension
- name: Upload Firefox sources artifact
if: ${{ inputs.browser == 'firefox' }}
uses: actions/upload-artifact@v4
with:
name: aliasvault-${{ env.VERSION }}-browser-extension-sources
path: apps/browser-extension/dist/sources-unpacked
- name: Rename zip files
run: |
mv apps/browser-extension/dist/aliasvault-browser-extension-${{ env.VERSION }}-${{ inputs.browser }}.zip apps/browser-extension/dist/aliasvault-${{ env.VERSION }}-${{ inputs.browser }}.zip
if [ -f apps/browser-extension/dist/aliasvault-browser-extension-${{ env.VERSION }}-sources.zip ]; then
mv apps/browser-extension/dist/aliasvault-browser-extension-${{ env.VERSION }}-sources.zip apps/browser-extension/dist/aliasvault-${{ env.VERSION }}-browser-extension-sources.zip
fi
shell: bash
- name: Upload to GitHub Release
if: ${{ inputs.upload_to_release == 'true' }}
uses: softprops/action-gh-release@v1
with:
files: |
apps/browser-extension/dist/aliasvault-${{ env.VERSION }}-${{ inputs.browser }}.zip
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}
- name: Upload Firefox sources to Release
if: ${{ inputs.upload_to_release == 'true' && inputs.browser == 'firefox' }}
uses: softprops/action-gh-release@v1
with:
files: apps/browser-extension/dist/aliasvault-${{ env.VERSION }}-browser-extension-sources.zip
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}

118
.github/actions/build-ios-app/action.yml vendored Normal file
View File

@@ -0,0 +1,118 @@
name: "Build iOS App"
description: "Builds iOS App, optionally signs and uploads to App Store Connect"
inputs:
run_tests:
description: "Whether to run iOS unit tests"
required: false
default: "false"
signed:
description: "Whether to sign the iOS build"
required: false
default: "false"
upload_to_app_store_connect:
description: "Whether to upload the iOS App to App Store Connect"
required: false
default: "false"
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
shell: bash
working-directory: apps/mobile-app
- name: Extract version
run: |
VERSION=$(node -p "require('./app.json').expo.version")
echo "VERSION=$VERSION" >> $GITHUB_ENV
shell: bash
working-directory: apps/mobile-app
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Install Fastlane
run: gem install fastlane
shell: bash
- name: Install CocoaPods
run: |
sudo gem install cocoapods
shell: bash
- name: Create ASC private key file
if: ${{ inputs.signed == 'true' }}
run: |
mkdir -p $RUNNER_TEMP/asc
echo "${{ env.ASC_PRIVATE_KEY_BASE64 }}" | base64 --decode > $RUNNER_TEMP/asc/AuthKey.p8
shell: bash
- name: Install CocoaPods
run: |
cd ios
pod install
shell: bash
working-directory: apps/mobile-app
- name: Build iOS IPA
if: ${{ inputs.signed == 'true' }}
env:
IDEFileSystemSynchronizedGroupsAreEnabled: NO
XCODE_WORKSPACE: AliasVault.xcworkspace
XCODE_SCHEME: AliasVault
XCODE_CONFIGURATION: Release
XCODE_ARCHIVE_PATH: AliasVault.xcarchive
XCODE_EXPORT_PATH: ./build
XCODE_SKIP_FILESYSTEM_SYNC: true
run: |
cd ios
xcodebuild clean -workspace "$XCODE_WORKSPACE" \
-scheme "$XCODE_SCHEME" \
-configuration "$XCODE_CONFIGURATION"
xcodebuild -workspace "$XCODE_WORKSPACE" \
-scheme "$XCODE_SCHEME" \
-configuration "$XCODE_CONFIGURATION" \
-archivePath "$XCODE_ARCHIVE_PATH" \
-destination 'generic/platform=iOS' \
-allowProvisioningUpdates \
-authenticationKeyPath $RUNNER_TEMP/asc/AuthKey.p8 \
-authenticationKeyID ${{ env.ASC_KEY_ID }} \
-authenticationKeyIssuerID ${{ env.ASC_ISSUER_ID }} \
archive
xcodebuild -exportArchive \
-archivePath "$XCODE_ARCHIVE_PATH" \
-exportOptionsPlist ../exportOptions.plist \
-exportPath "$XCODE_EXPORT_PATH"
shell: bash
working-directory: apps/mobile-app
- name: Upload IPA as artifact
if: ${{ inputs.signed == 'true' }}
uses: actions/upload-artifact@v4
with:
name: aliasvault-${{ env.VERSION }}-ios.ipa
path: apps/mobile-app/ios/build/AliasVault.ipa
retention-days: 14
- name: Upload to App Store Connect via Fastlane
if: ${{ inputs.upload_to_app_store_connect == 'true' }}
env:
ASC_KEY_ID: ${{ env.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ env.ASC_ISSUER_ID }}
run: |
cd apps/mobile-app/ios
fastlane pilot upload \
--ipa "./build/AliasVault.ipa" \
--api_key_path "$RUNNER_TEMP/asc/AuthKey.p8" \
--skip_waiting_for_build_processing true
shell: bash

View File

@@ -63,157 +63,32 @@ jobs:
build-chrome-extension:
needs: build-shared-libraries
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/browser-extension
steps:
- uses: actions/checkout@v4
- name: Get short SHA
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Chrome Extension
uses: ./.github/actions/build-browser-extension
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/browser-extension/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build extension
run: npm run build:chrome
- name: Run tests
run: npm run test
- name: Run linting
run: npm run lint
- name: Zip Chrome Extension
run: npm run zip:chrome
- name: Unzip for artifact
run: |
mkdir -p dist/chrome-unpacked
unzip dist/aliasvault-browser-extension-*-chrome.zip -d dist/chrome-unpacked
- name: Upload dist artifact Chrome
uses: actions/upload-artifact@v4
with:
name: aliasvault-browser-extension-${{ github.event_name == 'release' && github.ref_name || (github.ref_name == 'main' && format('main-{0}', steps.vars.outputs.sha_short) || steps.vars.outputs.sha_short) }}-chrome
path: apps/browser-extension/dist/chrome-unpacked
outputs:
sha_short: ${{ steps.vars.outputs.sha_short }}
browser: chrome
build-firefox-extension:
needs: build-shared-libraries
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/browser-extension
steps:
- uses: actions/checkout@v4
- name: Get short SHA
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Firefox Extension
uses: ./.github/actions/build-browser-extension
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/browser-extension/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build extension
run: npm run build:firefox
- name: Run tests
run: npm run test
- name: Run linting
run: npm run lint
- name: Zip Firefox Extension
run: npm run zip:firefox
- name: Unzip for artifact
run: |
mkdir -p dist/firefox-unpacked
unzip dist/aliasvault-browser-extension-*-firefox.zip -d dist/firefox-unpacked
mkdir -p dist/sources-unpacked
unzip dist/aliasvault-browser-extension-*-sources.zip -d dist/sources-unpacked
- name: Upload dist artifact Firefox
uses: actions/upload-artifact@v4
with:
name: aliasvault-browser-extension-${{ github.event_name == 'release' && github.ref_name || (github.ref_name == 'main' && format('main-{0}', steps.vars.outputs.sha_short) || steps.vars.outputs.sha_short) }}-firefox
path: apps/browser-extension/dist/firefox-unpacked
- name: Upload dist artifact Firefox sources
uses: actions/upload-artifact@v4
with:
name: aliasvault-browser-extension-${{ github.event_name == 'release' && github.ref_name || (github.ref_name == 'main' && format('main-{0}', steps.vars.outputs.sha_short) || steps.vars.outputs.sha_short) }}-sources
path: apps/browser-extension/dist/sources-unpacked
outputs:
sha_short: ${{ steps.vars.outputs.sha_short }}
browser: firefox
build-edge-extension:
needs: build-shared-libraries
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/browser-extension
steps:
- uses: actions/checkout@v4
- name: Get short SHA
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Edge Extension
uses: ./.github/actions/build-browser-extension
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/browser-extension/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build extension
run: npm run build:edge
- name: Run tests
run: npm run test
- name: Run linting
run: npm run lint
- name: Zip Edge Extension
run: npm run zip:edge
- name: Unzip for artifact
run: |
mkdir -p dist/edge-unpacked
unzip dist/aliasvault-browser-extension-*-edge.zip -d dist/edge-unpacked
- name: Upload dist artifact Edge
uses: actions/upload-artifact@v4
with:
name: aliasvault-browser-extension-${{ github.event_name == 'release' && github.ref_name || (github.ref_name == 'main' && format('main-{0}', steps.vars.outputs.sha_short) || steps.vars.outputs.sha_short) }}-edge
path: apps/browser-extension/dist/edge-unpacked
outputs:
sha_short: ${{ steps.vars.outputs.sha_short }}
browser: edge

View File

@@ -17,6 +17,11 @@ on:
required: true
type: boolean
default: false
upload_to_app_store_connect:
description: 'Upload iOS IPA to App Store Connect'
required: true
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -115,187 +120,56 @@ jobs:
build-android:
needs: setup
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/mobile-app
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Android App
uses: ./.github/actions/build-android-app
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Build JS bundle (Android - Expo)
run: |
mkdir -p build
npx expo export \
--dev \
--output-dir ./build \
--platform android
- name: Run Android Unit Tests
run: |
cd android
./gradlew :app:testDebugUnitTest --tests "net.aliasvault.app.*"
- name: Upload Android Test Reports
if: always()
uses: actions/upload-artifact@v4
with:
name: android-test-reports
path: apps/mobile-app/android/app/build/reports/tests/testDebugUnitTest/
retention-days: 7
run_tests: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
build-android-signed:
needs: setup
if: github.event_name == 'workflow_dispatch' && github.event.inputs.build_android_signed == 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/mobile-app
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Android App
uses: ./.github/actions/build-android-app
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Decode keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Configure signing
run: |
cat >> android/gradle.properties <<EOF
ALIASVAULT_UPLOAD_STORE_FILE=keystore.jks
ALIASVAULT_UPLOAD_KEY_ALIAS=${{ secrets.ANDROID_KEY_ALIAS }}
ALIASVAULT_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ALIASVAULT_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}
EOF
- name: Build Signed APK & AAB
run: |
cd android
./gradlew bundleRelease
./gradlew assembleRelease
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: signed-apk
path: apps/mobile-app/android/app/build/outputs/apk/release/app-release.apk
retention-days: 14
- name: Upload AAB
uses: actions/upload-artifact@v4
with:
name: signed-aab
path: apps/mobile-app/android/app/build/outputs/bundle/release/app-release.aab
retention-days: 14
signed: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
build-ios-signed:
needs: setup
if: github.event_name == 'workflow_dispatch' && github.event.inputs.build_ios_signed == 'true'
runs-on: macos-15
defaults:
run:
working-directory: apps/mobile-app
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build iOS App
uses: ./.github/actions/build-ios-app
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Install Fastlane
run: gem install fastlane
- name: Create ASC private key file
run: |
mkdir -p $RUNNER_TEMP/asc
echo "${{ secrets.ASC_PRIVATE_KEY_BASE64 }}" | base64 --decode > $RUNNER_TEMP/asc/AuthKey.p8
- name: Install CocoaPods
run: |
cd ios
pod install
- name: Build iOS IPA
signed: true
upload_to_app_store_connect: ${{ github.event.inputs.upload_to_app_store_connect }}
env:
IDEFileSystemSynchronizedGroupsAreEnabled: NO
XCODE_WORKSPACE: AliasVault.xcworkspace
XCODE_SCHEME: AliasVault
XCODE_CONFIGURATION: Release
XCODE_ARCHIVE_PATH: AliasVault.xcarchive
XCODE_EXPORT_PATH: ./build
XCODE_SKIP_FILESYSTEM_SYNC: true
run: |
cd ios
xcodebuild clean -workspace "$XCODE_WORKSPACE" \
-scheme "$XCODE_SCHEME" \
-configuration "$XCODE_CONFIGURATION"
xcodebuild -workspace "$XCODE_WORKSPACE" \
-scheme "$XCODE_SCHEME" \
-configuration "$XCODE_CONFIGURATION" \
-archivePath "$XCODE_ARCHIVE_PATH" \
-destination 'generic/platform=iOS' \
-allowProvisioningUpdates \
-authenticationKeyPath $RUNNER_TEMP/asc/AuthKey.p8 \
-authenticationKeyID ${{ secrets.ASC_KEY_ID }} \
-authenticationKeyIssuerID ${{ secrets.ASC_ISSUER_ID }} \
archive
xcodebuild -exportArchive \
-archivePath "$XCODE_ARCHIVE_PATH" \
-exportOptionsPlist ../exportOptions.plist \
-exportPath "$XCODE_EXPORT_PATH"
- name: Upload IPA
uses: actions/upload-artifact@v4
with:
name: signed-ipa
path: apps/mobile-app/ios/build/AliasVault.ipa
retention-days: 14
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASC_PRIVATE_KEY_BASE64: ${{ secrets.ASC_PRIVATE_KEY_BASE64 }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_TEAM_ID: ${{ secrets.ASC_TEAM_ID }}

View File

@@ -24,105 +24,65 @@ jobs:
files: install.sh
token: ${{ secrets.GITHUB_TOKEN }}
package-browser-extensions:
build-chrome-extension:
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/browser-extension
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Chrome Extension
uses: ./.github/actions/build-browser-extension
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/browser-extension/package-lock.json
browser: chrome
upload_to_release: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies
run: npm ci
build-firefox-extension:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Zip extensions
run: |
npm run zip:chrome
npm run zip:firefox
npm run zip:edge
- name: Upload extensions to release
uses: softprops/action-gh-release@v2
- name: Build Firefox Extension
uses: ./.github/actions/build-browser-extension
with:
files: |
apps/browser-extension/dist/aliasvault-browser-extension-*-chrome.zip
apps/browser-extension/dist/aliasvault-browser-extension-*-firefox.zip
apps/browser-extension/dist/aliasvault-browser-extension-*-edge.zip
apps/browser-extension/dist/aliasvault-browser-extension-*-sources.zip
token: ${{ secrets.GITHUB_TOKEN }}
browser: firefox
upload_to_release: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-edge-extension:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build Edge Extension
uses: ./.github/actions/build-browser-extension
with:
browser: edge
upload_to_release: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-android-release:
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/mobile-app
steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
- name: Build Android App
uses: ./.github/actions/build-android-app
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: apps/mobile-app/package-lock.json
- name: Install dependencies
run: npm ci
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Decode keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks
- name: Configure signing
run: |
cat >> android/gradle.properties <<EOF
ALIASVAULT_UPLOAD_STORE_FILE=keystore.jks
ALIASVAULT_UPLOAD_KEY_ALIAS=${{ secrets.ANDROID_KEY_ALIAS }}
ALIASVAULT_UPLOAD_STORE_PASSWORD=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ALIASVAULT_UPLOAD_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}
EOF
- name: Build JS bundle (Android - Expo)
run: |
mkdir -p build
npx expo export \
--dev \
--output-dir ./build \
--platform android
- name: Build Signed APK & AAB
run: |
cd android
./gradlew bundleRelease
./gradlew assembleRelease
- name: Upload APK to release
uses: softprops/action-gh-release@v2
with:
files: android/app/build/outputs/apk/release/app-release.apk
token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload AAB to release
uses: softprops/action-gh-release@v2
with:
files: android/app/build/outputs/bundle/release/app-release.aab
token: ${{ secrets.GITHUB_TOKEN }}
signed: true
upload_to_release: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
build-and-push-docker:
runs-on: ubuntu-latest

View File

@@ -1,5 +1,5 @@
# <img src="https://github.com/user-attachments/assets/933c8b45-a190-4df6-913e-b7c64ad9938b" width="35" alt="AliasVault"> AliasVault
End-to-end encrypted password manager with built-in alias and email generation — giving you full control over your online identity and safeguarding your privacy. AliasVault: the privacy toolbox that you control.
The privacy-first password & email alias manager. Fully end-to-end encrypted, with built-in alias generation and email server — giving you full control over your online identity and safeguarding your privacy.
[<img src="https://img.shields.io/github/v/release/lanedirt/AliasVault?include_prereleases&logo=github&label=Release">](https://github.com/lanedirt/AliasVault/releases)
[![.NET E2E Tests (with Sharding)](https://github.com/lanedirt/AliasVault/actions/workflows/dotnet-e2e-tests.yml/badge.svg)](https://github.com/lanedirt/AliasVault/actions/workflows/dotnet-e2e-tests.yml)
@@ -47,7 +47,7 @@ Built on 15 years of experience, AliasVault is open-source, self-hostable and co
## Cloud-hosted
Use the official cloud version of AliasVault at [app.aliasvault.net](https://app.aliasvault.net). This fully supported platform is always up to date with our latest release.
AliasVault is available on: [Web](https://app.aliasvault.net) | [iOS](https://apps.apple.com/app/id6745490915) | [Chrome](https://chromewebstore.google.com/detail/aliasvault/bmoggiinmnodjphdjnmpcnlleamkfedj) | [Firefox](https://addons.mozilla.org/en-US/firefox/addon/aliasvault/) | [Edge](https://microsoftedge.microsoft.com/addons/detail/aliasvault/kabaanafahnjkfkplbnllebdmppdemfo) | [Safari](https://apps.apple.com/app/id6743163173)
AliasVault is available on: [Web](https://app.aliasvault.net) | [iOS](https://apps.apple.com/app/id6745490915) | [Android](https://play.google.com/store/apps/details?id=net.aliasvault.app) | [Chrome](https://chromewebstore.google.com/detail/aliasvault/bmoggiinmnodjphdjnmpcnlleamkfedj) | [Firefox](https://addons.mozilla.org/en-US/firefox/addon/aliasvault/) | [Edge](https://microsoftedge.microsoft.com/addons/detail/aliasvault/kabaanafahnjkfkplbnllebdmppdemfo) | [Safari](https://apps.apple.com/app/id6743163173)
[<img width="700" alt="Screenshot of AliasVault" src="docs/assets/img/screenshot.png">](https://app.aliasvault.net)

View File

@@ -2,7 +2,7 @@
"name": "aliasvault-browser-extension",
"description": "AliasVault Browser Extension",
"private": true,
"version": "0.0.0",
"version": "0.18.1",
"type": "module",
"scripts": {
"dev:chrome": "wxt -b chrome",

View File

@@ -447,7 +447,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -460,7 +460,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -479,7 +479,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "AliasVault Extension/AliasVault_Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -492,7 +492,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -515,7 +515,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -530,7 +530,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"-framework",
SafariServices,
@@ -554,7 +554,7 @@
CODE_SIGN_ENTITLEMENTS = AliasVault/AliasVault.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -569,7 +569,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"-framework",
SafariServices,

View File

@@ -13,6 +13,7 @@ import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
import { LoginResponse } from '@/utils/types/webapi/Login';
import LoginServerInfo from '@/entrypoints/popup/components/LoginServerInfo';
import { ApiAuthError } from '@/utils/types/errors/ApiAuthError';
import ConversionUtility from '../utils/ConversionUtility';
/**
* Login page
@@ -66,7 +67,7 @@ const Login: React.FC = () => {
authContext.clearGlobalMessage();
// Use the srpUtil instance instead of the imported singleton
const loginResponse = await srpUtil.initiateLogin(credentials.username);
const loginResponse = await srpUtil.initiateLogin(ConversionUtility.normalizeUsername(credentials.username));
// 1. Derive key from password using Argon2id
const passwordHash = await EncryptionUtility.deriveKeyFromPassword(
@@ -84,7 +85,7 @@ const Login: React.FC = () => {
// 2. Validate login with SRP protocol
const validationResponse = await srpUtil.validateLogin(
credentials.username,
ConversionUtility.normalizeUsername(credentials.username),
passwordHashString,
rememberMe,
loginResponse
@@ -122,7 +123,7 @@ const Login: React.FC = () => {
}
// All is good. Store auth info which is required to make requests to the web API.
await authContext.setAuthTokens(credentials.username, validationResponse.token.token, validationResponse.token.refreshToken);
await authContext.setAuthTokens(ConversionUtility.normalizeUsername(credentials.username), validationResponse.token.token, validationResponse.token.refreshToken);
// Initialize the SQLite context with the new vault data.
await dbContext.initializeDatabase(vaultResponseJson, passwordHashBase64);
@@ -164,7 +165,7 @@ const Login: React.FC = () => {
}
const validationResponse = await srpUtil.validateLogin2Fa(
credentials.username,
ConversionUtility.normalizeUsername(credentials.username),
passwordHashString,
rememberMe,
loginResponse,
@@ -189,7 +190,7 @@ const Login: React.FC = () => {
}
// All is good. Store auth info which is required to make requests to the web API.
await authContext.setAuthTokens(credentials.username, validationResponse.token.token, validationResponse.token.refreshToken);
await authContext.setAuthTokens(ConversionUtility.normalizeUsername(credentials.username), validationResponse.token.token, validationResponse.token.refreshToken);
// Initialize the SQLite context with the new vault data.
await dbContext.initializeDatabase(vaultResponseJson, passwordHashBase64);

View File

@@ -1,5 +1,7 @@
/**
* Utility class for conversion operations.
* TODO: make this a shared utility class in root /shared/ folder so we can reuse it between browser extension/mobile app
* and possibly WASM client.
*/
class ConversionUtility {
/**
@@ -49,6 +51,15 @@ class ConversionUtility {
return html;
}
}
/**
* Normalize a username by converting it to lowercase and trimming whitespace.
* @param username The username to normalize.
* @returns The normalized username.
*/
public normalizeUsername(username: string): string {
return username.toLowerCase().trim();
}
}
export default new ConversionUtility();

View File

@@ -6,7 +6,7 @@ export default defineConfig({
manifest: {
name: "AliasVault",
description: "AliasVault Browser AutoFill Extension. Keeping your personal information private.",
version: "0.18.0",
version: "0.18.1",
content_security_policy: {
extension_pages: "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
},

View File

@@ -93,8 +93,8 @@ android {
applicationId 'net.aliasvault.app'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 3
versionName "0.18.0"
versionCode 4
versionName "0.18.1"
}
signingConfigs {
debug {

View File

@@ -2,7 +2,7 @@
"expo": {
"name": "AliasVault",
"slug": "AliasVault",
"version": "0.18.0",
"version": "0.18.1",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "net.aliasvault.app",

View File

@@ -201,7 +201,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
</ThemedText>
{!hasBiometrics && (
<ThemedText style={[styles.helpText, { color: colors.errorBorder }]}>
{biometricDisplayName} is blocked in device settings. Tap to open settings and enable it.
{biometricDisplayName} is not available. Tap to open settings and/or go to your device settings to enable and configure it.
</ThemedText>
)}
</TouchableOpacity>

View File

@@ -24,6 +24,7 @@ import { VaultResponse } from '@/utils/types/webapi/VaultResponse';
import { EncryptionKeyDerivationParams } from '@/utils/types/messaging/EncryptionKeyDerivationParams';
import { useVaultSync } from '@/hooks/useVaultSync';
import { InAppBrowserView } from '@/components/ui/InAppBrowserView';
import ConversionUtility from '@/utils/ConversionUtility';
/**
* Login screen.
@@ -105,48 +106,61 @@ export default function LoginScreen() : React.ReactNode {
) : Promise<void> => {
// Get biometric display name
const biometricDisplayName = await authContext.getBiometricDisplayName();
const isBiometricsEnabledOnDevice = await authContext.isBiometricsEnabledOnDevice();
// Show biometric prompt
Alert.alert(
`Enable ${biometricDisplayName}?`,
`Would you like to use ${biometricDisplayName} to unlock your vault?`,
[
{
text: 'No',
style: 'destructive',
/**
* Handle disabling biometric authentication
*/
onPress: async () : Promise<void> => {
await authContext.setAuthMethods(['password']);
await continueProcessVaultResponse(
token,
refreshToken,
vaultResponseJson,
passwordHashBase64,
initiateLoginResponse
);
if (isBiometricsEnabledOnDevice) {
// Show biometric prompt if biometrics are available (faceid or fingerprint enrolled) on device.
Alert.alert(
`Enable ${biometricDisplayName}?`,
`Would you like to use ${biometricDisplayName} to unlock your vault?`,
[
{
text: 'No',
style: 'destructive',
/**
* Handle disabling biometric authentication
*/
onPress: async () : Promise<void> => {
await authContext.setAuthMethods(['password']);
await continueProcessVaultResponse(
token,
refreshToken,
vaultResponseJson,
passwordHashBase64,
initiateLoginResponse
);
}
},
{
text: 'Yes',
isPreferred: true,
/**
* Handle enabling biometric authentication
*/
onPress: async () : Promise<void> => {
await authContext.setAuthMethods(['faceid', 'password']);
await continueProcessVaultResponse(
token,
refreshToken,
vaultResponseJson,
passwordHashBase64,
initiateLoginResponse
);
}
}
},
{
text: 'Yes',
isPreferred: true,
/**
* Handle enabling biometric authentication
*/
onPress: async () : Promise<void> => {
await authContext.setAuthMethods(['faceid', 'password']);
await continueProcessVaultResponse(
token,
refreshToken,
vaultResponseJson,
passwordHashBase64,
initiateLoginResponse
);
}
}
]
);
]
);
} else {
// If biometrics are not available on device, only allow password authentication.
await authContext.setAuthMethods(['password']);
await continueProcessVaultResponse(
token,
refreshToken,
vaultResponseJson,
passwordHashBase64,
initiateLoginResponse
);
}
};
/**
@@ -172,7 +186,7 @@ export default function LoginScreen() : React.ReactNode {
};
// Set auth tokens, store encryption key and key derivation params, and initialize database
await authContext.setAuthTokens(credentials.username, token, refreshToken);
await authContext.setAuthTokens(ConversionUtility.normalizeUsername(credentials.username), token, refreshToken);
await dbContext.storeEncryptionKey(passwordHashBase64);
await dbContext.storeEncryptionKeyDerivationParams(encryptionKeyDerivationParams);
await dbContext.initializeDatabase(vaultResponseJson);
@@ -227,7 +241,7 @@ export default function LoginScreen() : React.ReactNode {
try {
authContext.clearGlobalMessage();
const initiateLoginResponse = await srpUtil.initiateLogin(credentials.username);
const initiateLoginResponse = await srpUtil.initiateLogin(ConversionUtility.normalizeUsername(credentials.username));
const passwordHash = await EncryptionUtility.deriveKeyFromPassword(
credentials.password,
@@ -242,7 +256,7 @@ export default function LoginScreen() : React.ReactNode {
setLoginStatus('Validating credentials');
await new Promise(resolve => requestAnimationFrame(resolve));
const validationResponse = await srpUtil.validateLogin(
credentials.username,
ConversionUtility.normalizeUsername(credentials.username),
passwordHashString,
rememberMe,
initiateLoginResponse
@@ -317,7 +331,7 @@ export default function LoginScreen() : React.ReactNode {
}
const validationResponse = await srpUtil.validateLogin2Fa(
credentials.username,
ConversionUtility.normalizeUsername(credentials.username),
passwordHashString,
rememberMe,
initiateLoginResponse,

View File

@@ -32,6 +32,7 @@ type AuthContextType = {
getAutoLockTimeout: () => Promise<number>;
setAutoLockTimeout: (timeout: number) => Promise<void>;
getBiometricDisplayName: () => Promise<string>;
isBiometricsEnabledOnDevice: () => Promise<boolean>;
setOfflineMode: (isOffline: boolean) => void;
verifyPassword: (password: string) => Promise<string | null>;
// Autofill methods
@@ -91,13 +92,30 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
}, []);
/**
* Check if biometrics is enabled on the device (regardless of whether it's enabled in the AliasVault app).
*/
const isBiometricsEnabledOnDevice = useCallback(async (): Promise<boolean> => {
const hasBiometrics = await LocalAuthentication.hasHardwareAsync();
if (!hasBiometrics) {
return false;
}
return await LocalAuthentication.isEnrolledAsync();
}, []);
/**
* Check if biometrics is enabled based on enabled auth methods
*/
const isBiometricsEnabled = useCallback(async (): Promise<boolean> => {
const deviceHasBiometrics = await isBiometricsEnabledOnDevice();
if (!deviceHasBiometrics) {
return false;
}
const methods = await getEnabledAuthMethods();
return methods.includes('faceid');
}, [getEnabledAuthMethods]);
}, [getEnabledAuthMethods, isBiometricsEnabledOnDevice]);
/**
* Set auth tokens in storage as part of the login process. After db is initialized, the login method should be called as well.
@@ -222,8 +240,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const methods = await getEnabledAuthMethods();
if (methods.includes('faceid')) {
try {
const isEnrolled = await LocalAuthentication.isEnrolledAsync();
if (isEnrolled) {
if (await isBiometricsEnabledOnDevice()) {
return await getBiometricDisplayName();
}
} catch (error) {
@@ -231,7 +248,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
}
return 'Password';
}, [getEnabledAuthMethods, getBiometricDisplayName]);
}, [getEnabledAuthMethods, getBiometricDisplayName, isBiometricsEnabledOnDevice]);
/**
* Get the auto-lock timeout from the iOS credentials manager
@@ -374,6 +391,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
clearGlobalMessage,
setAuthMethods,
getAuthMethodDisplay,
isBiometricsEnabledOnDevice,
getAutoLockTimeout,
setAutoLockTimeout,
getBiometricDisplayName,
@@ -398,6 +416,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
clearGlobalMessage,
setAuthMethods,
getAuthMethodDisplay,
isBiometricsEnabledOnDevice,
getAutoLockTimeout,
setAutoLockTimeout,
getBiometricDisplayName,

View File

@@ -1035,7 +1035,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = AliasVault/AliasVault.entitlements;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -1050,7 +1050,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1074,7 +1074,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = AliasVault/AliasVault.entitlements;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
INFOPLIST_FILE = AliasVault/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AliasVault;
@@ -1084,7 +1084,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1128,7 +1128,6 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -1191,7 +1190,6 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -1230,7 +1228,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1283,7 +1281,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1332,7 +1330,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1367,7 +1365,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1400,7 +1398,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1453,7 +1451,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1502,7 +1500,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1554,7 +1552,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8PHW4HN3F7;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1605,7 +1603,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = autofill/autofill.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1621,7 +1619,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
@@ -1650,7 +1648,7 @@
CODE_SIGN_ENTITLEMENTS = autofill/autofill.entitlements;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 6;
CURRENT_PROJECT_VERSION = 7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8PHW4HN3F7;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1666,7 +1664,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 0.18.0;
MARKETING_VERSION = 0.18.1;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = net.aliasvault.app.autofill;

View File

@@ -178,7 +178,12 @@ public class CredentialProviderViewController: ASCredentialProviderViewControlle
// Check if Face ID/Touch ID is enabled
let context = LAContext()
var authMethod = "Face ID / Touch ID"
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
var biometricsAvailable = false
var biometricsError: NSError?
// Check if device supports biometrics
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &biometricsError) {
biometricsAvailable = true
switch context.biometryType {
case .faceID:
authMethod = "Face ID"
@@ -189,6 +194,24 @@ public class CredentialProviderViewController: ASCredentialProviderViewControlle
}
}
// First check if biometrics are available on the device
if !biometricsAvailable {
let alert = UIAlertController(
title: "\(authMethod) Required",
message: "To use AliasVault Autofill, please enable \(authMethod) in your device settings and/or go to the AliasVault app settings to configure it.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] _ in
self?.extensionContext.cancelRequest(withError: NSError(
domain: ASExtensionErrorDomain,
code: ASExtensionError.userCanceled.rawValue
))
})
present(alert, animated: true)
return false
}
// Then check if Face ID/Touch ID is enabled in the app settings
if !vaultStore.getAuthMethods().contains(.faceID) {
let alert = UIAlertController(
title: "\(authMethod) Required",

View File

@@ -8,7 +8,7 @@ export class AppInfo {
/**
* The current extension version. This should be updated with each release of the extension.
*/
public static readonly VERSION = '0.18.0';
public static readonly VERSION = '0.18.1';
/**
* The minimum supported AliasVault server (API) version. If the server version is below this, the

View File

@@ -0,0 +1,17 @@
/**
* Utility class for conversion operations.
* TODO: make this a shared utility class in root /shared/ folder so we can reuse it between
* browser extension/mobile app and possibly WASM client.
*/
class ConversionUtility {
/**
* Normalize a username by converting it to lowercase and trimming whitespace.
* @param username The username to normalize.
* @returns The normalized username.
*/
public normalizeUsername(username: string): string {
return username.toLowerCase().trim();
}
}
export default new ConversionUtility();

View File

@@ -30,7 +30,7 @@ public static class AppInfo
/// <summary>
/// Gets the patch version number.
/// </summary>
public const int VersionPatch = 0;
public const int VersionPatch = 1;
/// <summary>
/// Gets the minimum supported AliasVault client version. Normally the minimum client version is the same

View File

@@ -80,6 +80,11 @@ get_browser_extension_version() {
grep "version: " ../apps/browser-extension/wxt.config.ts | head -n1 | tr -d '"' | tr -d ',' | tr -d ' ' | cut -d':' -f2
}
# Function to extract version from browser extension package.json
get_package_json_version() {
grep "\"version\": " ../apps/browser-extension/package.json | tr -d '"' | tr -d ',' | tr -d ' ' | cut -d':' -f2
}
# Function to extract version from mobile app
get_mobile_app_version() {
grep "\"version\": " ../apps/mobile-app/app.json | tr -d '"' | tr -d ',' | tr -d ' ' | cut -d':' -f2
@@ -107,7 +112,8 @@ get_safari_version() {
# Check current versions
echo "Checking current versions..."
server_version=$(get_server_version)
browser_version=$(get_browser_extension_version)
browser_wxt_version=$(get_browser_extension_version)
browser_package_version=$(get_package_json_version)
mobile_version=$(get_mobile_app_version)
mobile_ts_version=$(get_mobile_app_ts_version)
ios_version=$(get_ios_version)
@@ -117,7 +123,8 @@ safari_version=$(get_safari_version)
# Create associative array of versions
declare -A versions
versions["server"]="$server_version"
versions["browser"]="$browser_version"
versions["browser_wxt"]="$browser_wxt_version"
versions["browser_package"]="$browser_package_version"
versions["mobile"]="$mobile_version"
versions["mobile_ts"]="$mobile_ts_version"
versions["ios"]="$ios_version"
@@ -127,7 +134,8 @@ versions["safari"]="$safari_version"
# Create display names for output
declare -A display_names
display_names["server"]="Server"
display_names["browser"]="Browser Extension"
display_names["browser_wxt"]="Browser Extension (wxt.config.ts)"
display_names["browser_package"]="Browser Extension (package.json)"
display_names["mobile"]="Mobile App"
display_names["mobile_ts"]="Mobile App (TS)"
display_names["ios"]="iOS App"
@@ -195,6 +203,12 @@ update_version "../apps/browser-extension/wxt.config.ts" \
"version: \"[0-9]\+\.[0-9]\+\.[0-9]\+\"," \
"version: \"$version\","
# Update package.json version
echo "Updating package.json version..."
update_version "../apps/browser-extension/package.json" \
"\"version\": \"[0-9]\+\.[0-9]\+\.[0-9]\+\"," \
"\"version\": \"$version\","
# Update generic mobile app version
echo "Updating mobile app version..."
update_version "../apps/mobile-app/utils/AppInfo.ts" \