From ccaca04a5d55b3dcb1f9dea275b3e9501d957621 Mon Sep 17 00:00:00 2001 From: Xiaoxing Ye Date: Sun, 12 Jan 2020 17:12:04 +0800 Subject: [PATCH] rcd: move webgui apart; option to disable browser Fix #3601, #3785 --- MANUAL.html | 4 +- MANUAL.md | 10 +- MANUAL.txt | 7 +- cmd/rcd/rcd.go | 227 ----------------------------------- docs/content/flags.md | 4 +- docs/content/gui.md | 9 +- docs/content/rc.md | 14 ++- fs/rc/rc.go | 4 +- fs/rc/rcflags/rcflags.go | 4 +- fs/rc/rcserver/rcserver.go | 34 +++++- fs/rc/webgui.go | 238 +++++++++++++++++++++++++++++++++++++ 11 files changed, 309 insertions(+), 246 deletions(-) create mode 100644 fs/rc/webgui.go diff --git a/MANUAL.html b/MANUAL.html index c4cf29d31..4c48b5273 100644 --- a/MANUAL.html +++ b/MANUAL.html @@ -3254,7 +3254,7 @@ dir1/dir2/dir3/.ignore

Set the URL to fetch the rclone-web-gui files from.

Default https://api.github.com/repos/rclone/rclone-webui-react/releases/latest.

–rc-web-gui-update

-

Set this flag to Download / Force update rclone-webui-react from the rc-web-fetch-url.

+

Set this flag to check and update rclone-webui-react from the rc-web-fetch-url.

Default Off.

–rc-job-expire-duration=DURATION

Expire finished async jobs older than DURATION (default 60s).

@@ -4384,7 +4384,7 @@ These flags are available for every command. --ca-cert string CA certificate used to verify servers --cache-dir string Directory rclone will use for caching. (default "$HOME/.cache/rclone") --checkers int Number of checkers to run in parallel. (default 8) -

