Git Product home page Git Product logo

2fas-android's Introduction

Open Source 2FAS for Android

This is the official Android app for the Open Source 2FAS project.

What is 2FAS?

2FAS (Two-Factor Authentication Service) is a user authentication method that provides an additional layer of security for online accounts. In addition to a username and password, 2FAS uses a second factor, such as a one-time password (OTP) shown on a user's phone, to verify a user's identity. This helps prevent unauthorized access to accounts, even if a password is compromised.

Features

  • Support for time-based one-time passwords (TOTP) and HMAC-based on-time passwords (HOTP)
  • Compatible with any service that supports the TOTP and HOTP standard, including Google, Microsoft, and Dropbox
  • Easy to set up and use

Graphics

Please note that the graphics used in this app are not part of the open source project and are subject to their own separate licensing terms.

Bug Reporting

We use GitHub for bug reports. Please visit the 2FAS for Android issues page to search for and report any bugs you may have found. Before adding a new issue, please search for existing issues to avoid duplicates.

For reporting security issues only, please send a detailed description of the vulnerability to [email protected]. Do not use this address for general inquiries or bug reports unrelated to security concerns.

Getting Started

  1. Download the app from the releases page.
  2. Install the app on your Android device.
  3. Follow the on-screen instructions to set up 2FAS for your online accounts.

Contributing

We welcome contributions to the Open Source 2FAS project. If you would like to contribute, please see the contribution guide.

Donations

If you would like to support the development of the Open Source 2FAS project, you can make a donation. All donations will be used to support the ongoing development and maintenance of the project.

We appreciate your support!

License

Copyright (c) Two Factor Authentication Service, Inc. All rights reserved.

Licensed under the GNU General Public License v3.0.

2fas-android's People

Contributors

2fas-com avatar finefindus avatar grzegorzzajac000 avatar in-void avatar kobew50 avatar rafakob avatar zacharee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

2fas-android's Issues

Help me get my data back

I made a backup of the data using a third-party application and then restored the application through it, but for some reason, for some reason, after the restoration, the application crashes

2FAS Android can retry password again and again

Install 2FAS Android in a new phone. Enable Cloud sync. If the backup has password enabled, 2FAS will ask for password. Input some wrong password, the application allow the user to try again and again.

Correct behaviour is after 3 or 5 times of fail, 2FAS should delay retry for some time since possible an attack is on going.

Support AndOTP import

It would be great if there was an import option for AndOTP. Unfortunately, AndOTP is no longer being developed, it is also open source and I think your software is an appropriate replacement.

Cannot receive notification from browser extension

Hi Team,
I am new to this OTP app which has a very nice UI. I tried but cannot receive notifications from browser extension on my Android.
Steps:

  1. Go to a page with OTP login on browser and press Ctrl+Shift+2
  2. I can see a pop-up from extension but didn't receive on my phone.
  3. I tried turning on the app / switching to notifications section and triggered Ctrl+Shift+2 again but still no notifications received.

Plz help me if I have something wrong or tell me how to troubleshoot(eg, what logs are needed)
Much thx for developing the app!

Grid layout on foldables

Just a suggestion for adding the grid layout seen in Google Play screenshots to foldable phones

Authy

Is there a way to import from authy at all?

Doesn't ask notification permission

Hi,

I just installed the app and it works great, except when I synced with the browser extension it was not sending push notifications. After a bit of digging notification permissions for the app were set to off in my phones settings (Pixel 5 on Android 13). I believe the app should have asked for permissions when I tried to set up the browser extension.

Please feel free to correct me if I am incorrect, I have not tried to replicate it.

Thanks!

Feature request: Integrate autofill for 2FAS

It would be nice if 2FAS used the autofill integration on Android, especially for keyboards (that supports it).

The use case being that a user would get the 2FAS prompt in the keyboard when the 2FAS application identifies that the user is in an app or on a website which the user has a 2FA account set up for in the 2FAS application. Clicking on this would ask the user to authenticate themself with their authentication method (PIN, Fingerprint) and then the token would automatically be filled out in the code input field on the website or in the app the user is currently in. See how other password managers solved this, such as Bitwarden etc.

https://developer.android.com/guide/topics/text/ime-autofill

I do apologize if this has been requested before, or if it's already on the roadmap as a planned feature.
It may also be that 2FA tokens work differently than password managers when it comes to the autofill integration on Android, so I am not sure about the feasibility of this feature request.

