Browse Source

Merge branch 'update-checksum-20220205' of tmp/arozos into master

Checked, seems no problem, merge and re-test
TC 3 years ago
parent
commit
e827bd94d6
5 changed files with 155 additions and 65 deletions
  1. 1 0
      .gitignore
  2. 10 4
      mod/updates/handler.go
  3. 28 0
      mod/updates/internal.go
  4. 42 2
      mod/updates/updates.go
  5. 74 59
      web/SystemAO/updates/index.html

+ 1 - 0
.gitignore

@@ -63,3 +63,4 @@ upx.exe
 start.sh.backup
 start.sh.backup
 *.backup
 *.backup
 system/bridge.json
 system/bridge.json
+launcher.exe

+ 10 - 4
mod/updates/handler.go

@@ -40,7 +40,8 @@ type UpdateConfig struct {
 			I386  string `json:"i386"`
 			I386  string `json:"i386"`
 		} `json:"freebsd"`
 		} `json:"freebsd"`
 	} `json:"binary"`
 	} `json:"binary"`
-	Webpack string `json:"webpack"`
+	Webpack  string `json:"webpack"`
+	Checksum string `json:"checksum"`
 }
 }
 
 
 func HandleUpdateCheckSize(w http.ResponseWriter, r *http.Request) {
 func HandleUpdateCheckSize(w http.ResponseWriter, r *http.Request) {
@@ -79,6 +80,11 @@ func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
+	checksum, err := common.Mv(r, "checksum", true)
+	if err != nil {
+		checksum = ""
+	}
+
 	//Update the connection to websocket
 	//Update the connection to websocket
 	requireWebsocket, _ := common.Mv(r, "ws", false)
 	requireWebsocket, _ := common.Mv(r, "ws", false)
 	if requireWebsocket == "true" {
 	if requireWebsocket == "true" {
@@ -96,7 +102,7 @@ func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
 			Progress   float64
 			Progress   float64
 			StatusText string
 			StatusText string
 		}
 		}
-		err = DownloadUpdatesFromURL(binary, webpack, func(stage int, progress float64, statusText string) {
+		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
 			thisProgress := Progress{
 			thisProgress := Progress{
 				Stage:      stage,
 				Stage:      stage,
 				Progress:   progress,
 				Progress:   progress,
@@ -107,7 +113,7 @@ func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
 		})
 		})
 		if err != nil {
 		if err != nil {
 			//Finish with error
 			//Finish with error
-			c.WriteMessage(1, []byte("{\"error\":\""+err.Error()+"\""))
+			c.WriteMessage(1, []byte("{\"error\":\""+err.Error()+"\"}"))
 		} else {
 		} else {
 			//Done without error
 			//Done without error
 			c.WriteMessage(1, []byte("OK"))
 			c.WriteMessage(1, []byte("OK"))
@@ -119,7 +125,7 @@ func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
 
 
 	} else {
 	} else {
 		//Just download and return ok after finish
 		//Just download and return ok after finish
-		err = DownloadUpdatesFromURL(binary, webpack, func(stage int, progress float64, statusText string) {
+		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
 			fmt.Println("Downloading Update, Stage: ", stage, " Progress: ", progress, " Status: ", statusText)
 			fmt.Println("Downloading Update, Stage: ", stage, " Progress: ", progress, " Status: ", statusText)
 		})
 		})
 		if err != nil {
 		if err != nil {

+ 28 - 0
mod/updates/internal.go

@@ -3,12 +3,15 @@ package updates
 import (
 import (
 	"archive/tar"
 	"archive/tar"
 	"compress/gzip"
 	"compress/gzip"
+	"crypto/sha1"
+	"encoding/hex"
 	"errors"
 	"errors"
 	"io"
 	"io"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strconv"
 	"strconv"
+	"strings"
 )
 )
 
 
 func getFileSize(filename string) int64 {
 func getFileSize(filename string) int64 {
@@ -101,3 +104,28 @@ func extractTarGz(gzipStream io.Reader, unzipPath string, progressUpdateFunction
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+func getSHA1Hash(filename string) (string, error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	h := sha1.New()
+	if _, err := io.Copy(h, f); err != nil {
+		return "", err
+	}
+	return hex.EncodeToString(h.Sum(nil)), nil
+}
+
+func readCheckSumFile(fileContent string, filename string, checksum string) bool {
+	checkSumFromFile := strings.Split(fileContent, "\r\n")
+	for _, line := range checkSumFromFile {
+		checkSumLine := strings.Split(line, " *")
+		if checkSumLine[1] == filename {
+			return checkSumLine[0] == checksum
+		}
+	}
+	return false
+}

+ 42 - 2
mod/updates/updates.go

@@ -10,7 +10,7 @@ import (
 )
 )
 
 
 //Download updates from given URL, return real time progress of stage (int),  progress (int) and status text (string)
 //Download updates from given URL, return real time progress of stage (int),  progress (int) and status text (string)
-func DownloadUpdatesFromURL(binaryURL string, webpackURL string, progressUpdateFunction func(int, float64, string)) error {
+func DownloadUpdatesFromURL(binaryURL string, webpackURL string, checksumURL string, progressUpdateFunction func(int, float64, string)) error {
 	//Create the update download folder
 	//Create the update download folder
 	os.RemoveAll("./updates")
 	os.RemoveAll("./updates")
 	os.MkdirAll("./updates", 0755)
 	os.MkdirAll("./updates", 0755)
@@ -24,6 +24,7 @@ func DownloadUpdatesFromURL(binaryURL string, webpackURL string, progressUpdateF
 	//Generate the download position
 	//Generate the download position
 	binaryDownloadTarget := "./updates/" + filepath.Base(binaryURL)
 	binaryDownloadTarget := "./updates/" + filepath.Base(binaryURL)
 	webpackDownloadTarget := "./updates/" + filepath.Base(webpackURL)
 	webpackDownloadTarget := "./updates/" + filepath.Base(webpackURL)
+	checksumDownloadTarget := "./updates/" + filepath.Base(checksumURL)
 
 
 	//Check if the webpack is .tar.gz
 	//Check if the webpack is .tar.gz
 	if filepath.Ext(webpackDownloadTarget) != ".gz" {
 	if filepath.Ext(webpackDownloadTarget) != ".gz" {
@@ -86,7 +87,46 @@ func DownloadUpdatesFromURL(binaryURL string, webpackURL string, progressUpdateF
 	}
 	}
 	webpackDownloadComplete = 1
 	webpackDownloadComplete = 1
 
 
-	//Download completed. Try unzip webpack
+	//Download completed.
+	//check checksum if exists
+	//just a small file, dont need progress bar
+	if checksumURL != "" {
+		err = downloadFile(checksumURL, checksumDownloadTarget)
+		if err != nil {
+			errorMessage = err.Error()
+			return err
+		}
+		checksumFileContent, err := ioutil.ReadFile(checksumDownloadTarget)
+		if err != nil {
+			errorMessage = err.Error()
+			return err
+		}
+		binaryHash, err := getSHA1Hash(binaryDownloadTarget)
+		if err != nil {
+			errorMessage = err.Error()
+			return err
+		}
+		webpackHash, err := getSHA1Hash(webpackDownloadTarget)
+		if err != nil {
+			errorMessage = err.Error()
+			return err
+		}
+		binaryBool := readCheckSumFile(string(checksumFileContent), filepath.Base(binaryURL), binaryHash)
+		webPackBool := readCheckSumFile(string(checksumFileContent), filepath.Base(webpackURL), webpackHash)
+		os.Remove(checksumDownloadTarget)
+		if !binaryBool {
+			progressUpdateFunction(1, 100, "Binary checksum mismatch")
+			errorMessage = "Binary checksum mismatch"
+			return errors.New("Binary checksum mismatch")
+		}
+		if !webPackBool {
+			progressUpdateFunction(1, 100, "Web pack checksum mismatch")
+			errorMessage = "Web pack checksum mismatch"
+			return errors.New("Web pack checksum mismatch")
+		}
+	}
+
+	//Try unzip webpack
 	gzipstrean, err := os.Open(webpackDownloadTarget)
 	gzipstrean, err := os.Open(webpackDownloadTarget)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 74 - 59
web/SystemAO/updates/index.html

@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html ng-app="App">
 <html ng-app="App">
+
 <head>
 <head>
     <title>System Update</title>
     <title>System Update</title>
     <meta charset="UTF-8">
     <meta charset="UTF-8">
@@ -9,6 +10,7 @@
     <script type="text/javascript" src="../../script/semantic/semantic.min.js"></script>
     <script type="text/javascript" src="../../script/semantic/semantic.min.js"></script>
     <!-- <script type="text/javascript" src="../../script/ao_module.js"></script> -->
     <!-- <script type="text/javascript" src="../../script/ao_module.js"></script> -->
 </head>
 </head>
+
 <body>
 <body>
     <div class="ui container">
     <div class="ui container">
         <div class="ui basic segment">
         <div class="ui basic segment">
@@ -16,7 +18,7 @@
                 <i class="sync icon"></i>
                 <i class="sync icon"></i>
                 <div class="content">
                 <div class="content">
                     System Update
                     System Update
-                  <div class="sub header">Update the ArozOS System to the latest version</div>
+                    <div class="sub header">Update the ArozOS System to the latest version</div>
                 </div>
                 </div>
             </h3>
             </h3>
             <div class="ui divider"></div>
             <div class="ui divider"></div>
@@ -43,7 +45,7 @@
                 <i class="yellow exclamation icon"></i>
                 <i class="yellow exclamation icon"></i>
                 <div class="content">
                 <div class="content">
                     <div class="header">
                     <div class="header">
-                    Confirm Update?
+                        Confirm Update?
                     </div>
                     </div>
                     <p><span>This updates will take up </span><span id="spaceEst" style="font-weight: bold;"></span> <span>of space.</span></p>
                     <p><span>This updates will take up </span><span id="spaceEst" style="font-weight: bold;"></span> <span>of space.</span></p>
                     <p><b>Please make sure you have back up all important files and config files before you proceeds.</b></p>
                     <p><b>Please make sure you have back up all important files and config files before you proceeds.</b></p>
@@ -60,12 +62,14 @@
                         Starting Download Session
                         Starting Download Session
                     </div>
                     </div>
                     <br>
                     <br>
-                    <p id="fallbackmodeExp" style="display:none;">You are seeing this message is because the websocket connection to your host failed to establish. No worry, updates can still be done using AJAX fallback mode, just without the real time progress updates. <br>Please wait until the download complete before closing this page.</br></p>
+                    <p id="fallbackmodeExp" style="display:none;">You are seeing this message is because the websocket connection to your host failed to establish. No worry, updates can still be done using AJAX fallback mode, just without the real time progress updates. <br>Please wait until the
+                        download complete before closing this page.</br>
+                    </p>
                     <div class="ui blue active progress">
                     <div class="ui blue active progress">
                         <div id="downloadProgressBar" class="bar">
                         <div id="downloadProgressBar" class="bar">
                             <div class="progress">0.00%</div>
                             <div class="progress">0.00%</div>
                         </div>
                         </div>
-                      </div>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
             <div id="success" class="ui icon green message" style="display:none;">
             <div id="success" class="ui icon green message" style="display:none;">
@@ -96,7 +100,7 @@
                 </div>
                 </div>
             </div>
             </div>
             <div id="restartPanel" class="ui message" style="display:none;">
             <div id="restartPanel" class="ui message" style="display:none;">
-                <div class="header" >
+                <div class="header">
                     Launcher Detected: <span id="launcherName">N/A</span>
                     Launcher Detected: <span id="launcherName">N/A</span>
                 </div>
                 </div>
                 <p>You will need to restart ArozOS in order to apply the updates.</p>
                 <p>You will need to restart ArozOS in order to apply the updates.</p>
@@ -125,19 +129,18 @@
             <small>Usually with named as: webpack.tar.gz</small>
             <small>Usually with named as: webpack.tar.gz</small>
             <br><br>
             <br><br>
             <button class="ui red button updateBtn" onclick="updateViaURL();"><i class="cloud upload icon"></i> Execute Update</button>
             <button class="ui red button updateBtn" onclick="updateViaURL();"><i class="cloud upload icon"></i> Execute Update</button>
-            
+
             <div class="ui divider"></div>
             <div class="ui divider"></div>
 
 
 
 
             <div class="ui message">
             <div class="ui message">
                 <h4><i class="info circle icon"></i>Update Instruction</h4>
                 <h4><i class="info circle icon"></i>Update Instruction</h4>
-                <p>To update your ArozOS system, you will need two files: A compiled binary of the newer version of ArozOS and the webpack compress file in .tar.gz format.
-                You can get the two files on Github, private distribution servers or from cluster nodes. Please choose one of the update method below and press "Update" to start the update process.</p>
+                <p>To update your ArozOS system, you will need two files: A compiled binary of the newer version of ArozOS and the webpack compress file in .tar.gz format. You can get the two files on Github, private distribution servers or from cluster
+                    nodes. Please choose one of the update method below and press "Update" to start the update process.</p>
                 <p>Notes that updates only work if ArozOS is started by the launcher. If not, you might need to manually update the system using system commands.</p>
                 <p>Notes that updates only work if ArozOS is started by the launcher. If not, you might need to manually update the system using system commands.</p>
                 <div class="ui accordion">
                 <div class="ui accordion">
                     <div class="title">
                     <div class="title">
-                      <i class="dropdown icon"></i>
-                      How to update manually?
+                        <i class="dropdown icon"></i> How to update manually?
                     </div>
                     </div>
                     <div class="content">
                     <div class="content">
                         <p>If your system is not started by any launcher (versions before v1.120), you might want to manually update the ArozOS following the steps below.</p>
                         <p>If your system is not started by any launcher (versions before v1.120), you might want to manually update the ArozOS following the steps below.</p>
@@ -147,7 +150,8 @@
                             <div class="item">SSH into your host, cd into the ArozOS root (Usually located at ~/arozos/src/)</div>
                             <div class="item">SSH into your host, cd into the ArozOS root (Usually located at ~/arozos/src/)</div>
                             <div class="item">Check if the "updates" folder exists. If yes, check if the new ArozOS binary and "system" and "web" folder exists</div>
                             <div class="item">Check if the "updates" folder exists. If yes, check if the new ArozOS binary and "system" and "web" folder exists</div>
                             <div class="item">Backup any important files or config if needed</div>
                             <div class="item">Backup any important files or config if needed</div>
-                            <div class="item">Stop the arozos service using <code>sudo systemctl stop arozos</code></code></div>
+                            <div class="item">Stop the arozos service using <code>sudo systemctl stop arozos</code></code>
+                            </div>
                             <div class="item">Copy the updates to the arozos root using <code>cp -r ./updates/* ./</code></div>
                             <div class="item">Copy the updates to the arozos root using <code>cp -r ./updates/* ./</code></div>
                             <div class="item">Restore the files or config</div>
                             <div class="item">Restore the files or config</div>
                             <div class="item">Start the arozos service using <code>sydo systemctl start arozos</code></div>
                             <div class="item">Start the arozos service using <code>sydo systemctl start arozos</code></div>
@@ -174,21 +178,22 @@
         var useVendorUpdate = false;
         var useVendorUpdate = false;
         var vendorUpdateBinaryURL = "";
         var vendorUpdateBinaryURL = "";
         var vendorUpdateWebpackURL = "";
         var vendorUpdateWebpackURL = "";
+        var vendorUpdateCheckSumURL = "";
 
 
         $(".accordion").accordion();
         $(".accordion").accordion();
         initVendorUpdateInfo();
         initVendorUpdateInfo();
         checkPendingUpdates();
         checkPendingUpdates();
 
 
-        function checkPendingUpdates(){
-            $.get("../../system/update/checkpending", function(data){
-                if (data == true){
+        function checkPendingUpdates() {
+            $.get("../../system/update/checkpending", function(data) {
+                if (data == true) {
                     //There is a pending update.
                     //There is a pending update.
                     hideAllStatus();
                     hideAllStatus();
                     $("#pending").slideDown('fast');
                     $("#pending").slideDown('fast');
-                    $.get("/system/update/restart", function(data){
-                        if (data.error !== undefined){
+                    $.get("/system/update/restart", function(data) {
+                        if (data.error !== undefined) {
                             //No launcher
                             //No launcher
-                        }else{
+                        } else {
                             $("#launcherName").text(data);
                             $("#launcherName").text(data);
                             $("#restartPanel").show();
                             $("#restartPanel").show();
                         }
                         }
@@ -198,91 +203,96 @@
             })
             })
         }
         }
 
 
-        function initVendorUpdateInfo(){
-            $.get("../../system/update/platform", function(data){
+        function initVendorUpdateInfo() {
+            $.get("../../system/update/platform", function(data) {
                 console.log(data);
                 console.log(data);
-                if (data.error !== undefined){
+                if (data.error !== undefined) {
                     //No vendor update modes
                     //No vendor update modes
                     $(".vendorupdate").hide();
                     $(".vendorupdate").hide();
-                }else{
-                    if (data.Config.binary[data.OS] && data.Config.binary[data.OS][data.ARCH]){
+                } else {
+                    if (data.Config.binary[data.OS] && data.Config.binary[data.OS][data.ARCH]) {
                         //This update target exists
                         //This update target exists
                         vendorUpdateBinaryURL = data.Config.binary[data.OS][data.ARCH];
                         vendorUpdateBinaryURL = data.Config.binary[data.OS][data.ARCH];
                     }
                     }
                     vendorUpdateWebpackURL = data.Config.webpack;
                     vendorUpdateWebpackURL = data.Config.webpack;
+                    vendorUpdateCheckSumURL = data.Config.checksum;
                     $(".vendorName").text(data.Config.vendor);
                     $(".vendorName").text(data.Config.vendor);
                 }
                 }
             })
             })
         }
         }
 
 
-        function updateViaVendor(){
+        function updateViaVendor() {
             let binaryDownloadURL = vendorUpdateBinaryURL;
             let binaryDownloadURL = vendorUpdateBinaryURL;
             let webpackDownloadURL = vendorUpdateWebpackURL;
             let webpackDownloadURL = vendorUpdateWebpackURL;
-            if (binaryDownloadURL == "" || webpackDownloadURL == ""){
+
+            if (binaryDownloadURL == "" || webpackDownloadURL == "") {
                 return
                 return
             }
             }
             //Check space need
             //Check space need
             $("#checking").slideDown("fast");
             $("#checking").slideDown("fast");
             $("#warning").slideUp("fast");
             $("#warning").slideUp("fast");
             useVendorUpdate = true;
             useVendorUpdate = true;
-            $.get(`/system/update/checksize?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data){
-                if (data.error != undefined){
+            $.get(`/system/update/checksize?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data) {
+                if (data.error != undefined) {
                     cancelUpdateStatus();
                     cancelUpdateStatus();
                     alert("Update failed: " + data.error)
                     alert("Update failed: " + data.error)
-                }else{
+                } else {
                     let totalDownloadBytes = data[0] + data[1];
                     let totalDownloadBytes = data[0] + data[1];
                     $("#spaceEst").text(ao_module_utils.formatBytes(totalDownloadBytes, 2));
                     $("#spaceEst").text(ao_module_utils.formatBytes(totalDownloadBytes, 2));
                     $("#confirmDownload").slideDown("fast");
                     $("#confirmDownload").slideDown("fast");
                     $("#checking").slideUp("fast");
                     $("#checking").slideUp("fast");
                     console.log(data);
                     console.log(data);
                 }
                 }
-               
+
             })
             })
         }
         }
 
 
-        function updateViaURL(){
+        function updateViaURL() {
             let binaryDownloadURL = $("#burl").val().trim();
             let binaryDownloadURL = $("#burl").val().trim();
             let webpackDownloadURL = $("#wurl").val().trim();
             let webpackDownloadURL = $("#wurl").val().trim();
-            if (binaryDownloadURL == "" || webpackDownloadURL == ""){
+            if (binaryDownloadURL == "" || webpackDownloadURL == "") {
                 alert("Invalid or Empty URL given");
                 alert("Invalid or Empty URL given");
                 return
                 return
             }
             }
             //Check space need
             //Check space need
             $("#checking").slideDown("fast");
             $("#checking").slideDown("fast");
             $("#warning").slideUp("fast");
             $("#warning").slideUp("fast");
-            $.get(`/system/update/checksize?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data){
-                if (data.error != undefined){
+            $.get(`/system/update/checksize?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data) {
+                if (data.error != undefined) {
                     cancelUpdateStatus();
                     cancelUpdateStatus();
                     alert("Update failed: " + data.error)
                     alert("Update failed: " + data.error)
-                }else{
+                } else {
                     let totalDownloadBytes = data[0] + data[1];
                     let totalDownloadBytes = data[0] + data[1];
                     $("#spaceEst").text(ao_module_utils.formatBytes(totalDownloadBytes, 2));
                     $("#spaceEst").text(ao_module_utils.formatBytes(totalDownloadBytes, 2));
                     $("#confirmDownload").slideDown("fast");
                     $("#confirmDownload").slideDown("fast");
                     $("#checking").slideUp("fast");
                     $("#checking").slideUp("fast");
                     console.log(data);
                     console.log(data);
                 }
                 }
-               
+
             })
             })
         }
         }
 
 
-        function confirmURLUpdate(){
+        function confirmURLUpdate() {
             let binaryDownloadURL = $("#burl").val().trim();
             let binaryDownloadURL = $("#burl").val().trim();
             let webpackDownloadURL = $("#wurl").val().trim();
             let webpackDownloadURL = $("#wurl").val().trim();
+            let checksumDownloadURL = "";
 
 
-            if (useVendorUpdate){
+            if (useVendorUpdate) {
                 //Use vendor link for update. Replace the download target with vendor update links
                 //Use vendor link for update. Replace the download target with vendor update links
                 useVendorUpdate = false;
                 useVendorUpdate = false;
                 binaryDownloadURL = vendorUpdateBinaryURL;
                 binaryDownloadURL = vendorUpdateBinaryURL;
                 webpackDownloadURL = vendorUpdateWebpackURL;
                 webpackDownloadURL = vendorUpdateWebpackURL;
+                checksumDownloadURL = vendorUpdateCheckSumURL;
             }
             }
-            if (binaryDownloadURL == "" || webpackDownloadURL == ""){
+            if (binaryDownloadURL == "" || webpackDownloadURL == "") {
                 alert("Invalid or Empty URL given");
                 alert("Invalid or Empty URL given");
                 return
                 return
             }
             }
 
 
             var wsroot = ao_module_utils.getWebSocketEndpoint();
             var wsroot = ao_module_utils.getWebSocketEndpoint();
-            var requestEndpoint = wsroot + `/system/update/download?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}&ws=true`
+            var requestEndpoint = wsroot + `/system/update/download?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}&checksum=${checksumDownloadURL}&ws=true`
             console.log("Connecting to: ", requestEndpoint);
             console.log("Connecting to: ", requestEndpoint);
+            var isFailed = false;
 
 
             hideAllStatus();
             hideAllStatus();
             $("#downloading").slideDown("fast");
             $("#downloading").slideDown("fast");
@@ -296,24 +306,28 @@
 
 
             socket.onmessage = function(event) {
             socket.onmessage = function(event) {
                 let status = JSON.parse(event.data);
                 let status = JSON.parse(event.data);
-                if (status.error !== undefined){
+                if (status.error !== undefined) {
                     hideAllStatus();
                     hideAllStatus();
                     $("#failed").slideDown();
                     $("#failed").slideDown();
                     $("#failedErrorMessage").text(status.error);
                     $("#failedErrorMessage").text(status.error);
-                }else{
+                    $(".updateBtn").removeClass("disabled");
+                    isFailed = true
+                } else {
                     //Progressing
                     //Progressing
                     let progressText = status.Progress.toFixed(2) + "%";
                     let progressText = status.Progress.toFixed(2) + "%";
                     $("#downloadProgressBar").find(".progress").text(progressText);
                     $("#downloadProgressBar").find(".progress").text(progressText);
-                    $("#downloadProgressBar").css("width",status.Progress + "%");
+                    $("#downloadProgressBar").css("width", status.Progress + "%");
                     $("#downloadStatusText").text(`[${status.Stage}] ${status.StatusText}`);
                     $("#downloadStatusText").text(`[${status.Stage}] ${status.StatusText}`);
                 }
                 }
                 console.log(event.data);
                 console.log(event.data);
             };
             };
 
 
             socket.onclose = function(event) {
             socket.onclose = function(event) {
-                hideAllStatus();
-                $("#success").slideDown();
-                checkLauncher();
+                if(!isFailed){
+                    hideAllStatus();
+                    $("#success").slideDown();
+                    checkLauncher();
+                }
             };
             };
 
 
             socket.onerror = function(error) {
             socket.onerror = function(error) {
@@ -322,7 +336,7 @@
             };
             };
         }
         }
 
 
-        function downloadUpdateFallbackMode(binaryDownloadURL, webpackDownloadURL){
+        function downloadUpdateFallbackMode(binaryDownloadURL, webpackDownloadURL) {
             hideAllStatus();
             hideAllStatus();
             $("#downloading").slideDown("fast");
             $("#downloading").slideDown("fast");
             $("#downloadStatusText").text("Waiting for Download Complete (Fallback Mode)");
             $("#downloadStatusText").text("Waiting for Download Complete (Fallback Mode)");
@@ -330,13 +344,13 @@
             $("#downloadProgressBar").find(".progress").text("Downloading");
             $("#downloadProgressBar").find(".progress").text("Downloading");
             $("#downloadProgressBar").css("width", "50%");
             $("#downloadProgressBar").css("width", "50%");
             $(".updateBtn").addClass("disabled");
             $(".updateBtn").addClass("disabled");
-            $.get(`../../system/update/download?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data){
-                if (data.error !== undefined){
+            $.get(`../../system/update/download?webpack=${webpackDownloadURL}&binary=${binaryDownloadURL}`, function(data) {
+                if (data.error !== undefined) {
                     hideAllStatus();
                     hideAllStatus();
                     $("#failed").slideDown();
                     $("#failed").slideDown();
                     $("#failedErrorMessage").text(data.error);
                     $("#failedErrorMessage").text(data.error);
                     $(".updateBtn").removeClass("disabled");
                     $(".updateBtn").removeClass("disabled");
-                }else{
+                } else {
                     hideAllStatus();
                     hideAllStatus();
                     $("#success").slideDown();
                     $("#success").slideDown();
                     checkLauncher();
                     checkLauncher();
@@ -344,38 +358,38 @@
             })
             })
         }
         }
 
 
-        function checkLauncher(){
+        function checkLauncher() {
             $(".updateBtn").removeClass("disabled");
             $(".updateBtn").removeClass("disabled");
-            $.get("/system/update/restart", function(data){
-                if (data.error !== undefined){
+            $.get("/system/update/restart", function(data) {
+                if (data.error !== undefined) {
                     //No launcher
                     //No launcher
                     $("#restartPanel").hide();
                     $("#restartPanel").hide();
-                }else{
+                } else {
                     $("#launcherName").text(data);
                     $("#launcherName").text(data);
                     $("#restartPanel").show();
                     $("#restartPanel").show();
                 }
                 }
                 console.log("Launcher check: ", data);
                 console.log("Launcher check: ", data);
             })
             })
-           
+
         }
         }
 
 
-        function restartArozOS(){
-            if (confirm("CONFIRM RESTART?")){
+        function restartArozOS() {
+            if (confirm("CONFIRM RESTART?")) {
                 window.top.location.href = "../updates/updating.html";
                 window.top.location.href = "../updates/updating.html";
             }
             }
         }
         }
 
 
-        function cancelUpdateStatus(){
+        function cancelUpdateStatus() {
             hideAllStatus();
             hideAllStatus();
             $("#warning").slideDown("fast");
             $("#warning").slideDown("fast");
         }
         }
 
 
-        function restartLater(){
+        function restartLater() {
             hideAllStatus();
             hideAllStatus();
         }
         }
 
 
 
 
-        function hideAllStatus(){
+        function hideAllStatus() {
             $("#warning").slideUp("fast");
             $("#warning").slideUp("fast");
             $("#confirmDownload").slideUp("fast");
             $("#confirmDownload").slideUp("fast");
             $("#checking").slideUp("fast");
             $("#checking").slideUp("fast");
@@ -386,4 +400,5 @@
         }
         }
     </script>
     </script>
 </body>
 </body>
-</html>  
+
+</html>