2FAuth
2FAuth copied to clipboard
gauth qr code can't be imported
Version
4.2.4
Details & Steps to reproduce
1st way: open google authenticator, export all entries --> scan the qr code with 2fauth (import). error message: invalid or not readable data by google authenticator (translated from german) 2nd way: upload the screenshot from google authenticator -> same error message
Expectation
google authenticator entities are imported
Error & Logs
[2023-11-22 19:01:13] local.ERROR: Protobuf failed to get OTP parameters from provided migration URI
[2023-11-22 19:01:13] local.ERROR: Error occurred during parsing: Unexpected wire type.
[2023-11-22 19:01:13] local.ERROR: Google Authenticator {"userId":1,"exception":"[object] (App\\Exceptions\\InvalidMigrationDataException(code: 0): Google Authenticator at /srv/app/Services/Migrators/GoogleAuthMigrator.php:37)
[stacktrace]
#0 /srv/app/Services/TwoFAccountService.php(59): App\\Services\\Migrators\\GoogleAuthMigrator->migrate()
#1 /srv/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(353): App\\Services\\TwoFAccountService->migrate()
#2 /srv/app/Api/v1/Controllers/TwoFAccountController.php(134): Illuminate\\Support\\Facades\\Facade::__callStatic()
#3 /srv/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\\Api\\v1\\Controllers\\TwoFAccountController->migrate()
#4 /srv/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\\Routing\\Controller->callAction()
#5 /srv/vendor/laravel/framework/src/Illuminate/Routing/Route.php(260): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#6 /srv/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\\Routing\\Route->runController()
#7 /srv/vendor/laravel/framework/src/Illuminate/Routing/Router.php(799): Illuminate\\Routing\\Route->run()
#8 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#9 /srv/app/Http/Middleware/LogUserLastSeen.php(34): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#10 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\LogUserLastSeen->handle()
#11 /srv/app/Http/Middleware/KickOutInactiveUser.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#12 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\KickOutInactiveUser->handle()
#13 /srv/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#14 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#15 /srv/app/Http/Middleware/SetLanguage.php(68): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#16 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\SetLanguage->handle()
#17 /srv/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#18 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#19 /srv/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(159): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#20 /srv/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(135): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest()
#21 /srv/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(87): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequestUsingNamedLimiter()
#22 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle()
#23 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#24 /srv/vendor/laravel/framework/src/Illuminate/Routing/Router.php(800): Illuminate\\Pipeline\\Pipeline->then()
#25 /srv/vendor/laravel/framework/src/Illuminate/Routing/Router.php(777): Illuminate\\Routing\\Router->runRouteWithinStack()
#26 /srv/vendor/laravel/framework/src/Illuminate/Routing/Router.php(741): Illuminate\\Routing\\Router->runRoute()
#27 /srv/vendor/laravel/framework/src/Illuminate/Routing/Router.php(730): Illuminate\\Routing\\Router->dispatchToRoute()
#28 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\\Routing\\Router->dispatch()
#29 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#30 /srv/app/Http/Middleware/ForceJsonResponse.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#31 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\ForceJsonResponse->handle()
#32 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#33 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#34 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#35 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#36 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#37 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#38 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#39 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#40 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(89): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#41 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#42 /srv/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(62): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#43 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle()
#44 /srv/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#45 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#46 /srv/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#47 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then()
#48 /srv/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#49 /srv/public/index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle()
#50 {main}
"}
Execution environment
AUTH_PROXY_HEADER_FOR_EMAIL=null REDIS_PORT=6379 LOG_LEVEL=notice DB_CONNECTION=sqlite APP_DEBUG=false MAIL_USERNAME=null WEBAUTHN_NAME=2FAuth HOSTNAME=314d82d55162 [email protected] APP_URL=http://localhost IS_DEMO_APP=false MIX_ENV=local SHLVL=1 PUSHER_APP_ID= HOME=/ PUSHER_APP_SECRET= BROADCAST_DRIVER=log COMMIT=c765bfd MAIL_FROM_NAME=2FAuth DB_DATABASE=/srv/database/database.sqlite APP_NAME=2FAuth MAIL_DRIVER=SMTP WEBAUTHN_ID=null WEBAUTHN_ICON=null SESSION_DRIVER=file WEBAUTHN_USER_VERIFICATION=preferred TRUSTED_PROXIES=null LOG_CHANNEL=daily [email protected] VERSION=latest CREATED=2023-11-21T12:53:11Z CACHE_DRIVER=file LOGIN_THROTTLE=5 QUEUE_DRIVER=sync TERM=xterm MAIL_ENCRYPTION=null PUSHER_APP_KEY= PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [email protected] PUSHER_APP_CLUSTER=mt1 MAIL_PASSWORD=null MAIL_HOST=10.a.b.c THROTTLE_API=60 AUTHENTICATION_GUARD=web-guard SESSION_LIFETIME=120 REDIS_PASSWORD=null PROXY_LOGOUT_URL=null MAIL_PORT=2525 MIX_PUSHER_APP_KEY= APP_ENV=local APP_KEY=SomeRandomStringOf32CharsExactly REDIS_HOST=127.0.0.1 MIX_PUSHER_APP_CLUSTER= PWD=/srv AUTH_PROXY_HEADER_FOR_USER=null
Containerization
- [X] Docker
Additional information
No response
the qr-code contains: otpauth-migration://offline?data=Ck123456zy5Glu123456JlNsYW123456VkNDKT123456ZWdyb2123456NzhAZ2123456Y29tGg123456ayABKA123456[430charremoved]ChSjccaijm%2FJ6gqvp4%2FOSkHu5vKAXhIIbGlua2VkSW4gASgBMAIQARgBIAAo5J6%2Bqfr%2F%2F%2F%2F%2FAQ%3D%3D
I just tested with GAuth 4.0.2 on iOS, no issue. What OS & GAuth version are you using?
Android 13 (MIUI 14.0.8), Authenticator 6.0
Same error here, saying "not a valid QR code".
Android 10, Honor 8x, Google authenticator version 6.0
The QR Code contains: otpauth-migration::offline?data=...
Addition: I see this error in the running docker conatiner error output:
[error] 41#41: *27 FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 67108872 bytes) in /srv/vendor/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php on line 85" while reading response header from upstream, client: 172.17.0.1, server: 2fauth, request: "POST /api/v1/qrcode/decode HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost:8081", referrer: "http://localhost:8081/account/import"
The image has a size of 376 KB.
The image was then cropped to only contain the QR code, is of the type jpg and has a size of 146 kB.
Error: "POST /api/v1/qrcode/decode HTTP/1.1" 400 44 "http://localhost:8081/account/import" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
Thank you.
Regards Joachim
In addition to my report above:
I was able to sucessfully decode the Goggle Autheticator export QRCode screenshot using the khanamiryan/php-qrcode-detector-decoder library with this code:
$qrcode = new QrReader(__DIR__.'/Screenshot_20231124_084225_65.jpg');
$hints = [
'TRY_HARDER' => true,
'NR_ALLOW_SKIP_ROWS' => 0
];
$qrcode->decode($hints);
$text = $qrcode->text($hints);
Maybe the $hints array should be added to the method app/Services/QrCodeService::decode() method() ?
@juppwerner Thx for the hint. I will make some tests with these arguments, but before that I need to reproduce the issue and check exactly what is failing. The OP issue seems to be an error at data parsing while you seems to have an issue at QR decoding.
To you both:
How many accounts were exported from Authenticator?
With Dev Tools opened in your browser, what is the result of the POST
request to .../api/v1/qrcode/decode
right after you upload a (rejected) QR code image from the Import page?
i have 7 accounts in there. when just import 1 it is working. will now try to find the bad one.
yes, the amount of exports seem to be the root cause. with 4 accounts it works, starting with 5 it doesn't recognize a live scan and an uploaded qr code will fail as well.
I have 9 accounts in my export QrCode. Just to clarify, I was not able to parse my qr code image to text without using the hints array.
@juppwerner
Error Allowed memory size of 134217728 bytes exhausted (tried to allocate 67108872 bytes) in /srv/vendor/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php on line 85
means the memory_limit
set in php.ini has been reached by the script. So trying to decode an hi-res image may be the reason why you faced it.
How did you tried the following? Using a local dev env?
I was able to sucessfully decode the Goggle Autheticator export QRCode screenshot using the khanamiryan/php-qrcode-detector-decoder library with this code:
$qrcode = new QrReader(__DIR__.'/Screenshot_20231124_084225_65.jpg'); $hints = [ 'TRY_HARDER' => true, 'NR_ALLOW_SKIP_ROWS' => 0 ];
If so, the php config of your dev env may have a different memory_limit
than the one in the docker container, making this test not really reliable. Correct me if I'm wrong, this is just a guess.
Furthermore, I don't understand which "version" of the qrcode you was able to decode with the $hints
option: the original one or the cropped one?
@astrakid
yes, the amount of exports seem to be the root cause. with 4 accounts it works, starting with 5 it doesn't recognize a live scan and an uploaded qr code will fail as well.
The live scan decoding is not done by the same part of 2FAuth as the decoding of the uploaded qrcodes. In the first case it is a local js qr reader, otherwise it is a php qr reader. This is why you received the error regardless of the method. So the pb comes from the part after the =
sign of the otpauth migration uri which is encoded with protobuf.
i have 7 accounts in there. when just import 1 it is working. will now try to find the bad one.
Any news on that?
is it possible to increase the php memory limit in docker container?
i have 7 accounts in there. when just import 1 it is working. will now try to find the bad one.
at least it was only the amount of imported codes causing the issue, so all codes worked at all. but not all 7 at once.
I too am unable to import all google account,
When exporting them, it provides 3 QR codes to scan for import, I cannt add these to 2fauthy as it doesnt like them and produces a error "Server Error"
Leaving this here for anyone who is also struggling with this issue. I had to use an app like QtQr to get the text from the QR code, then use this tool to convert the Google-specific transfer links to plain otpauth links that work on most authenticators. Supposedly the Aegis authenticator can understand the Google links natively, but I haven't confirmed.
Thx for the head up and the workaround @ericsubach, I totally forgot this issue 🫤 Will work on it asap.
Same issue here.
So, I was able to reproduce the not a valid qr code error
. This occurs when the uploaded image contains a qrcode which is too small or too blurry. I have changed the message in the error notification to be more relevant and to suggest how to fix the issue (cropping the image, submitting a sharper image).
I've also changed the way images with qr code are analyzed. Now, if no readable QR code is found in the image, the image is scanned again but with a more aggressive (but more expensive for the server) method. In some situations this should prevent the qrcode reading to fail.
Finally, for those who want to increase the memory limit no matter what, here is how to do so using docker-compose:
-
Create a
2fauth.ini
file in a local directory, i.e/docker-php-conf.d
-
Edit the file and add the directive you need. For example, to increase memory limit, add
memory_limit=256M
-
In your
docker-compose.yml
file, add a new volume:volumes: - /docker-php-conf.d/php-2fauth.ini:/etc/php81/conf.d/2fauth.ini
-
Start your container
same issue as OP
Ver 5.1.1 (Deployed on Ubuntu via Docker Compose. ) Authenticator 6.0
5 Google accounts, successfully exported 2. However, for the remaining accounts, whether exporting individually or in bulk, it consistently prompts "Invalid or unreadable Google Authenticator data".
Here's my workaround:
After exporting the Google QR code, I scanned it using the Edge browser on my phone to obtain the text (otpauth-migration://offline?data=xxxx), saved it as a text file, and successfully imported it.