Thanks. :)

Lastpass Import support

Lastpass Authenticator can export as a plain text json file. I think it would be relatively simple to implement lastpass support.

Support for alternative synchronisation/targets

It would be great to be able to back up data to another destination as an alternative to Google. Besides Dropbox or OneDrive, I would find this much more interesting if SFTP or other protocols were supported (which are supported by systems like Synology NAS), where you can then also use the browser extension.

Task hijacking vulnerability

Hey there,

I want to report a task hijacking vulnerability I found on 2fas Android latest app version. Here is the explanation and the associated PoC I made to confirm the vulnerability.

Activities are organized into collections called "tasks". A task is a collection of activities that users interact with when trying to perform an action in an application. These activities are arranged in a stack called the Back Stack (keeping the opening order). In this way, when users want to return to the previous activity, the system just pops the activity at the top of this stack.

Activities also have different launch modes (specified as attributes within the AndroidManifest.xml file) which provide the underlying operating system with instructions on how they should be launched.

The "Task Hijacking" vulnerability concerns all devices running a version strictly inferior to Android 10. The 2fas application is therefore affected, since it can run on Android 6 devices (minSdk in the Appconfig.kt file is set to 23).

package com.twofasapp.buildlogic.version

object AppConfig {
    const val minSdk = 23
    const val targetSdk = 33
    const val compileSdk = 33

    private const val verMajor = 4
    private const val verMinor = 5
    private const val verPatch = 13
    private const val verInternal = 0

    const val versionCode = verMajor * 1000000 + verMinor * 10000 + verPatch * 100 + verInternal
    const val versionName = "${verMajor}.${verMinor}.${verPatch}"
    const val apkName = "TwoFas-${verMajor}.${verMinor}.${verPatch}-${verInternal}"
}

Also known as StrandHogg, this vulnerability was first demonstrated in 2015 and is mainly concerned with the "singleTask" mode. Indeed, one of the specific features of the "singleTask" activity is to allow other activities to be inserted at the root of its task.

As a result, 2fas is vulnerable to a number of task hijacking attacks. This problem is confirmed by examining the contents of the AndroidManifest.xml file :

  • 2 activities use the singleTask launch mode;
  • the android:taskAffinity attribute is not defined in the application tag.
 <application
        android:name="com.twofasapp.App"
        android:allowBackup="false"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/android__app_name"
        android:localeConfig="@xml/locales_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/Theme.App">

        [...]

        <!-- ACTIVITIES -->

        <activity
            android:name=".ui.main.StartActivity"
            android:exported="true"
            android:launchMode="singleTask"
            android:noHistory="false"
            android:screenOrientation="locked"
            android:theme="@style/Theme.App">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="otpauth" />
            </intent-filter>

        </activity>

        <activity
            android:launchMode="singleTask"
            android:name=".ui.main.MainActivity"
            android:label="Add service by scanning QR Code" />

A malicious application could therefore take advantage of this weakness to manipulate the way users interact with 2fas application. More precisely, this would involve placing a malicious activity at the root of its task. If this activity looks exactly like one of the 2fas views, a user could be fooled into performing some actions (enter information etc.). This could be useful in a phishing attempt.

Please see the following video which illustrates the previous explanation and do not hesitate to ask if needed :

PoC.webm

Best regards,

Translations

Why not just add a link here (on crowdin) to translate app?

(feature request) Immediately Lock The App

I observed that the app is missing the below features.

The app is not asking for the pin,

  1. After the phone is locked and unlocked.
  2. When 2fas app is opened from the recent apps.
  3. Accessing the app from recent apps list immediately.

Accessing the app from recent apps list immediately.

Open the 2fas app. Place it in the recent apps list by clicking on the recent app list button or gesture. Open it again from the recent apps list immediately. The app does not ask for the pin.


Ideally, for all the above cases the app must be locked immediately and ask for the pin to unlock.

Token for Namecheap being created with "Heap" as identifier

On 8/6/2023, when scanning the QR code for Namecheap.com, the entry for Namecheap was created as "Heap." This was attempted two times, and on both attempts the entry was created with the identifier "Heap."

An image is attached, and the bottom entry is the one I've mentioned above. You can log in to Namecheap just fine using the code generated, and I have manually renamed the entry and used the Namecheap logo that comes along with 2FAS, but this obviously should not be how this gets set up.

