Bubka / 2FAuth

A Web app to manage your Two-Factor Authentication (2FA) accounts and generate their security codes
https://docs.2fauth.app/
GNU Affero General Public License v3.0
1.96k stars 133 forks source link

Can't decipher codes after updating to 5.1.0 #324

Closed despokd closed 5 months ago

despokd commented 5 months ago

Version

5.1.0

Details & Steps to reproduce

  1. Update from 5.0.4 to 5.1.0 1.1. git fetch 1.2 curl https://api.github.com/repos/Bubka/2FAuth/releases/latest | grep "\"name\"" | grep -Eo 'v[^\"]*' | xargs git checkout 1.3 /usr/local/php8.2/bin/php artisan 2fauth:install (no .env changes)
  2. Login

Returns error The secret cannot be decrypted. This is mainly caused by an incorrectly set APP_KEY in the .env configuration file of 2Fauth or by corrupted data in the database. image

Expectation

Opens working dashboard after login

Error & Logs

[2024-03-18 07:23:52] local.ERROR: Secret cannot be deciphered, OTP generation aborted
[2024-03-18 07:23:52] local.ERROR:  {"userId":1,"exception":"[object] (App\\Exceptions\\UndecipherableException(code: 0):  at /home/PATH_TO_2FAUTH/app/Models/TwoFAccount.php:363)
[stacktrace]
#0 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): App\\Models\\TwoFAccount->getOTP()
#1 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/DelegatesToResource.php(155): Illuminate\\Http\\Resources\\Json\\JsonResource->forwardCallTo()
#2 /home/PATH_TO_2FAUTH/app/Api/v1/Resources/TwoFAccountReadResource.php(34): Illuminate\\Http\\Resources\\Json\\JsonResource->__call()
#3 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Collections/helpers.php(224): App\\Api\\v1\\Resources\\TwoFAccountReadResource->App\\Api\\v1\\Resources\\{closure}()
#4 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php(106): value()
#5 /home/PATH_TO_2FAUTH/app/Api/v1/Resources/TwoFAccountReadResource.php(28): Illuminate\\Http\\Resources\\Json\\JsonResource->when()
#6 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(107): App\\Api\\v1\\Resources\\TwoFAccountReadResource->toArray()
#7 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(254): Illuminate\\Http\\Resources\\Json\\JsonResource->resolve()
#8 [internal function]: Illuminate\\Http\\Resources\\Json\\JsonResource->jsonSerialize()
#9 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(84): json_encode()
#10 /home/PATH_TO_2FAUTH/vendor/symfony/http-foundation/JsonResponse.php(49): Illuminate\\Http\\JsonResponse->setData()
#11 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(32): Symfony\\Component\\HttpFoundation\\JsonResponse->__construct()
#12 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php(101): Illuminate\\Http\\JsonResponse->__construct()
#13 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceResponse.php(37): Illuminate\\Routing\\ResponseFactory->json()
#14 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php(244): Illuminate\\Http\\Resources\\Json\\ResourceResponse->toResponse()
#15 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php(117): Illuminate\\Http\\Resources\\Json\\JsonResource->toResponse()
#16 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(900): Illuminate\\Http\\Resources\\Json\\ResourceCollection->toResponse()
#17 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(885): Illuminate\\Routing\\Router::toResponse()
#18 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(805): Illuminate\\Routing\\Router->prepareResponse()
#19 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#20 /home/PATH_TO_2FAUTH/app/Http/Middleware/LogUserLastSeen.php(34): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#21 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): App\\Http\\Middleware\\LogUserLastSeen->handle()
#22 /home/PATH_TO_2FAUTH/app/Http/Middleware/KickOutInactiveUser.php(47): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#23 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): App\\Http\\Middleware\\KickOutInactiveUser->handle()
#24 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#25 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#26 /home/PATH_TO_2FAUTH/app/Http/Middleware/SetLanguage.php(68): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#27 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): App\\Http\\Middleware\\SetLanguage->handle()
#28 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#29 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#30 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(159): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#31 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(125): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest()
#32 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(87): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequestUsingNamedLimiter()
#33 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle()
#34 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#35 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(805): Illuminate\\Pipeline\\Pipeline->then()
#36 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(784): Illuminate\\Routing\\Router->runRouteWithinStack()
#37 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(748): Illuminate\\Routing\\Router->runRoute()
#38 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Routing/Router.php(737): Illuminate\\Routing\\Router->dispatchToRoute()
#39 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\\Routing\\Router->dispatch()
#40 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(144): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#41 /home/PATH_TO_2FAUTH/app/Http/Middleware/ForceJsonResponse.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#42 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): App\\Http\\Middleware\\ForceJsonResponse->handle()
#43 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#44 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#45 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#46 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#47 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#48 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#49 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#50 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#51 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(99): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#52 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#53 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(62): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#54 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Http\\Middleware\\HandleCors->handle()
#55 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#56 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(183): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#57 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(119): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#58 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then()
#59 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#60 /home/PATH_TO_2FAUTH/public/index.php(51): Illuminate\\Foundation\\Http\\Kernel->handle()
#61 {main}
"}

Execution environment

Date: Tue, 19 Mar 2024 06:58:44 +0000
userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0
Version: 5.1.0
Environment: local
Install path: /
Debug: false
Cache driver: file
Log channel: daily
Log level: notice
DB driver: mysql
PHP version: 8.2.15
Operating system: Linux
interface: cgi-fcgi
Auth guard: web-guard
webauthn user verification: preferred
Trusted proxies: none
lastRadarScan: 2024-03-19 06:54:48

Containerization

Additional information

No response

Bubka commented 5 months ago

Hi, I made no change to the encryption feature from v5.0.4 to v5.1.0, this is really unexpected. Do you have a backup of your .env file to confirm the value of APP_KEY has not changed?

despokd commented 5 months ago

The App key is the same as before. I saved a backup of the key.

Thanks for quick reply!

If there is no solution for this, I can reimplement the codes (they're not so many).

Bubka commented 5 months ago

Are you confortable with source code editing? I would like you to test something.

What other information does this line provide?

despokd commented 5 months ago

No problem. Log is placed and returns:

[2024-03-18 15:30:48] local.ERROR: Decrypt failed: The MAC is invalid.  
[2024-03-18 15:30:48] local.ERROR: Decrypt failed: The MAC is invalid.  
[2024-03-18 15:30:48] local.ERROR: Decrypt failed: The MAC is invalid.  
[2024-03-18 15:30:48] local.ERROR: Secret cannot be deciphered, OTP generation aborted  
[2024-03-18 15:30:48] local.ERROR:  {"userId":1,"exception":"[object] (App\\Exceptions\\UndecipherableException(code: 0):  at /home/PATH_TO_2FAUTH/app/Models/TwoFAccount.php:363)
[stacktrace]
#0 /home/PATH_TO_2FAUTH/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php(23): App\\Models\\TwoFAccount->getOTP()
...
Bubka commented 5 months ago

Ok thx.

How is set your Show password setting? After a click/tap? Constantly? If Constantly, please switch to After a click/tap, I wan't to know if all the records are broken are just one of them.

FYI: The url to the settings page is /settings/options

despokd commented 5 months ago

I can't access /settings/options because of the error, but /admin/users/ with another user works. I am not sure which option is Show password, but here are the preferences of the user:

showOtpAsDot: true
revealDottedOTP: true
closeOtpOnCopy: false
copyOtpOnDisplay: false
clearSearchOnCopy: false
useBasicQrcodeReader: true
displayMode: list
showAccountsIcons: true
kickUserAfter: 15
activeGroup: 0
rememberActiveGroup: true
viewDefaultGroupOnCopy: false
defaultGroup: 0
defaultCaptureMode: advancedForm
useDirectCapture: false
useWebauthnOnly: false
getOfficialIcons: true
theme: light
formatPassword: true
formatPasswordBy: 0.5
lang: de
getOtpOnRequest: false

I also added the Variables section to the issue description, as I seen them.

despokd commented 5 months ago

I looked up the label and Show password stands for otp_generation at /resources/lang/en/settings.php#L135 . Which I set to 'otp_generation_on_request' => 'After a click/tap', if I remember correctly.

despokd commented 5 months ago

I looked up the label and Show password stands for otp_generation at /resources/lang/en/settings.php#L135 . Which I set to 'otp_generation_on_request' => 'After a click/tap', if I remember correctly.

Ignore that I found the getOtpOnRequest: false at the bottom and "getOtpOnRequest": false, at the database table for users.

I set it to true and I can now access the dashboard. It contains the OTP entries and warns with "not readable":

image

Bubka commented 5 months ago

ok, so all records are locked😞

Do you have a backup of the whole .env file made before the update? If so try to restore it please.

despokd commented 5 months ago

Not a current backup. There are some changes to SMTP and Database vars. I compared it with the current file and nothing changed except the above.

Bubka commented 5 months ago

What kind of change for the db? location? Type?

despokd commented 5 months ago

Type: SQLite to MySQL. SQLite was never used. This change was part of the setup and before the update.

Bubka commented 5 months ago

Can you check the encoding please. Does it change between the 2 files?

despokd commented 5 months ago

I do not have the old .env as a file backup. I compared env.example with .env, because the file was not modified since install. Both return with file -bi .env: text/plain; charset=us-ascii

Bubka commented 5 months ago

I'm running out of options... The last reason I think about is a cached key.

Previous versions of 2FAuth provided a .env.example file to start from. This APP_KEY was preset with SomeRandomStringOf32CharsExactly, so if the instance has been running before the APP_KEY has been changed, maybe the preset value has been cached and used all that time while you had changed APP_KEY after the first run.

Try it, we'll know: set your APP_KEY to SomeRandomStringOf32CharsExactly. Does it fix the issue?

despokd commented 5 months ago

I set APP_KEY=SomeRandomStringOf32CharsExactly and cleared config, cache and view with artisan. Nothing changed. I looked up my .env.example and it contains no key: APP_KEY=, which breaks the app.

I recreate my 2 OTPs now. Thanks for your help anyway :)

Bubka commented 5 months ago

Ok. Don't know if you had a dump of your DB. If not, you should have (at least) one so you can restore/rollback if something goes wrong.