From 700f4e0a382d7d72b17bbe1aa9f3e8c91481961b Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Thu, 21 May 2026 09:19:48 +0530 Subject: [PATCH 1/4] Fix local upload from browser --- ui/public/locales/en.json | 5 + ui/src/views/image/RegisterOrUploadIso.vue | 57 ++++++-- .../views/image/RegisterOrUploadTemplate.vue | 52 ++++++- ui/src/views/storage/UploadLocalVolume.vue | 135 ++++++++++++------ 4 files changed, 195 insertions(+), 54 deletions(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 673f6da0ad11..6adf1942e799 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1617,6 +1617,8 @@ "label.offeringid": "Offering ID", "label.offeringtype": "Compute Offering type", "label.ok": "OK", +"label.ssvm.open.cert.page": "Open Certificate Page", +"label.retry.upload": "Retry Upload", "label.only.end.date.and.time": "Only end date and time", "label.only.start.date.and.time": "Only start date and time", "label.open.documentation": "Open documentation", @@ -3667,6 +3669,9 @@ "message.upload.iso.failed.description": "Failed to upload ISO.", "message.upload.template.failed.description": "Failed to upload Template", "message.upload.volume.failed": "Volume upload failed", +"message.ssvm.cert.untrusted": "The upload server certificate is not trusted by your browser.", +"message.ssvm.cert.trust.instructions": "Click 'Open Certificate Page' to open the upload server in a new browser tab. Accept the certificate warning shown by your browser, then come back here and click 'Retry Upload'.", +"message.ssvm.cert.still.untrusted": "The certificate still appears untrusted. Please accept it in the opened tab and try again.", "message.user.not.permitted.api": "User is not permitted to use the API", "message.validate.equalto": "Please enter the same value again.", "message.validate.max": "Please enter a value less than or equal to {0}.", diff --git a/ui/src/views/image/RegisterOrUploadIso.vue b/ui/src/views/image/RegisterOrUploadIso.vue index 37ae369727fe..0b430cd49610 100644 --- a/ui/src/views/image/RegisterOrUploadIso.vue +++ b/ui/src/views/image/RegisterOrUploadIso.vue @@ -19,11 +19,27 @@
- + {{ $t('message.upload.file.processing') }} +
+ +
+ {{ $t('label.cancel') }} + + {{ $t('label.ssvm.open.cert.page') }} + + + {{ $t('label.retry.upload') }} + +
+
1) { @@ -502,6 +540,7 @@ export default { fileList.forEach(file => { formData.append('files[]', file) }) + this.uploading = true this.uploadPercentage = 0 axios.post(this.uploadParams.postURL, formData, @@ -529,6 +568,8 @@ export default { description: `${this.$t('message.upload.iso.failed.description')} - ${e}`, duration: 0 }) + }).finally(() => { + this.uploading = false }) }, handleSubmit (e) { @@ -583,18 +624,18 @@ export default { } params.format = 'ISO' this.loading = true - api('getUploadParamsForIso', params).then(json => { + api('getUploadParamsForIso', params).then(async json => { this.uploadParams = (json.postuploadisoresponse && json.postuploadisoresponse.getuploadparams) ? json.postuploadisoresponse.getuploadparams : '' - const response = this.handleUpload() if (this.userdataid !== null) { this.linkUserdataToTemplate(this.userdataid, json.postuploadisoresponse.iso[0].id) } - if (response === 'upload successful') { - this.$notification.success({ - message: this.$t('message.success.upload'), - description: this.$t('message.success.upload.iso.description') - }) + this.ssvmOrigin = new URL(this.uploadParams.postURL).origin + const trusted = await this.probeSsvmCert(this.ssvmOrigin) + if (!trusted) { + this.ssvmCertUntrusted = true + return } + this.handleUpload() }).catch(error => { this.$notifyError(error) }).finally(() => { diff --git a/ui/src/views/image/RegisterOrUploadTemplate.vue b/ui/src/views/image/RegisterOrUploadTemplate.vue index 3ada9f6fd531..d79def815f51 100644 --- a/ui/src/views/image/RegisterOrUploadTemplate.vue +++ b/ui/src/views/image/RegisterOrUploadTemplate.vue @@ -19,11 +19,27 @@
- + {{ $t('message.upload.file.processing') }} +
+ +
+ {{ $t('label.cancel') }} + + {{ $t('label.ssvm.open.cert.page') }} + + + {{ $t('label.retry.upload') }} + +
+
{ formData.append('files[]', file) }) + this.uploading = true this.uploadPercentage = 0 axios.post(this.uploadParams.postURL, formData, @@ -639,6 +677,8 @@ export default { this.closeAction() }).catch(e => { this.$notifyError(e) + }).finally(() => { + this.uploading = false }) }, fetchCustomHypervisorName () { @@ -1124,12 +1164,18 @@ export default { duration: 0 }) } - api('getUploadParamsForTemplate', params).then(json => { + api('getUploadParamsForTemplate', params).then(async json => { this.uploadParams = (json.postuploadtemplateresponse && json.postuploadtemplateresponse.getuploadparams) ? json.postuploadtemplateresponse.getuploadparams : '' - this.handleUpload() if (this.userdataid !== null) { this.linkUserdataToTemplate(this.userdataid, json.postuploadtemplateresponse.template[0].id) } + this.ssvmOrigin = new URL(this.uploadParams.postURL).origin + const trusted = await this.probeSsvmCert(this.ssvmOrigin) + if (!trusted) { + this.ssvmCertUntrusted = true + return + } + this.handleUpload() }).catch(error => { this.$notifyError(error) }).finally(() => { diff --git a/ui/src/views/storage/UploadLocalVolume.vue b/ui/src/views/storage/UploadLocalVolume.vue index 3a0bf4e129fe..d598db2cbf74 100644 --- a/ui/src/views/storage/UploadLocalVolume.vue +++ b/ui/src/views/storage/UploadLocalVolume.vue @@ -17,11 +17,27 @@