Also, and I do not know for certain whether there is a connection between these two things, the 2FAS browser extension will not work with Namecheap's website for me. It works just fine elsewhere, so I suspect that there may be some connection.

Device: Xiaomi Redmi Note 11 Pro+ 5G Model: 21091116UG
OS: MIUI Global 14.0.3.0 (TKTEUXM)
Android Version: 13 TP1A.220624.014
Android Security Update: 2023-02-01

Redacted

Support for automated backup

I am currently still using AndOTP. There is an option there to automatically create a backup file whenever changes are made. I use this to automatically store a backup on my NAS. Could you implement something similar?
It would be good if you could encrypt the backup with a password, then it can also be stored locally on the smartphone, where it is then saved.

Add donate link to the repository

The other repositories seem to have the sponsor button, however, this one does not have it.
It'd be great if it could be added, so that it has more promotion as well. ๐Ÿ™‚

Feature: Show/ or Search by Issuer

Background

Many other 2fa products show the issuer in text in some way.

Product Issuer
Aegis issuer (username)
Authy issuer: username

However, 2fas does not despite storing the info

Also it isn't possible to search by issuer. For example I might search for "Bitwarden", however I'm not likely to search for my log in email as I use this for many services

Feature

Please add the option to show the issuer in some way, or search by issuer

Thanks :)

Extension pair QR-code not scannable

Hello,

On 2FAS Android version 4.5.9 I'm not able to scan the QR-code for the extension. I believe the focus is working, and scanning QR-codes with any other app works perfectly fine.

Add importer from Authenticator Pro

Please add support for importing from Authenticator Pro, a popular 2-FA application. It provides backups as an encrypted JSON file, the encryption and decryption code can be found here.

I tried to port the code myself, but due to various problems in #18 I couldn't get the app to compile/run.

blank screen preview missed

with the last update, the app preview when pressed the recent app button on the navigation bar, in the past the app preview was empty screen, now after update, the app preview is not blank, that is a security hole, I liked the previous behavior

Translate to Arabic

Hi, can I contribute to translating 2FA to Arabic? I am ready if you agree.

App Crashes

I am a user of your 2fa app and I have been experiencing some issues with the browser extension QR code scanning. Whenever I try to scan the QR code, the app crashes abruptly. I would like to report this bug and seek your assistance.

I am using a Huawei Nova 5z mobile phone with the HarmonyOS 3.0.0.165 operating system. Would it be possible for you to investigate this issue and provide a fix for it?

Thank you for your attention to this matter.

Export to CSV

Would it be possible to add a feature to export to a CSV?

Feature Request: full Material you support

I had suggested this feature a year back on discord but it seems forgotten. So creating a GitHub to keep a track on.

Since the app uses md3 elements, we would appreciate dynamic color theming based on the user's wallpaper as an optional switch toggle keeping the app's brand colors as default as discussed on discord.

Automatically change icon

When I manually enter a code, I have to enter the name of the application, then find and select the corresponding icon.

Why not change the icon automatically thanks to the name of the entry? Or at least offer one or more suggestions?

Failed to apply plugin 'twofas.androidApplication'.

I just tried to build the app, but wasn't able to. It crashes with the error

An exception occurred applying plugin request [id: 'twofas.androidApplication', version: 'unspecified']
> Failed to apply plugin 'twofas.androidApplication'.
Logs
Build file '/home/user/Documents/dev/git/2fas-android/app/build.gradle.kts' line: 2

