Handle icon & qrcode upload failure gracefully

This commit is contained in:
Bubka 2022-09-02 14:28:57 +02:00
parent fa8bd1def0
commit 61d177aecd
7 changed files with 55 additions and 36 deletions

View File

@ -22,11 +22,13 @@ class IconController extends Controller
$this->validate($request, [
'icon' => 'required|image',
]);
$path = $request->file('icon')->store('', 'icons');
$response = array( "filename" => pathinfo($path)['basename']);
return response()->json($response, 201);
$icon = $request->file('icon');
$path = $icon instanceof \Illuminate\Http\UploadedFile ? $icon->store('', 'icons') : false;
return $path
? response()->json(['filename' => pathinfo($path)['basename']], 201)
: response()->json(['message' => __('errors.file_upload_failed')], 500);
}

View File

@ -35,7 +35,9 @@ class QrCodeController extends Controller
{
$file = $request->file('qrcode');
return response()->json(['data' => QrCode::decode($file)], 200);
return $file instanceof \Illuminate\Http\UploadedFile
? response()->json(['data' => QrCode::decode($file)], 200)
: response()->json(['message' => __('errors.file_upload_failed')], 500);
}
}

View File

@ -213,7 +213,7 @@ class Form {
return new Promise((resolve, reject) => {
// (Form.axios || axios).request({ url: this.route(url), method, data, ...config })
Vue.axios.request({ url: this.route(url), method: 'post', data: formData, header: {'Content-Type' : 'multipart/form-data'} })
Vue.axios.request({ url: this.route(url), method: 'post', data: formData, header: {'Content-Type' : 'multipart/form-data'}, ...config })
.then(response => {
this.finishProcessing()

View File

@ -110,18 +110,21 @@
* Upload the submitted QR code file to the backend for decoding, then route the user
* to the Create or Import form with decoded URI to prefill the form
*/
async submitQrCode() {
submitQrCode() {
let imgdata = new FormData();
imgdata.append('qrcode', this.$refs.qrcodeInput.files[0]);
imgdata.append('inputFormat', 'fileUpload');
const { data } = await this.form.upload('/api/v1/qrcode/decode', imgdata)
if( data.data.slice(0, 33).toLowerCase() === "otpauth-migration://offline?data=" ) {
this.$router.push({ name: 'importAccounts', params: { migrationUri: data.data } });
}
else this.$router.push({ name: 'createAccount', params: { decodedUri: data.data } });
this.form.upload('/api/v1/qrcode/decode', imgdata, {returnError: true}).then(response => {
if( response.data.data.slice(0, 33).toLowerCase() === "otpauth-migration://offline?data=" ) {
this.$router.push({ name: 'importAccounts', params: { migrationUri: response.data.data } });
}
else this.$router.push({ name: 'createAccount', params: { decodedUri: response.data.data } });
})
.catch(error => {
this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
});
},
/**

View File

@ -340,32 +340,38 @@
this.$router.push({name: 'accounts'});
},
async uploadQrcode(event) {
uploadQrcode(event) {
let imgdata = new FormData();
imgdata.append('qrcode', this.$refs.qrcodeInput.files[0]);
imgdata.append('inputFormat', 'fileUpload');
// First we get the uri encoded in the qrcode
const { data } = await this.form.upload('/api/v1/qrcode/decode', imgdata)
this.uri = data.data
// Then the otp described by the uri
this.axios.post('/api/v1/twofaccounts/preview', { uri: data.data }).then(response => {
this.form.fill(response.data)
this.secretIsBase32Encoded = 1
this.tempIcon = response.data.icon ? response.data.icon : null
this.form.upload('/api/v1/qrcode/decode', imgdata, {returnError: true}).then(response => {
this.uri = response.data.data
// Then the otp described by the uri
this.axios.post('/api/v1/twofaccounts/preview', { uri: this.uri }).then(response => {
this.form.fill(response.data)
this.secretIsBase32Encoded = 1
this.tempIcon = response.data.icon ? response.data.icon : null
})
.catch(error => {
if( error.response.status === 422 ) {
if( error.response.data.errors.uri ) {
this.showAlternatives = true
}
}
});
})
.catch(error => {
if( error.response.status === 422 ) {
if( error.response.data.errors.uri ) {
this.showAlternatives = true
}
}
this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
return false
});
},
async uploadIcon(event) {
uploadIcon(event) {
// clean possible already uploaded temp icon
this.deleteIcon()
@ -373,9 +379,12 @@
let imgdata = new FormData();
imgdata.append('icon', this.$refs.iconInput.files[0]);
const { data } = await this.form.upload('/api/v1/icons', imgdata)
this.tempIcon = data.filename;
this.form.upload('/api/v1/icons', imgdata, {returnError: true}).then(response => {
this.tempIcon = response.data.filename;
})
.catch(error => {
this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
});
},
fetchLogo() {

View File

@ -265,10 +265,12 @@
let imgdata = new FormData();
imgdata.append('icon', this.$refs.iconInput.files[0]);
const { data } = await this.form.upload('/api/v1/icons', imgdata)
this.tempIcon = data.filename;
this.form.upload('/api/v1/icons', imgdata, {returnError: true}).then(response => {
this.tempIcon = response.data.filename;
})
.catch(error => {
this.$notify({type: 'is-danger', text: this.$t(error.response.data.message) })
});
},
fetchLogo() {

View File

@ -41,5 +41,6 @@ return [
'auth_proxy_failed_legend' => '2Fauth is configured to run behind an authentication proxy but your proxy does not return the expected header. Check your configuration and try again.',
'invalid_google_auth_migration' => 'Invalid or unreadable Google Authenticator data',
'unsupported_otp_type' => 'Unsupported OTP type',
'no_logo_found_for_x' => 'No logo available for {service}'
'no_logo_found_for_x' => 'No logo available for {service}',
'file_upload_failed' => 'File upload failed'
];