-c, –checksum Skip based on checksum (if available) & size, not mod-time & size –client-cert string Client SSL certificate (PEM) for mutual TLS auth –client-key string Client SSL private key (PEM) for mutual TLS auth –compare-dest string use DIR to server side copy flies from. –config string Config file. (default “$HOME/.config/rclone/rclone.conf”) –contimeout duration Connect timeout (default 1m0s) –copy-dest string Compare dest to DIR also. –cpuprofile string Write cpu profile to file –delete-after When synchronizing, delete files on destination after transferring (default) –delete-before When synchronizing, delete files on destination before transferring –delete-during When synchronizing, delete files during transfer –delete-excluded Delete files on dest excluded from sync –disable string Disable a comma separated list of features. Use help to see a list. -n, –dry-run Do a trial run with no permanent changes –dump DumpFlags List of items to dump from: headers,bodies,requests,responses,auth,filters,goroutines,openfiles –dump-bodies Dump HTTP headers and bodies - may contain sensitive info –dump-headers Dump HTTP headers - may contain sensitive info –exclude stringArray Exclude files matching pattern –exclude-from stringArray Read exclude patterns from file –exclude-if-present string Exclude directories if filename is present –fast-list Use recursive list if available. Uses more memory but fewer transactions. –files-from stringArray Read list of source-file names from file -f, –filter stringArray Add a file-filtering rule –filter-from stringArray Read filtering patterns from a file –ignore-case Ignore case in filters (case insensitive) –ignore-case-sync Ignore case when synchronizing –ignore-checksum Skip post copy check of checksums. –ignore-errors delete even if there are I/O errors –ignore-existing Skip all files that exist on destination –ignore-size Ignore size when skipping use mod-time or checksum. -I, –ignore-times Don’t skip files that match size and time - transfer all files –immutable Do not modify files. Fail if existing files have been modified. –include stringArray Include files matching pattern –include-from stringArray Read include patterns from file –log-file string Log everything to this file –log-format string Comma separated list of log format options (default “date,time”) –log-level string Log level DEBUG|INFO|NOTICE|ERROR (default “NOTICE”) –low-level-retries int Number of low level retries to do. (default 10) –max-age Duration Only transfer files younger than this in s or suffix ms|s|m|h|d|w|M|y (default off) –max-backlog int Maximum number of objects in sync or check backlog. (default 10000) –max-delete int When synchronizing, limit the number of deletes (default -1) –max-depth int If set limits the recursion depth to this. (default -1) –max-size SizeSuffix Only transfer files smaller than this in k or suffix b|k|M|G (default off) –max-stats-groups int Maximum number of stats groups to keep in memory. On max oldest is discarded. (default 1000) –max-transfer SizeSuffix Maximum size of data to transfer. (default off) –memprofile string Write memory profile to file –min-age Duration Only transfer files older than this in s or suffix ms|s|m|h|d|w|M|y (default off) –min-size SizeSuffix Only transfer files bigger than this in k or suffix b|k|M|G (default off) –modify-window duration Max time diff to be considered the same (default 1ns) –multi-thread-cutoff SizeSuffix Use multi-thread downloads for files above this size. (default 250M) –multi-thread-streams int Max number of streams to use for multi-thread downloads. (default 4) –no-check-certificate Do not verify the server SSL certificate. Insecure. –no-gzip-encoding Don’t set Accept-Encoding: gzip. –no-traverse Don’t traverse destination file system on copy. –no-update-modtime Don’t update destination mod-time if files identical. -P, –progress Show progress during transfer. -q, –quiet Print as little stuff as possible –rc Enable the remote control server. –rc-addr string IPaddress:Port or :Port to bind server to. (default “localhost:5572”) –rc-allow-origin string Set the allowed origin for CORS. –rc-baseurl string Prefix for URLs - leave blank for root. –rc-cert string SSL PEM key (concatenation of certificate and CA certificate) –rc-client-ca string Client certificate authority to verify clients with –rc-files string Path to local files to serve on the HTTP server. –rc-htpasswd string htpasswd file - if not provided no authentication is done –rc-job-expire-duration duration expire finished async jobs older than this value (default 1m0s) –rc-job-expire-interval duration interval to check for expired async jobs (default 10s) –rc-key string SSL PEM Private key –rc-max-header-bytes int Maximum size of request header (default 4096) –rc-no-auth Don’t require auth for certain methods. –rc-pass string Password for authentication. –rc-realm string realm for authentication (default “rclone”) –rc-serve Enable the serving of remote objects. –rc-server-read-timeout duration Timeout for server reading data (default 1h0m0s) –rc-server-write-timeout duration Timeout for server writing data (default 1h0m0s) –rc-user string User name for authentication. –rc-web-fetch-url string URL to fetch the releases for webgui. (default “https://api.github.com/repos/rclone/rclone-webui-react/releases/latest”) –rc-web-gui Launch WebGUI on localhost –rc-web-gui-update Update / Force update to latest version of web gui –retries int Retry operations this many times if they fail (default 3) –retries-sleep duration Interval between retrying operations if they fail, e.g 500ms, 60s, 5m. (0 to disable) –size-only Skip based on size only, not mod-time or checksum –stats duration Interval between printing stats, e.g 500ms, 60s, 5m. (0 to disable) (default 1m0s) –stats-file-name-length int Max file name length in stats. 0 for no limit (default 45) –stats-log-level string Log level to show –stats output DEBUG|INFO|NOTICE|ERROR (default “INFO”) –stats-one-line Make the stats fit on one line. –stats-one-line-date Enables –stats-one-line and add current date/time prefix. –stats-one-line-date-format string Enables –stats-one-line-date and uses custom formatted date. Enclose date string in double quotes (“). See https://golang.org/pkg/time/#Time.Format –stats-unit string Show data rate in stats as either ‘bits’ or ‘bytes’/s (default”bytes“) –streaming-upload-cutoff SizeSuffix Cutoff for switching to chunked upload if file size is unknown. Upload starts after reaching cutoff or when file ends. (default 100k) –suffix string Suffix to add to changed files. –suffix-keep-extension Preserve the extension when using –suffix. –syslog Use Syslog for logging –syslog-facility string Facility for syslog, eg KERN,USER,… (default”DAEMON“) –timeout duration IO idle timeout (default 5m0s) –tpslimit float Limit HTTP transactions per second to this. –tpslimit-burst int Max burst of transactions for –tpslimit. (default 1) –track-renames When synchronizing, track file renames and do a server side move if possible –transfers int Number of file transfers to run in parallel. (default 4) -u, –update Skip files that are newer on the destination. –use-cookies Enable session cookiejar. –use-json-log Use json log format. –use-mmap Use mmap allocator (see docs). –use-server-modtime Use server modified time instead of object metadata –user-agent string Set the user-agent to a specified string. The default is rclone/ version (default”rclone/v1.50.0") -v, –verbose count Print lots more stuff (repeat for more)

+

-c, –checksum Skip based on checksum (if available) & size, not mod-time & size –client-cert string Client SSL certificate (PEM) for mutual TLS auth –client-key string Client SSL private key (PEM) for mutual TLS auth –compare-dest string use DIR to server side copy flies from. –config string Config file. (default “$HOME/.config/rclone/rclone.conf”) –contimeout duration Connect timeout (default 1m0s) –copy-dest string Compare dest to DIR also. –cpuprofile string Write cpu profile to file –delete-after When synchronizing, delete files on destination after transferring (default) –delete-before When synchronizing, delete files on destination before transferring –delete-during When synchronizing, delete files during transfer –delete-excluded Delete files on dest excluded from sync –disable string Disable a comma separated list of features. Use help to see a list. -n, –dry-run Do a trial run with no permanent changes –dump DumpFlags List of items to dump from: headers,bodies,requests,responses,auth,filters,goroutines,openfiles –dump-bodies Dump HTTP headers and bodies - may contain sensitive info –dump-headers Dump HTTP headers - may contain sensitive info –exclude stringArray Exclude files matching pattern –exclude-from stringArray Read exclude patterns from file –exclude-if-present string Exclude directories if filename is present –fast-list Use recursive list if available. Uses more memory but fewer transactions. –files-from stringArray Read list of source-file names from file -f, –filter stringArray Add a file-filtering rule –filter-from stringArray Read filtering patterns from a file –ignore-case Ignore case in filters (case insensitive) –ignore-case-sync Ignore case when synchronizing –ignore-checksum Skip post copy check of checksums. –ignore-errors delete even if there are I/O errors –ignore-existing Skip all files that exist on destination –ignore-size Ignore size when skipping use mod-time or checksum. -I, –ignore-times Don’t skip files that match size and time - transfer all files –immutable Do not modify files. Fail if existing files have been modified. –include stringArray Include files matching pattern –include-from stringArray Read include patterns from file –log-file string Log everything to this file –log-format string Comma separated list of log format options (default “date,time”) –log-level string Log level DEBUG|INFO|NOTICE|ERROR (default “NOTICE”) –low-level-retries int Number of low level retries to do. (default 10) –max-age Duration Only transfer files younger than this in s or suffix ms|s|m|h|d|w|M|y (default off) –max-backlog int Maximum number of objects in sync or check backlog. (default 10000) –max-delete int When synchronizing, limit the number of deletes (default -1) –max-depth int If set limits the recursion depth to this. (default -1) –max-size SizeSuffix Only transfer files smaller than this in k or suffix b|k|M|G (default off) –max-stats-groups int Maximum number of stats groups to keep in memory. On max oldest is discarded. (default 1000) –max-transfer SizeSuffix Maximum size of data to transfer. (default off) –memprofile string Write memory profile to file –min-age Duration Only transfer files older than this in s or suffix ms|s|m|h|d|w|M|y (default off) –min-size SizeSuffix Only transfer files bigger than this in k or suffix b|k|M|G (default off) –modify-window duration Max time diff to be considered the same (default 1ns) –multi-thread-cutoff SizeSuffix Use multi-thread downloads for files above this size. (default 250M) –multi-thread-streams int Max number of streams to use for multi-thread downloads. (default 4) –no-check-certificate Do not verify the server SSL certificate. Insecure. –no-gzip-encoding Don’t set Accept-Encoding: gzip. –no-traverse Don’t traverse destination file system on copy. –no-update-modtime Don’t update destination mod-time if files identical. -P, –progress Show progress during transfer. -q, –quiet Print as little stuff as possible –rc Enable the remote control server. –rc-addr string IPaddress:Port or :Port to bind server to. (default “localhost:5572”) –rc-allow-origin string Set the allowed origin for CORS. –rc-baseurl string Prefix for URLs - leave blank for root. –rc-cert string SSL PEM key (concatenation of certificate and CA certificate) –rc-client-ca string Client certificate authority to verify clients with –rc-files string Path to local files to serve on the HTTP server. –rc-htpasswd string htpasswd file - if not provided no authentication is done –rc-job-expire-duration duration expire finished async jobs older than this value (default 1m0s) –rc-job-expire-interval duration interval to check for expired async jobs (default 10s) –rc-key string SSL PEM Private key –rc-max-header-bytes int Maximum size of request header (default 4096) –rc-no-auth Don’t require auth for certain methods. –rc-pass string Password for authentication. –rc-realm string realm for authentication (default “rclone”) –rc-serve Enable the serving of remote objects. –rc-server-read-timeout duration Timeout for server reading data (default 1h0m0s) –rc-server-write-timeout duration Timeout for server writing data (default 1h0m0s) –rc-user string User name for authentication. –rc-web-fetch-url string URL to fetch the releases for webgui. (default “https://api.github.com/repos/rclone/rclone-webui-react/releases/latest”) –rc-web-gui Launch WebGUI on localhost –rc-web-gui-update Check and update to latest version of web gui –retries int Retry operations this many times if they fail (default 3) –retries-sleep duration Interval between retrying operations if they fail, e.g 500ms, 60s, 5m. (0 to disable) –size-only Skip based on size only, not mod-time or checksum –stats duration Interval between printing stats, e.g 500ms, 60s, 5m. (0 to disable) (default 1m0s) –stats-file-name-length int Max file name length in stats. 0 for no limit (default 45) –stats-log-level string Log level to show –stats output DEBUG|INFO|NOTICE|ERROR (default “INFO”) –stats-one-line Make the stats fit on one line. –stats-one-line-date Enables –stats-one-line and add current date/time prefix. –stats-one-line-date-format string Enables –stats-one-line-date and uses custom formatted date. Enclose date string in double quotes (“). See https://golang.org/pkg/time/#Time.Format –stats-unit string Show data rate in stats as either ‘bits’ or ‘bytes’/s (default”bytes“) –streaming-upload-cutoff SizeSuffix Cutoff for switching to chunked upload if file size is unknown. Upload starts after reaching cutoff or when file ends. (default 100k) –suffix string Suffix to add to changed files. –suffix-keep-extension Preserve the extension when using –suffix. –syslog Use Syslog for logging –syslog-facility string Facility for syslog, eg KERN,USER,… (default”DAEMON“) –timeout duration IO idle timeout (default 5m0s) –tpslimit float Limit HTTP transactions per second to this. –tpslimit-burst int Max burst of transactions for –tpslimit. (default 1) –track-renames When synchronizing, track file renames and do a server side move if possible –transfers int Number of file transfers to run in parallel. (default 4) -u, –update Skip files that are newer on the destination. –use-cookies Enable session cookiejar. –use-json-log Use json log format. –use-mmap Use mmap allocator (see docs). –use-server-modtime Use server modified time instead of object metadata –user-agent string Set the user-agent to a specified string. The default is rclone/ version (default”rclone/v1.50.0") -v, –verbose count Print lots more stuff (repeat for more)


 ## Backend Flags
 
diff --git a/MANUAL.md b/MANUAL.md
index 402fb81b0..90fc33113 100644
--- a/MANUAL.md
+++ b/MANUAL.md
@@ -6723,8 +6723,10 @@ This will produce logs like this and rclone needs to continue to run to serve th
 This assumes you are running rclone locally on your machine.  It is
 possible to separate the rclone and the GUI - see below for details.
 
-If you wish to update to the latest API version then you can add
-`--rc-web-gui-update` to the command line.
+By default, rclone will NOT check for GUI update each time it operates. You may alter this
+behaviour by using `--rc-web-gui-update` to check and update.
+
+Also, rclone will open the default browser automatically. You may disable it by using `--rc-web-gui-no-open-browser`.
 
 ## Using the GUI
 
@@ -6900,7 +6902,7 @@ Default https://api.github.com/repos/rclone/rclone-webui-react/releases/latest.
 
 ### --rc-web-gui-update
 
-Set this flag to Download / Force update rclone-webui-react from the rc-web-fetch-url.
+Set this flag to check and update rclone-webui-react from the rc-web-fetch-url.
 
 Default Off.
 
@@ -8426,7 +8428,7 @@ These flags are available for every command.
       --rc-user string                       User name for authentication.
       --rc-web-fetch-url string              URL to fetch the releases for webgui. (default "https://api.github.com/repos/rclone/rclone-webui-react/releases/latest")
       --rc-web-gui                           Launch WebGUI on localhost
-      --rc-web-gui-update                    Update / Force update to latest version of web gui
+      --rc-web-gui-update                    Check and update to latest version of web gui
       --retries int                          Retry operations this many times if they fail (default 3)
       --retries-sleep duration               Interval between retrying operations if they fail, e.g 500ms, 60s, 5m. (0 to disable)
       --size-only                            Skip based on size only, not mod-time or checksum
diff --git a/MANUAL.txt b/MANUAL.txt
index bdfcd5269..99eae2213 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -6353,7 +6353,7 @@ serve the GUI:
 This assumes you are running rclone locally on your machine. It is
 possible to separate the rclone and the GUI - see below for details.
 
-If you wish to update to the latest API version then you can add
+If you wish to check and update to the latest API version then you can add
 --rc-web-gui-update to the command line.
 
 
@@ -6550,9 +6550,10 @@ https://api.github.com/repos/rclone/rclone-webui-react/releases/latest.
 
 –rc-web-gui-update
 
-Set this flag to Download / Force update rclone-webui-react from the
+Set this flag to check and update rclone-webui-react from the
 rc-web-fetch-url.
 
+
 Default Off.
 
 –rc-job-expire-duration=DURATION
@@ -7980,7 +7981,7 @@ server writing data (default 1h0m0s) –rc-user string User name for
 authentication. –rc-web-fetch-url string URL to fetch the releases for
 webgui. (default
 “https://api.github.com/repos/rclone/rclone-webui-react/releases/latest”)
-–rc-web-gui Launch WebGUI on localhost –rc-web-gui-update Update / Force
+–rc-web-gui Launch WebGUI on localhost –rc-web-gui-update Check and
 update to latest version of web gui –retries int Retry operations this
 many times if they fail (default 3) –retries-sleep duration Interval
 between retrying operations if they fail, e.g 500ms, 60s, 5m. (0 to
diff --git a/cmd/rcd/rcd.go b/cmd/rcd/rcd.go
index 0e2b15fde..240b6a272 100644
--- a/cmd/rcd/rcd.go
+++ b/cmd/rcd/rcd.go
@@ -1,25 +1,11 @@
 package rcd
 
 import (
-	"archive/zip"
-	"encoding/json"
-	"fmt"
-	"io"
 	"log"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strconv"
-	"strings"
-	"time"
 
 	"github.com/rclone/rclone/cmd"
-	"github.com/rclone/rclone/fs"
-	"github.com/rclone/rclone/fs/config"
 	"github.com/rclone/rclone/fs/rc/rcflags"
 	"github.com/rclone/rclone/fs/rc/rcserver"
-	"github.com/rclone/rclone/lib/errors"
-	"github.com/rclone/rclone/lib/random"
 	"github.com/spf13/cobra"
 )
 
@@ -53,29 +39,6 @@ See the [rc documentation](/rc/) for more info on the rc flags.
 			rcflags.Opt.Files = args[0]
 		}
 
-		if rcflags.Opt.WebUI {
-			if err := checkRelease(rcflags.Opt.WebGUIUpdate); err != nil {
-				log.Fatalf("Error while fetching the latest release of rclone-webui-react %v", err)
-			}
-			if rcflags.Opt.NoAuth {
-				rcflags.Opt.NoAuth = false
-				fs.Infof(nil, "Cannot run web-gui without authentication, using default auth")
-			}
-			if rcflags.Opt.HTTPOptions.BasicUser == "" {
-				rcflags.Opt.HTTPOptions.BasicUser = "gui"
-				fs.Infof(nil, "Using default username: %s \n", rcflags.Opt.HTTPOptions.BasicUser)
-			}
-			if rcflags.Opt.HTTPOptions.BasicPass == "" {
-				randomPass, err := random.Password(128)
-				if err != nil {
-					log.Fatalf("Failed to make password: %v", err)
-				}
-				rcflags.Opt.HTTPOptions.BasicPass = randomPass
-				fs.Infof(nil, "No password specified. Using random password: %s \n", randomPass)
-			}
-			rcflags.Opt.Serve = true
-		}
-
 		s, err := rcserver.Start(&rcflags.Opt)
 		if err != nil {
 			log.Fatalf("Failed to start remote control: %v", err)
@@ -87,193 +50,3 @@ See the [rc documentation](/rc/) for more info on the rc flags.
 		s.Wait()
 	},
 }
-
-//checkRelease is a helper function to download and setup latest release of rclone-webui-react
-func checkRelease(shouldUpdate bool) (err error) {
-	cachePath := filepath.Join(config.CacheDir, "webgui")
-	extractPath := filepath.Join(cachePath, "current")
-	oldUpdateExists := exists(extractPath)
-
-	// if the old file exists does not exist or forced update is enforced.
-	// TODO: Add hashing to check integrity of the previous update.
-	if !oldUpdateExists || shouldUpdate {
-		// Get the latest release details
-		WebUIURL, tag, size, err := getLatestReleaseURL()
-		if err != nil {
-			return err
-		}
-
-		zipName := tag + ".zip"
-		zipPath := filepath.Join(cachePath, zipName)
-
-		if !exists(cachePath) {
-			if err := os.MkdirAll(cachePath, 0755); err != nil {
-				fs.Logf(nil, "Error creating cache directory: %s", cachePath)
-				return err
-			}
-		}
-
-		fs.Logf(nil, "A new release for gui is present at "+WebUIURL)
-		fs.Logf(nil, "Downloading webgui binary. Please wait. [Size: %s, Path :  %s]\n", strconv.Itoa(size), zipPath)
-
-		// download the zip from latest url
-		err = downloadFile(zipPath, WebUIURL)
-		if err != nil {
-			return err
-		}
-		err = os.RemoveAll(extractPath)
-		if err != nil {
-			fs.Logf(nil, "No previous downloads to remove")
-		}
-		fs.Logf(nil, "Unzipping")
-		err = unzip(zipPath, extractPath)
-		if err != nil {
-			return err
-		}
-
-	} else {
-		fs.Logf(nil, "Required files exist. Skipping download")
-	}
-	return nil
-}
-
-// getLatestReleaseURL returns the latest release details of the rclone-webui-react
-func getLatestReleaseURL() (string, string, int, error) {
-	resp, err := http.Get(rcflags.Opt.WebGUIFetchURL)
-	if err != nil {
-		return "", "", 0, errors.New("Error getting latest release of rclone-webui")
-	}
-	results := gitHubRequest{}
-	if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
-		return "", "", 0, errors.New("Could not decode results from http request")
-	}
-
-	res := results.Assets[0].BrowserDownloadURL
-	tag := results.TagName
-	size := results.Assets[0].Size
-	//fmt.Println( "URL:" + res)
-
-	return res, tag, size, nil
-
-}
-
-// downloadFile is a helper function to download a file from url to the filepath
-func downloadFile(filepath string, url string) error {
-
-	// Get the data
-	resp, err := http.Get(url)
-	if err != nil {
-		return err
-	}
-	defer fs.CheckClose(resp.Body, &err)
-
-	// Create the file
-	out, err := os.Create(filepath)
-	if err != nil {
-		return err
-	}
-	defer fs.CheckClose(out, &err)
-
-	// Write the body to file
-	_, err = io.Copy(out, resp.Body)
-	return err
-}
-
-// unzip is a helper function to unzip a file specified in src to path dest
-func unzip(src, dest string) (err error) {
-	dest = filepath.Clean(dest) + string(os.PathSeparator)
-
-	r, err := zip.OpenReader(src)
-	if err != nil {
-		return err
-	}
-	defer fs.CheckClose(r, &err)
-
-	if err := os.MkdirAll(dest, 0755); err != nil {
-		return err
-	}
-
-	// Closure to address file descriptors issue with all the deferred .Close() methods
-	extractAndWriteFile := func(f *zip.File) error {
-		path := filepath.Join(dest, f.Name)
-		// Check for Zip Slip: https://github.com/rclone/rclone/issues/3529
-		if !strings.HasPrefix(path, dest) {
-			return fmt.Errorf("%s: illegal file path", path)
-		}
-
-		rc, err := f.Open()
-		if err != nil {
-			return err
-		}
-		defer fs.CheckClose(rc, &err)
-
-		if f.FileInfo().IsDir() {
-			if err := os.MkdirAll(path, 0755); err != nil {
-				return err
-			}
-		} else {
-			if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
-				return err
-			}
-			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
-			if err != nil {
-				return err
-			}
-			defer fs.CheckClose(f, &err)
-
-			_, err = io.Copy(f, rc)
-			if err != nil {
-				return err
-			}
-		}
-		return nil
-	}
-
-	for _, f := range r.File {
-		err := extractAndWriteFile(f)
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// exists returns whether the given file or directory exists
-func exists(path string) bool {
-	_, err := os.Stat(path)
-	if err == nil {
-		return true
-	}
-	if os.IsNotExist(err) {
-		return false
-	}
-	return true
-}
-
-// gitHubRequest Maps the GitHub API request to structure
-type gitHubRequest struct {
-	URL string `json:"url"`
-
-	Prerelease  bool      `json:"prerelease"`
-	CreatedAt   time.Time `json:"created_at"`
-	PublishedAt time.Time `json:"published_at"`
-	TagName     string    `json:"tag_name"`
-	Assets      []struct {
-		URL                string    `json:"url"`
-		ID                 int       `json:"id"`
-		NodeID             string    `json:"node_id"`
-		Name               string    `json:"name"`
-		Label              string    `json:"label"`
-		ContentType        string    `json:"content_type"`
-		State              string    `json:"state"`
-		Size               int       `json:"size"`
-		DownloadCount      int       `json:"download_count"`
-		CreatedAt          time.Time `json:"created_at"`
-		UpdatedAt          time.Time `json:"updated_at"`
-		BrowserDownloadURL string    `json:"browser_download_url"`
-	} `json:"assets"`
-	TarballURL string `json:"tarball_url"`
-	ZipballURL string `json:"zipball_url"`
-	Body       string `json:"body"`
-}
diff --git a/docs/content/flags.md b/docs/content/flags.md
index c996a033b..8dfccd8c2 100755
--- a/docs/content/flags.md
+++ b/docs/content/flags.md
@@ -101,7 +101,9 @@ These flags are available for every command.
       --rc-user string                       User name for authentication.
       --rc-web-fetch-url string              URL to fetch the releases for webgui. (default "https://api.github.com/repos/rclone/rclone-webui-react/releases/latest")
       --rc-web-gui                           Launch WebGUI on localhost
-      --rc-web-gui-update                    Update / Force update to latest version of web gui
+      --rc-web-gui-update                    Check and update to latest version of web gui
+      --rc-web-gui-force-update              Force update to latest version of web gui
+      --rc-web-gui-no-open-browser           Don't open browser automatically
       --retries int                          Retry operations this many times if they fail (default 3)
       --retries-sleep duration               Interval between retrying operations if they fail, e.g 500ms, 60s, 5m. (0 to disable)
       --size-only                            Skip based on size only, not mod-time or checksum
diff --git a/docs/content/gui.md b/docs/content/gui.md
index d5aa0e825..22b3e6aa7 100644
--- a/docs/content/gui.md
+++ b/docs/content/gui.md
@@ -29,8 +29,13 @@ This will produce logs like this and rclone needs to continue to run to serve th
 This assumes you are running rclone locally on your machine.  It is
 possible to separate the rclone and the GUI - see below for details.
 
-If you wish to update to the latest API version then you can add
-`--rc-web-gui-update` to the command line.
+If you wish to check for updates then you can add `--rc-web-gui-update` 
+to the command line.
+
+If you find your GUI broken, you may force it to update by add `--rc-web-gui-force-update`.
+
+By default, rclone will open your browser. Add `--rc-web-gui-no-open-browser` 
+to disable this feature.
 
 ## Using the GUI
 
diff --git a/docs/content/rc.md b/docs/content/rc.md
index 22f46ec8f..c7d654bb1 100644
--- a/docs/content/rc.md
+++ b/docs/content/rc.md
@@ -107,7 +107,19 @@ Default https://api.github.com/repos/rclone/rclone-webui-react/releases/latest.
 
 ### --rc-web-gui-update
 
-Set this flag to Download / Force update rclone-webui-react from the rc-web-fetch-url.
+Set this flag to check and update rclone-webui-react from the rc-web-fetch-url.
+
+Default Off.
+
+### --rc-web-gui-force-update
+
+Set this flag to force update rclone-webui-react from the rc-web-fetch-url.
+
+Default Off.
+
+### --rc-web-gui-no-open-browser
+
+Set this flag to disable opening browser automatically when using web-gui.
 
 Default Off.
 
diff --git a/fs/rc/rc.go b/fs/rc/rc.go
index a6164d9d7..2ac58022f 100644
--- a/fs/rc/rc.go
+++ b/fs/rc/rc.go
@@ -24,7 +24,9 @@ type Options struct {
 	Files                    string // set to enable serving files locally
 	NoAuth                   bool   // set to disable auth checks on AuthRequired methods
 	WebUI                    bool   // set to launch the web ui
-	WebGUIUpdate             bool   // set to download new update
+	WebGUIUpdate             bool   // set to check new update
+	WebGUIForceUpdate        bool   // set to force download new update
+	WebGUINoOpenBrowser      bool   // set to disable auto opening browser
 	WebGUIFetchURL           string // set the default url for fetching webgui
 	AccessControlAllowOrigin string // set the access control for CORS configuration
 	JobExpireDuration        time.Duration
diff --git a/fs/rc/rcflags/rcflags.go b/fs/rc/rcflags/rcflags.go
index 0bf75c983..40aaadf07 100644
--- a/fs/rc/rcflags/rcflags.go
+++ b/fs/rc/rcflags/rcflags.go
@@ -21,7 +21,9 @@ func AddFlags(flagSet *pflag.FlagSet) {
 	flags.BoolVarP(flagSet, &Opt.Serve, "rc-serve", "", false, "Enable the serving of remote objects.")
 	flags.BoolVarP(flagSet, &Opt.NoAuth, "rc-no-auth", "", false, "Don't require auth for certain methods.")
 	flags.BoolVarP(flagSet, &Opt.WebUI, "rc-web-gui", "", false, "Launch WebGUI on localhost")
-	flags.BoolVarP(flagSet, &Opt.WebGUIUpdate, "rc-web-gui-update", "", false, "Update / Force update to latest version of web gui")
+	flags.BoolVarP(flagSet, &Opt.WebGUIUpdate, "rc-web-gui-update", "", false, "Check and update to latest version of web gui")
+	flags.BoolVarP(flagSet, &Opt.WebGUIForceUpdate, "rc-web-gui-force-update", "", false, "Force update to latest version of web gui")
+	flags.BoolVarP(flagSet, &Opt.WebGUINoOpenBrowser, "rc-web-gui-no-open-browser", "", false, "Don't open the browser automatically")
 	flags.StringVarP(flagSet, &Opt.WebGUIFetchURL, "rc-web-fetch-url", "", "https://api.github.com/repos/rclone/rclone-webui-react/releases/latest", "URL to fetch the releases for webgui.")
 	flags.StringVarP(flagSet, &Opt.AccessControlAllowOrigin, "rc-allow-origin", "", "", "Set the allowed origin for CORS.")
 	flags.DurationVarP(flagSet, &Opt.JobExpireDuration, "rc-job-expire-duration", "", Opt.JobExpireDuration, "expire finished async jobs older than this value")
diff --git a/fs/rc/rcserver/rcserver.go b/fs/rc/rcserver/rcserver.go
index f52faa761..4a2b5c71e 100644
--- a/fs/rc/rcserver/rcserver.go
+++ b/fs/rc/rcserver/rcserver.go
@@ -6,6 +6,7 @@ import (
 	"encoding/json"
 	"flag"
 	"fmt"
+	"log"
 	"mime"
 	"net/http"
 	"net/url"
@@ -24,6 +25,7 @@ import (
 	"github.com/rclone/rclone/fs/rc"
 	"github.com/rclone/rclone/fs/rc/jobs"
 	"github.com/rclone/rclone/fs/rc/rcflags"
+	"github.com/rclone/rclone/lib/random"
 	"github.com/skratchdot/open-golang/open"
 )
 
@@ -68,6 +70,28 @@ func newServer(opt *rc.Options, mux *http.ServeMux) *Server {
 		fs.Logf(nil, "Serving files from %q", opt.Files)
 		s.files = http.FileServer(http.Dir(opt.Files))
 	} else if opt.WebUI {
+		if err := rc.CheckAndDownloadWebGUIRelease(opt.WebGUIUpdate, opt.WebGUIForceUpdate, opt.WebGUIFetchURL, config.CacheDir); err != nil {
+			log.Fatalf("Error while fetching the latest release of Web GUI: %v", err)
+		}
+		if opt.NoAuth {
+			opt.NoAuth = false
+			fs.Infof(nil, "Cannot run Web GUI without authentication, using default auth")
+		}
+		if opt.HTTPOptions.BasicUser == "" {
+			opt.HTTPOptions.BasicUser = "gui"
+			fs.Infof(nil, "No username specified. Using default username: %s \n", rcflags.Opt.HTTPOptions.BasicUser)
+		}
+		if opt.HTTPOptions.BasicPass == "" {
+			randomPass, err := random.Password(128)
+			if err != nil {
+				log.Fatalf("Failed to make password: %v", err)
+			}
+			opt.HTTPOptions.BasicPass = randomPass
+			fs.Infof(nil, "No password specified. Using random password: %s \n", randomPass)
+		}
+		opt.Serve = true
+
+		fs.Logf(nil, "Serving Web GUI")
 		s.files = http.FileServer(http.Dir(extractPath))
 	}
 	return s
@@ -102,11 +126,13 @@ func (s *Server) Serve() error {
 			openURL.RawQuery = parameters.Encode()
 			openURL.RawPath = "/#/login"
 		}
-		// Don't open browser if serving in testing environment.
-		if flag.Lookup("test.v") == nil {
-			_ = open.Start(openURL.String())
+		// Don't open browser if serving in testing environment or required not to do so.
+		if flag.Lookup("test.v") == nil && !s.opt.WebGUINoOpenBrowser {
+			if err := open.Start(openURL.String()); err != nil {
+				fs.Errorf(nil, "Failed to open Web GUI in browser: %v. Manually access it at: %s", err, openURL.String())
+			}
 		} else {
-			fs.Errorf(nil, "Not opening browser in testing environment")
+			fs.Logf(nil, "Web GUI is not automatically opening browser. Navigate to %s to use.", openURL.String())
 		}
 	}
 	return nil
diff --git a/fs/rc/webgui.go b/fs/rc/webgui.go
new file mode 100644
index 000000000..cc3c1a009
--- /dev/null
+++ b/fs/rc/webgui.go
@@ -0,0 +1,238 @@
+// Define the Web GUI helpers
+
+package rc
+
+import (
+	"archive/zip"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/rclone/rclone/fs"
+	"github.com/rclone/rclone/lib/errors"
+)
+
+// getLatestReleaseURL returns the latest release details of the rclone-webui-react
+func getLatestReleaseURL(fetchURL string) (string, string, int, error) {
+	resp, err := http.Get(fetchURL)
+	if err != nil {
+		return "", "", 0, errors.New("Error getting latest release of rclone-webui")
+	}
+	results := gitHubRequest{}
+	if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
+		return "", "", 0, errors.New("Could not decode results from http request")
+	}
+
+	res := results.Assets[0].BrowserDownloadURL
+	tag := results.TagName
+	size := results.Assets[0].Size
+
+	return res, tag, size, nil
+}
+
+// CheckAndDownloadWebGUIRelease is a helper function to download and setup latest release of rclone-webui-react
+func CheckAndDownloadWebGUIRelease(checkUpdate bool, forceUpdate bool, fetchURL string, cacheDir string) (err error) {
+	cachePath := filepath.Join(cacheDir, "webgui")
+	tagPath := filepath.Join(cachePath, "tag")
+	extractPath := filepath.Join(cachePath, "current")
+
+	extractPathExist, extractPathStat, err := exists(extractPath)
+
+	if extractPathExist && !extractPathStat.IsDir() {
+		return errors.New("Web GUI path exists, but is a file instead of folder. Please check the path " + extractPath)
+	}
+
+	// if the old file exists does not exist or forced update is enforced.
+	// TODO: Add hashing to check integrity of the previous update.
+	if !extractPathExist || checkUpdate || forceUpdate {
+		// Get the latest release details
+		WebUIURL, tag, size, err := getLatestReleaseURL(fetchURL)
+		if err != nil {
+			return err
+		}
+
+		dat, err := ioutil.ReadFile(tagPath)
+		if err == nil && string(dat) == tag {
+			fs.Logf(nil, "No update to Web GUI available.")
+			if !forceUpdate {
+				return nil
+			}
+			fs.Logf(nil, "Force update the Web GUI binary.")
+		}
+
+		zipName := tag + ".zip"
+		zipPath := filepath.Join(cachePath, zipName)
+
+		cachePathExist, cachePathStat, _ := exists(cachePath)
+		if !cachePathExist {
+			if err := os.MkdirAll(cachePath, 0755); err != nil {
+				return errors.New("Error creating cache directory: " + cachePath)
+			}
+		}
+
+		if cachePathExist && !cachePathStat.IsDir() {
+			return errors.New("Web GUI path is a file instead of folder. Please check it " + extractPath)
+		}
+
+		fs.Logf(nil, "A new release for gui is present at "+WebUIURL)
+		fs.Logf(nil, "Downloading webgui binary. Please wait. [Size: %s, Path :  %s]\n", strconv.Itoa(size), zipPath)
+
+		// download the zip from latest url
+		err = downloadFile(zipPath, WebUIURL)
+		if err != nil {
+			return err
+		}
+
+		err = os.RemoveAll(extractPath)
+		if err != nil {
+			fs.Logf(nil, "No previous downloads to remove")
+		}
+		fs.Logf(nil, "Unzipping webgui binary")
+
+		err = unzip(zipPath, extractPath)
+		if err != nil {
+			return err
+		}
+
+		err = os.RemoveAll(zipPath)
+		if err != nil {
+			fs.Logf(nil, "Downloaded ZIP cannot be deleted")
+		}
+
+		err = ioutil.WriteFile(tagPath, []byte(tag), 0644)
+		if err != nil {
+			fs.Infof(nil, "Cannot write tag file. You may be required to redownload the binary next time.")
+		}
+	} else {
+		fs.Logf(nil, "Web GUI exists. Update skipped.")
+	}
+
+	return nil
+}
+
+// downloadFile is a helper function to download a file from url to the filepath
+func downloadFile(filepath string, url string) error {
+
+	// Get the data
+	resp, err := http.Get(url)
+	if err != nil {
+		return err
+	}
+	defer fs.CheckClose(resp.Body, &err)
+
+	// Create the file
+	out, err := os.Create(filepath)
+	if err != nil {
+		return err
+	}
+	defer fs.CheckClose(out, &err)
+
+	// Write the body to file
+	_, err = io.Copy(out, resp.Body)
+	return err
+}
+
+// unzip is a helper function to unzip a file specified in src to path dest
+func unzip(src, dest string) (err error) {
+	dest = filepath.Clean(dest) + string(os.PathSeparator)
+
+	r, err := zip.OpenReader(src)
+	if err != nil {
+		return err
+	}
+	defer fs.CheckClose(r, &err)
+
+	if err := os.MkdirAll(dest, 0755); err != nil {
+		return err
+	}
+
+	// Closure to address file descriptors issue with all the deferred .Close() methods
+	extractAndWriteFile := func(f *zip.File) error {
+		path := filepath.Join(dest, f.Name)
+		// Check for Zip Slip: https://github.com/rclone/rclone/issues/3529
+		if !strings.HasPrefix(path, dest) {
+			return fmt.Errorf("%s: illegal file path", path)
+		}
+
+		rc, err := f.Open()
+		if err != nil {
+			return err
+		}
+		defer fs.CheckClose(rc, &err)
+
+		if f.FileInfo().IsDir() {
+			if err := os.MkdirAll(path, 0755); err != nil {
+				return err
+			}
+		} else {
+			if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+				return err
+			}
+			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+			if err != nil {
+				return err
+			}
+			defer fs.CheckClose(f, &err)
+
+			_, err = io.Copy(f, rc)
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+
+	for _, f := range r.File {
+		err := extractAndWriteFile(f)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func exists(path string) (existance bool, stat os.FileInfo, err error) {
+	stat, err = os.Stat(path)
+	if err == nil {
+		return true, stat, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil, nil
+	}
+	return false, stat, err
+}
+
+// gitHubRequest Maps the GitHub API request to structure
+type gitHubRequest struct {
+	URL string `json:"url"`
+
+	Prerelease  bool      `json:"prerelease"`
+	CreatedAt   time.Time `json:"created_at"`
+	PublishedAt time.Time `json:"published_at"`
+	TagName     string    `json:"tag_name"`
+	Assets      []struct {
+		URL                string    `json:"url"`
+		ID                 int       `json:"id"`
+		NodeID             string    `json:"node_id"`
+		Name               string    `json:"name"`
+		Label              string    `json:"label"`
+		ContentType        string    `json:"content_type"`
+		State              string    `json:"state"`
+		Size               int       `json:"size"`
+		DownloadCount      int       `json:"download_count"`
+		CreatedAt          time.Time `json:"created_at"`
+		UpdatedAt          time.Time `json:"updated_at"`
+		BrowserDownloadURL string    `json:"browser_download_url"`
+	} `json:"assets"`
+	TarballURL string `json:"tarball_url"`
+	ZipballURL string `json:"zipball_url"`
+	Body       string `json:"body"`
+}