An exception occurred applying plugin request [id: 'twofas.androidApplication', version: 'unspecified']
> Failed to apply plugin 'twofas.androidApplication'.
   > /home/user/Documents/dev/git/2fas-android/config/config.properties (No such file or directory)

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Exception is:
org.gradle.api.plugins.InvalidPluginException: An exception occurred applying plugin request [id: 'twofas.androidApplication', version: 'unspecified']
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.exceptionOccurred(DefaultPluginRequestApplicator.java:222)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugin(DefaultPluginRequestApplicator.java:204)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyLegacyPlugin(DefaultPluginRequestApplicator.java:157)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.access$300(DefaultPluginRequestApplicator.java:60)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator$1$1.lambda$addLegacy$0(DefaultPluginRequestApplicator.java:113)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.lambda$applyPlugins$0(DefaultPluginRequestApplicator.java:142)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:142)
	at org.gradle.kotlin.dsl.provider.PluginRequestsHandler.handle(PluginRequestsHandler.kt:48)
	at org.gradle.kotlin.dsl.provider.StandardKotlinScriptEvaluator$InterpreterHost.applyPluginsTo(KotlinScriptEvaluator.kt:202)
	at org.gradle.kotlin.dsl.execution.Interpreter$ProgramHost.applyPluginsTo(Interpreter.kt:405)
	at Program.execute(Unknown Source)
	at org.gradle.kotlin.dsl.execution.Interpreter$ProgramHost.eval(Interpreter.kt:540)
	at org.gradle.kotlin.dsl.execution.Interpreter.eval(Interpreter.kt:210)
	at org.gradle.kotlin.dsl.provider.StandardKotlinScriptEvaluator.evaluate(KotlinScriptEvaluator.kt:118)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:51)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPluginFactory$create$1.invoke(KotlinScriptPluginFactory.kt:48)
	at org.gradle.kotlin.dsl.provider.KotlinScriptPlugin.apply(KotlinScriptPlugin.kt:34)
	at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
	at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:388)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:406)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:387)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42)
	at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26)
	at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:109)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:388)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$fromMutableState$1(DefaultProjectStateRegistry.java:411)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withReplacedLocks(DefaultWorkerLeaseService.java:345)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:411)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:387)
	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:100)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:72)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:792)
	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:156)
	at org.gradle.api.internal.project.ProjectLifecycleController.lambda$ensureSelfConfigured$2(ProjectLifecycleController.java:84)
	at org.gradle.internal.model.StateTransitionController.lambda$doTransition$13(StateTransitionController.java:247)
	at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:258)
	at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:246)
	at org.gradle.internal.model.StateTransitionController.lambda$maybeTransitionIfNotCurrentlyTransitioning$10(StateTransitionController.java:207)
	at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
	at org.gradle.internal.model.StateTransitionController.maybeTransitionIfNotCurrentlyTransitioning(StateTransitionController.java:203)
	at org.gradle.api.internal.project.ProjectLifecycleController.ensureSelfConfigured(ProjectLifecycleController.java:84)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.ensureConfigured(DefaultProjectStateRegistry.java:362)
	at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:33)
	at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:49)
	at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:42)
	at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64)
	at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
	at org.gradle.initialization.VintageBuildModelController.lambda$prepareProjects$2(VintageBuildModelController.java:84)
	at org.gradle.internal.model.StateTransitionController.lambda$doTransition$13(StateTransitionController.java:247)
	at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:258)
	at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:246)
	at org.gradle.internal.model.StateTransitionController.lambda$transitionIfNotPreviously$11(StateTransitionController.java:221)
	at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:34)
	at org.gradle.internal.model.StateTransitionController.transitionIfNotPreviously(StateTransitionController.java:217)
	at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:84)
	at org.gradle.initialization.VintageBuildModelController.getConfiguredModel(VintageBuildModelController.java:64)
	at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$withProjectsConfigured$1(DefaultBuildLifecycleController.java:116)
	at org.gradle.internal.model.StateTransitionController.lambda$notInState$4(StateTransitionController.java:154)
	at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
	at org.gradle.internal.model.StateTransitionController.notInState(StateTransitionController.java:150)
	at org.gradle.internal.build.DefaultBuildLifecycleController.withProjectsConfigured(DefaultBuildLifecycleController.java:116)
	at org.gradle.internal.build.DefaultBuildToolingModelController.locateBuilderForTarget(DefaultBuildToolingModelController.java:57)
	at org.gradle.internal.buildtree.DefaultBuildTreeModelCreator$DefaultBuildTreeModelController.lambda$locateBuilderForTarget$0(DefaultBuildTreeModelCreator.java:73)
	at org.gradle.internal.build.DefaultBuildLifecycleController.withToolingModels(DefaultBuildLifecycleController.java:185)
	at org.gradle.internal.build.AbstractBuildState.withToolingModels(AbstractBuildState.java:134)
	at org.gradle.internal.buildtree.DefaultBuildTreeModelCreator$DefaultBuildTreeModelController.locateBuilderForTarget(DefaultBuildTreeModelCreator.java:73)
	at org.gradle.internal.buildtree.DefaultBuildTreeModelCreator$DefaultBuildTreeModelController.locateBuilderForDefaultTarget(DefaultBuildTreeModelCreator.java:68)
	at org.gradle.tooling.internal.provider.runner.DefaultBuildController.getTarget(DefaultBuildController.java:157)
	at org.gradle.tooling.internal.provider.runner.DefaultBuildController.getModel(DefaultBuildController.java:101)
	at org.gradle.tooling.internal.consumer.connection.ParameterAwareBuildControllerAdapter.getModel(ParameterAwareBuildControllerAdapter.java:39)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.getModel(UnparameterizedBuildController.java:113)
	at org.gradle.tooling.internal.consumer.connection.NestedActionAwareBuildControllerAdapter.getModel(NestedActionAwareBuildControllerAdapter.java:31)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.findModel(UnparameterizedBuildController.java:97)
	at org.gradle.tooling.internal.consumer.connection.NestedActionAwareBuildControllerAdapter.findModel(NestedActionAwareBuildControllerAdapter.java:31)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.findModel(UnparameterizedBuildController.java:81)
	at org.gradle.tooling.internal.consumer.connection.NestedActionAwareBuildControllerAdapter.findModel(NestedActionAwareBuildControllerAdapter.java:31)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.findModel(UnparameterizedBuildController.java:66)
	at org.gradle.tooling.internal.consumer.connection.NestedActionAwareBuildControllerAdapter.findModel(NestedActionAwareBuildControllerAdapter.java:31)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:125)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:42)
	at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter.execute(InternalBuildActionAdapter.java:64)
	at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner$ActionAdapter.runAction(AbstractClientProvidedBuildActionRunner.java:131)
	at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner$ActionAdapter.beforeTasks(AbstractClientProvidedBuildActionRunner.java:99)
	at org.gradle.internal.buildtree.DefaultBuildTreeModelCreator.beforeTasks(DefaultBuildTreeModelCreator.java:52)
	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$fromBuildModel$2(DefaultBuildTreeLifecycleController.java:74)
	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$4(DefaultBuildTreeLifecycleController.java:98)
	at org.gradle.internal.model.StateTransitionController.lambda$transition$6(StateTransitionController.java:177)
	at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:258)
	at org.gradle.internal.model.StateTransitionController.lambda$transition$7(StateTransitionController.java:177)
	at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
	at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:177)
	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:95)
	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.fromBuildModel(DefaultBuildTreeLifecycleController.java:73)
	at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner.runClientAction(AbstractClientProvidedBuildActionRunner.java:43)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:53)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:49)
	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:65)
	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:140)
	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:122)
	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
	at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:65)
	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:65)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:36)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:249)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:109)
	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:36)
	at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:110)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
	at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:100)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter$ActionImpl.apply(BuildSessionLifecycleBuildActionExecuter.java:88)
	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:62)
	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:41)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:50)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:38)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
	at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin 'twofas.androidApplication'.
	at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:173)
	at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:146)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.lambda$applyLegacyPlugin$2(DefaultPluginRequestApplicator.java:159)
	at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugin(DefaultPluginRequestApplicator.java:199)
	... 189 more
