diff --git a/app/Api/v1/Controllers/TwoFAccountController.php b/app/Api/v1/Controllers/TwoFAccountController.php index f565036c..7e06a9eb 100644 --- a/app/Api/v1/Controllers/TwoFAccountController.php +++ b/app/Api/v1/Controllers/TwoFAccountController.php @@ -7,6 +7,7 @@ use App\Api\v1\Requests\TwoFAccountReorderRequest; use App\Api\v1\Requests\TwoFAccountStoreRequest; use App\Api\v1\Requests\TwoFAccountUpdateRequest; +use App\Api\v1\Requests\TwoFAccountImportRequest; use App\Api\v1\Requests\TwoFAccountBatchRequest; use App\Api\v1\Requests\TwoFAccountUriRequest; use App\Api\v1\Requests\TwoFAccountDynamicRequest; @@ -16,6 +17,7 @@ use App\Services\GroupService; use App\Services\TwoFAccountService; use Illuminate\Support\Arr; +use Illuminate\Support\Str; use Illuminate\Http\Request; use App\Http\Controllers\Controller; @@ -120,6 +122,60 @@ public function update(TwoFAccountUpdateRequest $request, TwoFAccount $twofaccou } + /** + * Dry-import Google authenticator data + * + * @param \App\Api\v1\Requests\TwoFAccountImportRequest $request + * @return \App\Api\v1\Resources\TwoFAccountCollection + */ + public function import(TwoFAccountImportRequest $request) + { + $ALGORITHM = [ + '', + 'sha1', + 'sha256', + 'sha512', + 'md5' + ]; + + $DIGIT_COUNT = [ + '', + 6, + 8 + ]; + + $OTP_TYPE = [ + '', + 'hotp', + 'totp' + ]; + + // require_once base_path('protobuf/SearchRequest.php'); + // $uri = 'otpauth-migration://offline?data=CjUKCi8gSXtDdoRpZEkSEWVkb3VhcmRAZ2FuZWF1Lm1lGg5iYW5rLmdhbmVhdS5tZSABKAEwAhABGAEgAA=='; + // $uri = base64_decode(urldecode('CjUKCi8gSXtDdoRpZEkSEWVkb3VhcmRAZ2FuZWF1Lm1lGg5iYW5rLmdhbmVhdS5tZSABKAEwAhABGAEgAA==')); + // $uri = 'otpauth-migration://offline?data=CiQKCj1PS8k1EUgVI0ESB0BidWJrYV8aB1R3aXR0ZXIgASgBMAIKIQoK6/l62ezmsWvMNRIFQnVia2EaBkdpdEh1YiABKAEwAhABGAEgAA=='; + // $uri = base64_decode(urldecode('CiQKCj1PS8k1EUgVI0ESB0BidWJrYV8aB1R3aXR0ZXIgASgBMAIKIQoK6/l62ezmsWvMNRIFQnVia2EaBkdpdEh1YiABKAEwAhABGAEgAA==')); + + $data = base64_decode(urldecode(Str::replace('otpauth-migration://offline?data=', '', $request->uri))); + + $proto = new \App\Protobuf\GoogleAuth\Payload(); + $proto->mergeFromString($data); + $otpParameters = $proto->getOtpParameters(); + + foreach ($otpParameters->getIterator() as $key => $otp_parameters) { + $out[$key]['secret'] = \ParagonIE\ConstantTime\Base32::encodeUpper($otp_parameters->getSecret()); + $out[$key]['account'] = $otp_parameters->getName(); + $out[$key]['service'] = $otp_parameters->getIssuer(); + $out[$key]['algorithm'] = $ALGORITHM[$otp_parameters->getalgorithm()]; + $out[$key]['digits'] = $DIGIT_COUNT[$otp_parameters->getDigits()]; + $out[$key]['otp_type'] = $OTP_TYPE[$otp_parameters->getType()]; + $out[$key]['counter'] = $otp_parameters->getCounter(); + } + + return response()->json($out, 200); + } + + /** * Save 2FA accounts order * diff --git a/app/Api/v1/Requests/TwoFAccountImportRequest.php b/app/Api/v1/Requests/TwoFAccountImportRequest.php new file mode 100644 index 00000000..a1fe1afc --- /dev/null +++ b/app/Api/v1/Requests/TwoFAccountImportRequest.php @@ -0,0 +1,31 @@ + 'required|string|regex:/^otpauth-migration:\/\/offline\?data=/i', + ]; + } +} \ No newline at end of file diff --git a/routes/api/v1.php b/routes/api/v1.php index 714e6f18..cee009e8 100644 --- a/routes/api/v1.php +++ b/routes/api/v1.php @@ -27,6 +27,7 @@ Route::delete('settings/{settingName}', 'SettingController@destroy')->name('settings.destroy'); Route::delete('twofaccounts', 'TwoFAccountController@batchDestroy')->name('twofaccounts.batchDestroy'); + Route::post('twofaccounts/import', 'TwoFAccountController@import')->name('twofaccounts.import'); Route::patch('twofaccounts/withdraw', 'TwoFAccountController@withdraw')->name('twofaccounts.withdraw'); Route::post('twofaccounts/reorder', 'TwoFAccountController@reorder')->name('twofaccounts.reorder'); Route::post('twofaccounts/preview', 'TwoFAccountController@preview')->name('twofaccounts.preview');