Caused by: org.gradle.internal.operations.BuildOperationInvocationException: /home/user/Documents/dev/git/2fas-android/config/config.properties (No such file or directory)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.throwAsBuildOperationInvocationException(DefaultBuildOperationRunner.java:192)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.access$100(DefaultBuildOperationRunner.java:24)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.api.internal.plugins.DefaultPluginManager.lambda$doApply$0(DefaultPluginManager.java:167)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
	at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:166)
	... 192 more
Caused by: java.io.FileNotFoundException: /home/user/Documents/dev/git/2fas-android/config/config.properties (No such file or directory)
	at com.twofasapp.buildlogic.extension.SigningConfigsKt.applySigningConfigs(SigningConfigs.kt:15)
	at com.twofasapp.buildlogic.TwoFasAndroidApplicationPlugin$apply$1$3.invoke(TwoFasAndroidApplicationPlugin.kt:27)
	at com.twofasapp.buildlogic.TwoFasAndroidApplicationPlugin$apply$1$3.invoke(TwoFasAndroidApplicationPlugin.kt:25)
	at com.twofasapp.buildlogic.TwoFasAndroidApplicationPlugin$inlined$sam$i$org_gradle_api_Action$0.execute(ExtensionContainerExtensions.kt)
	at org.gradle.internal.extensibility.ExtensionsStorage$ExtensionHolder.configure(ExtensionsStorage.java:173)
	at org.gradle.internal.extensibility.ExtensionsStorage.configureExtension(ExtensionsStorage.java:70)
	at org.gradle.internal.extensibility.DefaultConvention.configure(DefaultConvention.java:190)
	at com.twofasapp.buildlogic.TwoFasAndroidApplicationPlugin.apply(TwoFasAndroidApplicationPlugin.kt:56)
	at com.twofasapp.buildlogic.TwoFasAndroidApplicationPlugin.apply(TwoFasAndroidApplicationPlugin.kt:13)
	at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:43)
	at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
	at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:187)
	at org.gradle.api.internal.plugins.DefaultPluginManager.access$100(DefaultPluginManager.java:52)
	at org.gradle.api.internal.plugins.DefaultPluginManager$AddPluginBuildOperation.run(DefaultPluginManager.java:282)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	... 200 more

Ability to add custom logo

Migrating from Authy to 2FAS, and noticing a lot of site logos that are missing. The "change the color and 2 letters" customization is good, but would be nice to be able to give a URL to a logo to be used (or otherwise somehow paste in an image).

Feature request: add AppConfig for MDM

Mobile device management (MDM) is using AppConfig standard to preset and configure settings so apps can be mass deployed to devices: https://www.appconfig.org.

I think these options should be available:

  • option that passcode is required
  • toggle/hide Backup functionality
  • toggle/hide biometric option
  • preset lockout settings
  • toggle/hide browser extension

(feature request) Confirm PIN without tapping OK

Please provide a round checkbox option in Security -> PIN code to ' Confirm PIN without tapping OK '.

It should appear above or below the 'Please enter your new n-digit code PIN' dialogue when a PIN is being set or changed.


  • If the round checkbox is selected, then the app pin display will be same as now.
  • If the round checkbox is not selected, then the app pin display will have 'OK' button beside 0 (zero) on the right side.
  • And will not unlock the phone directly, but 'OK' should be clicked.

Allow spaces in export password

Hey everyone!
In the process of switching away from Authy where I can and onto 2FAS because so far it looks pretty solid.
Clean design, cool "next token" functionality, backup to GDrive (and also into a password-protected file)

I wanted to test export my vault just now with a password that contains spaces (rather, a passphrase)
However, it threw an error that spaces aren't supported.
Upon checking the code, it seems to not be included in the regex here:

password.matches(Regex("([A-Za-z0-9*.!@#\$%^&(){}\\[\\]:;<>,?/~_+-=|']+)"))

Is this a limitation in your encryption code or simply something that you guys didn't consider when writing that regex?

Thought I'd open an issue about this since I didn't see another one yet :)

On another note, thank you for such a great app! Already liking it!

Crash when pairing with 4.6.0

With 4.6.0 I can no longer pair new services. Clicking the button simply causes the app to crash. I downgraded and verified that 4.5.14 works fine.

I sent a crash report using android and here is a screenshot of it
image

Official APK on Releases

Good morning,

Would it be possible to add the official full APK (with all the required dependencies/libraries) on the "releases" section?
https://github.com/twofas/2fas-android/releases

The APK is not available on the official website either even though README.md file found here https://github.com/twofas/2fas-android#getting-started makes it look like you can download the APK.

Some of us would like to use 2FAS but we don't have access to download it through the Google Play Store.
Having the official full APK with all the required dependencies/libraries on the "releases" section would allow us to sideload the app on non Google Android devices like Amazon Tablets (since the 2FAS app it's not available on the Amazon AppStore).
It would be really useful.

Thanks in advance.

Feature Request: publish to F-Droid

Some people have Android (or Linux) devices that are unable to use the Google Play Store or choose not to use the Google Play Store. I spent a quick minute understanding F-Droid submissions (I am not a mobile developer) https://gitlab.com/fdroid/fdroiddata/blob/master/CONTRIBUTING.md

It looks like it involves a pull request with the metadata and a recipe for building. After that F-Droid builds the application from source.

My main use case is that I have a faulty phone with the 2fas app and now it's in a failed boot loop, so I need to be able to load another device with the application, but I don't have Play Store or App Store as an option.

[Feature Request] Allow export via JSON.

Hello,

I want you to add the ability to export my 2FA keys via a JSON file rather than a .2fas file since most TOTP apps supports that standard format and doesn't support .2fas files.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.