From 20769d96efd841f49b0374b723569854f4f01cf8 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Fri, 25 Sep 2020 12:22:51 +0200 Subject: [PATCH 01/11] Update angularjs dependencies from 1.7 to 1.8 --- webapp/bower.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/bower.json b/webapp/bower.json index 4f568404..1f59c229 100644 --- a/webapp/bower.json +++ b/webapp/bower.json @@ -15,7 +15,7 @@ "tests" ], "dependencies": { - "angular": "~1.7.2", + "angular": "~1.8.0", "bootstrap": "~3.3.5", "bootstrap-flat": "~3.3.4", "angular-bootstrap": "~2.3.2", @@ -24,8 +24,8 @@ "filesize": "~3.3.0", "showdown": "~0.3.4", "ng-file-upload": "~12.2.13", - "angular-route": "~1.7.2", - "angular-sanitize": "~1.7.2", + "angular-route": "~1.8.0", + "angular-sanitize": "~1.8.0", "angular-markdown-directive": "~0.3.1" } } From 1da9bc67cdc0f0bbdb920facf2b983b158165389 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Fri, 25 Sep 2020 13:28:20 +0200 Subject: [PATCH 02/11] Add --info to cli client to display server configuration --- client/config.go | 6 - client/plik.go | 361 +++++------------------------------ client/test.sh | 22 +++ client/update.go | 232 ++++++++++++++++++++++ plik/client.go | 29 +++ plik/client_test.go | 16 +- plik/internal.go | 2 +- server/common/config.go | 78 +++++++- server/common/config_test.go | 14 ++ server/common/utils.go | 53 +++++ server/common/utils_test.go | 23 +++ server/plikd.cfg | 2 +- server/server/server.go | 8 + 13 files changed, 518 insertions(+), 328 deletions(-) create mode 100644 client/update.go diff --git a/client/config.go b/client/config.go index 46020994..7beac520 100644 --- a/client/config.go +++ b/client/config.go @@ -187,12 +187,6 @@ func LoadConfig() (config *CliConfig, err error) { // UnmarshalArgs turns command line arguments into upload settings // Command line arguments override config file settings func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err error) { - - // Handle flags - if arguments["--version"].(bool) { - fmt.Printf("Plik client %s\n", common.GetBuildInfo()) - os.Exit(0) - } if arguments["--debug"].(bool) { config.Debug = true } diff --git a/client/plik.go b/client/plik.go index 055000b2..d6483534 100644 --- a/client/plik.go +++ b/client/plik.go @@ -2,20 +2,15 @@ package main import ( "bufio" - "encoding/json" "fmt" "io" "io/ioutil" "math/rand" - "net/http" - "net/url" "os" - "path/filepath" "runtime" "time" "github.com/docopt/docopt-go" - "github.com/kardianos/osext" "github.com/olekukonko/ts" "github.com/root-gg/utils" @@ -30,7 +25,6 @@ var arguments map[string]interface{} var config *CliConfig var archiveBackend archive.Backend var cryptoBackend crypto.Backend -var client *plik.Client var err error @@ -47,9 +41,6 @@ Usage: plik [options] [FILE] ... Options: - -h --help Show this help - -d --debug Enable debug mode - -q --quiet Enable quiet mode -o, --oneshot Enable OneShot ( Each file will be deleted on first download ) -r, --removable Enable Removable upload ( Each file can be deleted by anyone at anymoment ) -S, --stream Enable Streaming ( It will block until remote user starts downloading ) @@ -73,10 +64,19 @@ Options: --recipient RECIPIENT [pgp] Set recipient for pgp backend ( example : --recipient Bob ) --secure-options OPTIONS [openssl|pgp] Additional command line options --update Update client + -q --quiet Enable quiet mode + -d --debug Enable debug mode -v --version Show client version + -i --info Show client and server information + -h --help Show this help ` // Parse command line arguments - arguments, _ = docopt.Parse(usage, nil, true, "", false) + arguments, _ = docopt.ParseDoc(usage) + + if arguments["--version"].(bool) { + fmt.Printf("Plik client %s\n", common.GetBuildInfo()) + os.Exit(0) + } // Load config config, err = LoadConfig() @@ -99,13 +99,18 @@ Options: utils.Dump(config) } - client = plik.NewClient(config.URL) + client := plik.NewClient(config.URL) client.Debug = config.Debug client.ClientName = "plik_cli" - // Check client version + // Display info + if arguments["--info"].(bool) { + info(client) + } + + // Update updateFlag := arguments["--update"].(bool) - err = updateClient(updateFlag) + err = update(client, updateFlag) if err == nil { if updateFlag { os.Exit(0) @@ -302,6 +307,31 @@ Options: } } +func info(client *plik.Client) { + fmt.Printf("Plik client version : %s\n\n", common.GetBuildInfo()) + + fmt.Printf("Plik server url : %s\n", config.URL) + + serverBuildInfo, err := client.GetServerVersion() + if err != nil { + fmt.Printf("Plik server unreachable %s\n", err) + return + } + + fmt.Printf("Plik server version : %s\n", serverBuildInfo) + + serverConfig, err := client.GetServerConfig() + if err != nil { + fmt.Printf("Plik server unreachable %s\n", err) + return + } + + fmt.Printf("\nPlik server configuration :\n") + fmt.Printf(serverConfig.String()) + + os.Exit(0) +} + func getFileCommand(file *plik.File) (command string, err error) { // Step one - Downloading file switch config.DownloadBinary { @@ -338,311 +368,6 @@ func getFileCommand(file *plik.File) (command string, err error) { return } -func updateClient(updateFlag bool) (err error) { - // Do not check for update if AutoUpdate is not enabled - if !updateFlag && !config.AutoUpdate { - return - } - - // Do not update when quiet mode is enabled - if !updateFlag && config.Quiet { - return - } - - // Get client MD5SUM - path, err := osext.Executable() - if err != nil { - return - } - currentMD5, err := utils.FileMd5sum(path) - if err != nil { - return - } - - // Check server version - currentVersion := common.GetBuildInfo().Version - - var newVersion string - var downloadURL string - var newMD5 string - var buildInfo *common.BuildInfo - - var URL *url.URL - URL, err = url.Parse(config.URL + "/version") - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - var req *http.Request - req, err = http.NewRequest("GET", URL.String(), nil) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - resp, err := client.MakeRequest(req) - if resp == nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - defer resp.Body.Close() - - if resp.StatusCode == 200 { - // >=1.1 use BuildInfo from /version - - var body []byte - body, err = ioutil.ReadAll(resp.Body) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - // Parse json BuildInfo object - buildInfo = new(common.BuildInfo) - err = json.Unmarshal(body, buildInfo) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - newVersion = buildInfo.Version - for _, client := range buildInfo.Clients { - if client.OS == runtime.GOOS && client.ARCH == runtime.GOARCH { - newMD5 = client.Md5 - downloadURL = config.URL + "/" + client.Path - break - } - } - - if newMD5 == "" || downloadURL == "" { - err = fmt.Errorf("Server does not offer a %s-%s client", runtime.GOOS, runtime.GOARCH) - return - } - } else if resp.StatusCode == 404 { - // <1.1 fallback on MD5SUM file - - baseURL := config.URL + "/clients/" + runtime.GOOS + "-" + runtime.GOARCH - var URL *url.URL - URL, err = url.Parse(baseURL + "/MD5SUM") - if err != nil { - return - } - var req *http.Request - req, err = http.NewRequest("GET", URL.String(), nil) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - resp, err = client.MakeRequest(req) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - err = fmt.Errorf("Unable to get server version : %s", resp.Status) - return - } - - var body []byte - body, err = ioutil.ReadAll(resp.Body) - if err != nil { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - newMD5 = utils.Chomp(string(body)) - - binary := "plik" - if runtime.GOOS == "windows" { - binary += ".exe" - } - downloadURL = baseURL + "/" + binary - } else { - err = fmt.Errorf("Unable to get server version : %s", err) - return - } - - // Check if the client is up to date - if currentMD5 == newMD5 { - if updateFlag { - if newVersion != "" { - printf("Plik client %s is up to date\n", newVersion) - } else { - printf("Plik client is up to date\n") - } - os.Exit(0) - } - return - } - - // Ask for permission - if newVersion != "" { - fmt.Printf("Update Plik client from %s to %s ? [Y/n] ", currentVersion, newVersion) - } else { - fmt.Printf("Update Plik client to match server version ? [Y/n] ") - } - if ok, _ := common.AskConfirmation(true); !ok { - if updateFlag { - os.Exit(0) - } - return - } - - // Display release notes - if buildInfo != nil && buildInfo.Releases != nil { - - // Find current release - currentReleaseIndex := -1 - for i, release := range buildInfo.Releases { - if release.Name == currentVersion { - currentReleaseIndex = i - } - } - - // Find new release - newReleaseIndex := -1 - for i, release := range buildInfo.Releases { - if release.Name == newVersion { - newReleaseIndex = i - } - } - - // Find releases between current and new version - var releases []*common.Release - if currentReleaseIndex > 0 && newReleaseIndex > 0 && currentReleaseIndex < newReleaseIndex { - releases = buildInfo.Releases[currentReleaseIndex+1 : newReleaseIndex+1] - } - - for _, release := range releases { - // Get release notes from server - var URL *url.URL - URL, err = url.Parse(config.URL + "/changelog/" + release.Name) - if err != nil { - continue - } - var req *http.Request - req, err = http.NewRequest("GET", URL.String(), nil) - if err != nil { - err = fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) - continue - } - - resp, err = client.MakeRequest(req) - if err != nil { - err = fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) - continue - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - err = fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) - continue - } - - var body []byte - body, err = ioutil.ReadAll(resp.Body) - if err != nil { - err = fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) - continue - } - - // Ask to display the release notes - fmt.Printf("Do you want to browse the release notes of version %s ? [Y/n] ", release.Name) - if ok, _ := common.AskConfirmation(true); !ok { - continue - } - - // Display the release notes - releaseDate := time.Unix(release.Date, 0).Format("Mon Jan 2 2006 15:04") - fmt.Printf("Plik %s has been released %s\n\n", release.Name, releaseDate) - fmt.Println(string(body)) - - // Let user review the last release notes and ask to confirm update - if release.Name == newVersion { - fmt.Printf("\nUpdate Plik client from %s to %s ? [Y/n] ", currentVersion, newVersion) - if ok, _ := common.AskConfirmation(true); !ok { - if updateFlag { - os.Exit(0) - } - return - } - break - } - } - } - - // Download new client - tmpPath := filepath.Dir(path) + "/" + "." + filepath.Base(path) + ".tmp" - tmpFile, err := os.OpenFile(tmpPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) - if err != nil { - return - } - defer func() { - tmpFile.Close() - os.Remove(tmpPath) - }() - - URL, err = url.Parse(downloadURL) - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - req, err = http.NewRequest("GET", URL.String(), nil) - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - resp, err = client.MakeRequest(req) - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - if resp.StatusCode != 200 { - err = fmt.Errorf("Unable to download client : %s", resp.Status) - return - } - defer resp.Body.Close() - _, err = io.Copy(tmpFile, resp.Body) - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - err = tmpFile.Close() - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - - // Check download integrity - downloadMD5, err := utils.FileMd5sum(tmpPath) - if err != nil { - err = fmt.Errorf("Unable to download client : %s", err) - return - } - if downloadMD5 != newMD5 { - err = fmt.Errorf("Unable to download client : md5sum %s does not match %s", downloadMD5, newMD5) - return - } - - // Replace old client - err = os.Rename(tmpPath, path) - if err != nil { - err = fmt.Errorf("Unable to replace client : %s", err) - return - } - - if newVersion != "" { - fmt.Printf("Plik client successfully updated to %s\n", newVersion) - } else { - fmt.Printf("Plik client successfully updated\n") - } - - return -} - func printf(format string, args ...interface{}) { if !config.Quiet { fmt.Printf(format, args...) diff --git a/client/test.sh b/client/test.sh index 6354a8ef..64a9bad0 100755 --- a/client/test.sh +++ b/client/test.sh @@ -198,6 +198,28 @@ echo "OK" #--------------------------------------------- +#--------------------------------------------- + +echo -n " - info : " + +before +$CLIENT --info >$CLIENT_LOG 2>&1 +grep "Plik client version :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server url :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server version :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server configuration :" $CLIENT_LOG >/dev/null 2>/dev/null + +before +$CLIENT -i >$CLIENT_LOG 2>&1 +grep "Plik client version :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server url :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server version :" $CLIENT_LOG >/dev/null 2>/dev/null +grep "Plik server configuration :" $CLIENT_LOG >/dev/null 2>/dev/null + +echo "OK" + +#--------------------------------------------- + echo -n " - debug : " before diff --git a/client/update.go b/client/update.go new file mode 100644 index 00000000..df688ac8 --- /dev/null +++ b/client/update.go @@ -0,0 +1,232 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + "runtime" + "time" + + "github.com/kardianos/osext" + + "github.com/root-gg/plik/plik" + "github.com/root-gg/plik/server/common" + "github.com/root-gg/utils" +) + +func update(client *plik.Client, updateFlag bool) (err error) { + // Do not check for update if AutoUpdate is not enabled + if !updateFlag && !config.AutoUpdate { + return + } + + // Do not update when quiet mode is enabled + if !updateFlag && config.Quiet { + return + } + + // Get client MD5SUM + path, err := osext.Executable() + if err != nil { + return + } + currentMD5, err := utils.FileMd5sum(path) + if err != nil { + return + } + + // Check server version + currentVersion := common.GetBuildInfo().Version + + var newVersion string + var downloadURL string + var newMD5 string + + buildInfo, err := client.GetServerVersion() + if err != nil { + return fmt.Errorf("Unable to get server version : %s", err) + } + + newVersion = buildInfo.Version + for _, client := range buildInfo.Clients { + if client.OS == runtime.GOOS && client.ARCH == runtime.GOARCH { + newMD5 = client.Md5 + downloadURL = config.URL + "/" + client.Path + break + } + } + + if newMD5 == "" || downloadURL == "" { + return fmt.Errorf("Server does not offer a %s-%s client", runtime.GOOS, runtime.GOARCH) + + } + + // Check if the client is up to date + if currentMD5 == newMD5 { + if updateFlag { + if newVersion != "" { + printf("Plik client %s is up to date\n", newVersion) + } else { + printf("Plik client is up to date\n") + } + os.Exit(0) + } + return + } + + // Ask for permission + if newVersion != "" { + fmt.Printf("Update Plik client from %s to %s ? [Y/n] ", currentVersion, newVersion) + } else { + fmt.Printf("Update Plik client to match server version ? [Y/n] ") + } + if ok, _ := common.AskConfirmation(true); !ok { + if updateFlag { + os.Exit(0) + } + return + } + + // Display release notes + if buildInfo != nil && buildInfo.Releases != nil { + + // Find current release + currentReleaseIndex := -1 + for i, release := range buildInfo.Releases { + if release.Name == currentVersion { + currentReleaseIndex = i + } + } + + // Find new release + newReleaseIndex := -1 + for i, release := range buildInfo.Releases { + if release.Name == newVersion { + newReleaseIndex = i + } + } + + // Find releases between current and new version + var releases []*common.Release + if currentReleaseIndex > 0 && newReleaseIndex > 0 && currentReleaseIndex < newReleaseIndex { + releases = buildInfo.Releases[currentReleaseIndex+1 : newReleaseIndex+1] + } + + for _, release := range releases { + // Get release notes from server + var URL *url.URL + URL, err = url.Parse(config.URL + "/changelog/" + release.Name) + if err != nil { + return err + } + var req *http.Request + req, err = http.NewRequest("GET", URL.String(), nil) + if err != nil { + return fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) + } + + resp, err := client.MakeRequest(req) + if err != nil { + return fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != 200 { + return fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) + } + + var body []byte + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("Unable to get release notes for version %s : %s", release.Name, err) + } + + // Ask to display the release notes + fmt.Printf("Do you want to browse the release notes of version %s ? [Y/n] ", release.Name) + if ok, _ := common.AskConfirmation(true); !ok { + continue + } + + // Display the release notes + releaseDate := time.Unix(release.Date, 0).Format("Mon Jan 2 2006 15:04") + fmt.Printf("Plik %s has been released %s\n\n", release.Name, releaseDate) + fmt.Println(string(body)) + + // Let user review the last release notes and ask to confirm update + if release.Name == newVersion { + fmt.Printf("\nUpdate Plik client from %s to %s ? [Y/n] ", currentVersion, newVersion) + if ok, _ := common.AskConfirmation(true); !ok { + if updateFlag { + os.Exit(0) + } + return nil + } + break + } + } + } + + // Download new client + tmpPath := filepath.Dir(path) + "/" + "." + filepath.Base(path) + ".tmp" + tmpFile, err := os.OpenFile(tmpPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) + if err != nil { + return + } + defer func() { + tmpFile.Close() + os.Remove(tmpPath) + }() + + URL, err := url.Parse(downloadURL) + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + + } + req, err := http.NewRequest("GET", URL.String(), nil) + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + } + resp, err := client.MakeRequest(req) + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + } + if resp.StatusCode != 200 { + return fmt.Errorf("Unable to download client : %s", resp.Status) + } + defer resp.Body.Close() + _, err = io.Copy(tmpFile, resp.Body) + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + } + err = tmpFile.Close() + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + } + + // Check download integrity + downloadMD5, err := utils.FileMd5sum(tmpPath) + if err != nil { + return fmt.Errorf("Unable to download client : %s", err) + } + if downloadMD5 != newMD5 { + return fmt.Errorf("Unable to download client : md5sum %s does not match %s", downloadMD5, newMD5) + } + + // Replace old client + err = os.Rename(tmpPath, path) + if err != nil { + return fmt.Errorf("Unable to replace client : %s", err) + } + + if newVersion != "" { + fmt.Printf("Plik client successfully updated to %s\n", newVersion) + } else { + fmt.Printf("Plik client successfully updated\n") + } + + return +} diff --git a/plik/client.go b/plik/client.go index fd426f5c..283207fc 100644 --- a/plik/client.go +++ b/plik/client.go @@ -116,6 +116,35 @@ func (c *Client) GetServerVersion() (bi *common.BuildInfo, err error) { return bi, nil } +// GetServerConfig return the remote server configuration +func (c *Client) GetServerConfig() (config *common.Configuration, err error) { + var req *http.Request + req, err = http.NewRequest("GET", c.URL+"/config", nil) + if err != nil { + return nil, err + } + + resp, err := c.MakeRequest(req) + if err != nil { + return nil, err + } + + defer func() { _ = resp.Body.Close() }() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + // Parse json response + config = &common.Configuration{} + err = json.Unmarshal(body, config) + if err != nil { + return nil, err + } + + return config, nil +} + // GetUpload fetch upload metadata from the server func (c *Client) GetUpload(id string) (upload *Upload, err error) { return c.GetUploadProtectedByPassword(id, c.Login, c.Password) diff --git a/plik/client_test.go b/plik/client_test.go index 928e85f6..d53af3d9 100644 --- a/plik/client_test.go +++ b/plik/client_test.go @@ -21,7 +21,21 @@ func TestGetServerVersion(t *testing.T) { bi, err := pc.GetServerVersion() require.NoError(t, err, "unable to get plik server version") - require.Equal(t, common.GetBuildInfo().Version, bi.Version, "unable to get plik server version") + require.Equal(t, common.GetBuildInfo().Version, bi.Version, "invalid plik server version") +} + +func TestGetServerConfig(t *testing.T) { + ps, pc := newPlikServerAndClient() + defer shutdown(ps) + + ps.GetConfig().DownloadDomain = "test test test" + err := start(ps) + require.NoError(t, err, "unable to start plik server") + + config, err := pc.GetServerConfig() + require.NoError(t, err, "unable to get plik server config") + require.NotNil(t, config, "unable to get plik server config") + require.Equal(t, ps.GetConfig().DownloadDomain, config.DownloadDomain, "invalid config value") } func TestDefaultUploadParams(t *testing.T) { diff --git a/plik/internal.go b/plik/internal.go index 7ae89fea..d9178df6 100644 --- a/plik/internal.go +++ b/plik/internal.go @@ -315,7 +315,7 @@ func (c *Client) MakeRequest(req *http.Request) (resp *http.Response, err error) // Make request resp, err = c.HTTPClient.Do(req) if err != nil { - return + return nil, err } if resp.StatusCode != 200 { diff --git a/server/common/config.go b/server/common/config.go index d6d0caa3..a1faa11e 100644 --- a/server/common/config.go +++ b/server/common/config.go @@ -5,8 +5,11 @@ import ( "net" "net/url" "strings" + "time" "github.com/BurntSushi/toml" + "github.com/dustin/go-humanize" + "github.com/root-gg/logger" ) @@ -71,7 +74,7 @@ func NewConfiguration() (config *Configuration) { config.ListenPort = 8080 config.EnhancedWebSecurity = true - config.MaxFileSize = 10737418240 // 10GB + config.MaxFileSize = 10000000000 // 10GB config.MaxFilePerUpload = 1000 config.DefaultTTL = 2592000 // 30 days @@ -157,6 +160,10 @@ func (config *Configuration) Initialize() (err error) { } } + if config.DefaultTTL > config.MaxTTL { + return fmt.Errorf("DefaultTTL should not be more than MaxTTL") + } + return nil } @@ -229,3 +236,72 @@ func (config *Configuration) GetServerURL() *url.URL { return URL } + +func (config *Configuration) String() string { + str := "" + if config.DownloadDomain != "" { + str += fmt.Sprintf("Download domain : %s\n", config.DownloadDomain) + } + + str += fmt.Sprintf("Maximum file size : %s\n", humanize.Bytes(uint64(config.MaxFileSize))) + str += fmt.Sprintf("Maximum files per upload : %d\n", config.MaxFilePerUpload) + + if config.DefaultTTL > 0 { + str += fmt.Sprintf("Default upload TTL : %s\n", HumanDuration(time.Duration(config.DefaultTTL)*time.Second)) + } else { + str += fmt.Sprintf("Default upload TTL : unlimited\n") + } + + if config.MaxTTL > 0 { + str += fmt.Sprintf("Maximum upload TTL : %s\n", HumanDuration(time.Duration(config.MaxTTL)*time.Second)) + } else { + str += fmt.Sprintf("Maximum upload TTL : unlimited\n") + } + + if config.OneShot { + str += fmt.Sprintf("One shot upload : enabled\n") + } else { + str += fmt.Sprintf("One shot upload : disabled\n") + } + + if config.Removable { + str += fmt.Sprintf("Removable upload : enabled\n") + } else { + str += fmt.Sprintf("Removable upload : disabled\n") + } + + if config.Stream { + str += fmt.Sprintf("Streaming upload : enabled\n") + } else { + str += fmt.Sprintf("Streaming upload : disabled\n") + } + + if config.ProtectedByPassword { + str += fmt.Sprintf("Upload password : enabled\n") + } else { + str += fmt.Sprintf("Upload password : disabled\n") + } + + if config.Authentication { + str += fmt.Sprintf("Authentication : enabled\n") + + if config.GoogleAuthentication { + str += fmt.Sprintf("Google authentication : enabled\n") + } else { + str += fmt.Sprintf("Google authentication : disabled\n") + } + + if config.OvhAuthentication { + str += fmt.Sprintf("OVH authentication : enabled\n") + if config.OvhAPIEndpoint != "" { + str += fmt.Sprintf("OVH API endpoint : %s\n", config.OvhAPIEndpoint) + } + } else { + str += fmt.Sprintf("OVH authentication : disabled\n") + } + } else { + str += fmt.Sprintf("Authentication : disabled\n") + } + + return str +} diff --git a/server/common/config_test.go b/server/common/config_test.go index 3faa42ce..fd5d5ea4 100644 --- a/server/common/config_test.go +++ b/server/common/config_test.go @@ -85,6 +85,15 @@ func TestInitializeConfigInvalidDownloadDomain(t *testing.T) { require.Error(t, err, "able to initialize invalid config") } +func TestInitializeInvalidDefaultTTL(t *testing.T) { + config := NewConfiguration() + config.DefaultTTL = 10 * 86400 + config.MaxTTL = 1 * 86400 + + err := config.Initialize() + require.Error(t, err, "able to initialize invalid config") +} + func TestDisableAutoClean(t *testing.T) { config := NewConfiguration() require.True(t, config.IsAutoClean(), "invalid auto clean status") @@ -102,3 +111,8 @@ func TestGetServerUrl(t *testing.T) { config.Path = "/root" require.Equal(t, "https://1.1.1.1:8080/root", config.GetServerURL().String(), "invalid server url") } + +func TestString(t *testing.T) { + config := NewConfiguration() + require.NotEmpty(t, config.String()) +} diff --git a/server/common/utils.go b/server/common/utils.go index 768ff8aa..3f30bfc6 100644 --- a/server/common/utils.go +++ b/server/common/utils.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/root-gg/utils" ) @@ -93,3 +94,55 @@ func AskConfirmation(defaultValue bool) (bool, error) { return defaultValue, nil } } + +// HumanDuration displays duration with days and years +func HumanDuration(d time.Duration) string { + var minus bool + if d < 0 { + minus = true + d = -d + } + + years := d / (365 * 24 * time.Hour) + d = d % (365 * 24 * time.Hour) + days := d / (24 * time.Hour) + d = d % (24 * time.Hour) + hours := d / (time.Hour) + d = d % (time.Hour) + minutes := d / (time.Minute) + d = d % (time.Minute) + seconds := d / (time.Second) + d = d % (time.Second) + + str := "" + + if minus { + str += "-" + } + + if years > 0 { + str += fmt.Sprintf("%dy", years) + } + + if days > 0 { + str += fmt.Sprintf("%dd", days) + } + + if hours > 0 { + str += fmt.Sprintf("%dh", hours) + } + + if minutes > 0 { + str += fmt.Sprintf("%dm", minutes) + } + + if seconds > 0 { + str += fmt.Sprintf("%ds", seconds) + } + + if str == "" || d > 0 { + str += fmt.Sprintf("%s", d) + } + + return str +} diff --git a/server/common/utils_test.go b/server/common/utils_test.go index 227f77ec..1d594ddd 100644 --- a/server/common/utils_test.go +++ b/server/common/utils_test.go @@ -9,6 +9,7 @@ import ( "net/http" "net/http/httptest" "testing" + "time" "github.com/stretchr/testify/require" ) @@ -96,3 +97,25 @@ func TestWriteJSONResponse(t *testing.T) { require.Equal(t, obj.Foo, obj2.Foo) } + +func TestHumanDuration(t *testing.T) { + require.Equal(t, "0s", HumanDuration(time.Duration(0))) + require.Equal(t, "10ms", HumanDuration(10*time.Millisecond)) + require.Equal(t, "1s10ms", HumanDuration(time.Second+10*time.Millisecond)) + require.Equal(t, "30s", HumanDuration(30*time.Second)) + require.Equal(t, "30m", HumanDuration(30*time.Minute)) + require.Equal(t, "30m3s", HumanDuration(30*time.Minute+3*time.Second)) + require.Equal(t, "1h", HumanDuration(time.Hour)) + require.Equal(t, "1h1s", HumanDuration(time.Hour+time.Second)) + require.Equal(t, "1h1m", HumanDuration(time.Hour+time.Minute)) + require.Equal(t, "1h1m1s", HumanDuration(time.Hour+time.Minute+time.Second)) + require.Equal(t, "1d", HumanDuration(24*time.Hour)) + require.Equal(t, "1d1m1s", HumanDuration(24*time.Hour+time.Minute+time.Second)) + require.Equal(t, "1d1h1m1s", HumanDuration(24*time.Hour+time.Hour+time.Minute+time.Second)) + require.Equal(t, "30d", HumanDuration(30*24*time.Hour)) + require.Equal(t, "1y", HumanDuration(365*24*time.Hour)) + require.Equal(t, "1y1d", HumanDuration(366*24*time.Hour)) + require.Equal(t, "1y1d1s", HumanDuration(366*24*time.Hour+time.Second)) + require.Equal(t, "1y1d1h1m1s", HumanDuration(366*24*time.Hour+3661*time.Second)) + require.Equal(t, "-10s", HumanDuration(-10*time.Second)) +} diff --git a/server/plikd.cfg b/server/plikd.cfg index 98a64b02..4df043fd 100644 --- a/server/plikd.cfg +++ b/server/plikd.cfg @@ -9,7 +9,7 @@ ListenPort = 8080 # Port the HTTP server will listen on ListenAddress = "0.0.0.0" # Address the HTTP server will bind on Path = "" # HTTP root path -MaxFileSize = 10737418240 # 10GB +MaxFileSize = 10000000000 # 10GB MaxFilePerUpload = 1000 DefaultTTL = 2592000 # 30 days diff --git a/server/server/server.go b/server/server/server.go index 6b1e2886..3fa272bd 100644 --- a/server/server/server.go +++ b/server/server/server.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strconv" + "strings" "sync" "time" @@ -82,6 +83,13 @@ func (ps *PlikServer) start() (err error) { log.Infof("Starting plikd server v" + common.GetBuildInfo().Version) + log.Debug("Configuration :") + for _, line := range strings.Split(ps.config.String(), "\n") { + if line != "" { + log.Debug(line) + } + } + // Initialize backends err = ps.initializeMetadataBackend() if err != nil { From c53f989edb6f877ed4b21edbbc3ed85aac2232df Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Fri, 25 Sep 2020 20:53:49 +0200 Subject: [PATCH 03/11] Fix common.AskConfirmation handling of no input --- client/config.go | 10 ++++++++-- client/update.go | 17 +++++++++++++---- server/cmd/file.go | 22 +++++++++++++++++----- server/cmd/user.go | 6 +++++- server/common/utils.go | 3 +++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/client/config.go b/client/config.go index 7beac520..495b6f31 100644 --- a/client/config.go +++ b/client/config.go @@ -152,7 +152,10 @@ func LoadConfig() (config *CliConfig, err error) { fmt.Printf("We have been redirected to : %s\n", finalURL) fmt.Printf("Replace current url (%s) with the new one ? [Y/n] ", config.URL) - ok, _ := common.AskConfirmation(true) + ok, err := common.AskConfirmation(true) + if err != nil { + return nil, fmt.Errorf("Unable to ask for confirmation : %s", err) + } if ok { config.URL = strings.TrimSuffix(finalURL, "/") } @@ -160,7 +163,10 @@ func LoadConfig() (config *CliConfig, err error) { // Enable client updates ? fmt.Println("Do you want to enable client auto update ? [Y/n] ") - ok, _ := common.AskConfirmation(true) + ok, err := common.AskConfirmation(true) + if err != nil { + return nil, fmt.Errorf("Unable to ask for confirmation : %s", err) + } if ok { config.AutoUpdate = true } diff --git a/client/update.go b/client/update.go index df688ac8..e09088a4 100644 --- a/client/update.go +++ b/client/update.go @@ -84,11 +84,14 @@ func update(client *plik.Client, updateFlag bool) (err error) { } else { fmt.Printf("Update Plik client to match server version ? [Y/n] ") } - if ok, _ := common.AskConfirmation(true); !ok { + if ok, err := common.AskConfirmation(true); err != nil || !ok { + if err != nil { + return fmt.Errorf("Unable to ask for confirmation : %s", err) + } if updateFlag { os.Exit(0) } - return + return nil } // Display release notes @@ -147,7 +150,10 @@ func update(client *plik.Client, updateFlag bool) (err error) { // Ask to display the release notes fmt.Printf("Do you want to browse the release notes of version %s ? [Y/n] ", release.Name) - if ok, _ := common.AskConfirmation(true); !ok { + if ok, err := common.AskConfirmation(true); err != nil || !ok { + if err != nil { + return fmt.Errorf("Unable to ask for confirmation : %s", err) + } continue } @@ -159,7 +165,10 @@ func update(client *plik.Client, updateFlag bool) (err error) { // Let user review the last release notes and ask to confirm update if release.Name == newVersion { fmt.Printf("\nUpdate Plik client from %s to %s ? [Y/n] ", currentVersion, newVersion) - if ok, _ := common.AskConfirmation(true); !ok { + if ok, err := common.AskConfirmation(true); err != nil || !ok { + if err != nil { + return fmt.Errorf("Unable to ask for confirmation : %s", err) + } if updateFlag { os.Exit(0) } diff --git a/server/cmd/file.go b/server/cmd/file.go index badd9ab7..c7a7b697 100644 --- a/server/cmd/file.go +++ b/server/cmd/file.go @@ -114,7 +114,11 @@ func deleteFiles(cmd *cobra.Command, args []string) { // Ask confirmation fmt.Printf("Do you really want to remove this file %s %s ? [y/N]\n", file.ID, file.Name) - ok, _ := common.AskConfirmation(false) + ok, err := common.AskConfirmation(false) + if err != nil { + fmt.Printf("Unable to ask for confirmation : %s", err) + os.Exit(1) + } if !ok { os.Exit(0) } @@ -128,12 +132,16 @@ func deleteFiles(cmd *cobra.Command, args []string) { // Ask confirmation fmt.Printf("Do you really want to remove this upload %s ? [y/N]\n", fileParams.uploadID) - ok, _ := common.AskConfirmation(false) + ok, err := common.AskConfirmation(false) + if err != nil { + fmt.Printf("Unable to ask for confirmation : %s", err) + os.Exit(1) + } if !ok { os.Exit(0) } - err := metadataBackend.DeleteUpload(fileParams.uploadID) + err = metadataBackend.DeleteUpload(fileParams.uploadID) if err != nil { fmt.Printf("Unable to get upload files : %s\n", err) os.Exit(1) @@ -142,7 +150,11 @@ func deleteFiles(cmd *cobra.Command, args []string) { // Ask confirmation fmt.Printf("Do you really want to remove ALL uploads ? [y/N]\n") - ok, _ := common.AskConfirmation(false) + ok, err := common.AskConfirmation(false) + if err != nil { + fmt.Printf("Unable to ask for confirmation : %s", err) + os.Exit(1) + } if !ok { os.Exit(0) } @@ -150,7 +162,7 @@ func deleteFiles(cmd *cobra.Command, args []string) { deleteUpload := func(upload *common.Upload) error { return metadataBackend.DeleteUpload(upload.ID) } - err := metadataBackend.ForEachUpload(deleteUpload) + err = metadataBackend.ForEachUpload(deleteUpload) if err != nil { fmt.Printf("Unable to delete uploads : %s\n", err) os.Exit(1) diff --git a/server/cmd/user.go b/server/cmd/user.go index 53759a8c..9f2c7c3d 100644 --- a/server/cmd/user.go +++ b/server/cmd/user.go @@ -279,7 +279,11 @@ func deleteUser(cmd *cobra.Command, args []string) { // Ask confirmation fmt.Printf("Do you really want to delete this user %s and all its uploads ? [y/N]\n", userID) - ok, _ := common.AskConfirmation(false) + ok, err := common.AskConfirmation(false) + if err != nil { + fmt.Printf("Unable to ask for confirmation : %s", err) + os.Exit(1) + } if !ok { os.Exit(0) } diff --git a/server/common/utils.go b/server/common/utils.go index 3f30bfc6..48de426a 100644 --- a/server/common/utils.go +++ b/server/common/utils.go @@ -83,6 +83,9 @@ func AskConfirmation(defaultValue bool) (bool, error) { var input string _, err := fmt.Scanln(&input) if err != nil { + if err.Error() == "unexpected newline" { + return defaultValue, nil + } return false, err } From 156baf98edaf2704cb571e0c6b21afc7f5b92aa6 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Fri, 25 Sep 2020 22:21:11 +0200 Subject: [PATCH 04/11] Pass build info using ldflags --- .dockerignore | 1 - .gitignore | 1 - Makefile | 34 ++++---- README.md | 1 - client/config.go | 71 ++++++++--------- client/plik.go | 19 +++-- go.mod | 1 + go.sum | 2 + server/common/config.go | 2 +- server/common/version.go | 127 +++++++++++++++++++++++++++++ server/common/version_test.go | 16 +++- server/gen_build_info.sh | 146 ++++++++++------------------------ server/handlers/misc.go | 7 +- server/handlers/misc_test.go | 31 ++++++++ server/plikd.cfg | 2 +- version/version.sh | 2 - 16 files changed, 287 insertions(+), 176 deletions(-) create mode 100644 server/common/version.go diff --git a/.dockerignore b/.dockerignore index dbe8b332..62b98d88 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,7 +4,6 @@ documentation release releases server/plikd -server/common/version.go testing webapp/node_modules webapp/bower_components diff --git a/.gitignore b/.gitignore index db2156f5..5e7b038f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ webapp/dist clients client/client servers -server/common/version.go release releases debs diff --git a/Makefile b/Makefile index c5ea2b17..5f3f3973 100644 --- a/Makefile +++ b/Makefile @@ -12,13 +12,15 @@ GOHOSTARCH=$(shell go env GOHOSTARCH) DEBROOT_SERVER=debs/server DEBROOT_CLIENT=debs/client -race_detector = GORACE="halt_on_error=1" go build -race +BUILD_INFO=$(shell server/gen_build_info.sh $(RELEASE_VERSION) base64) +BUILD_FLAG=-ldflags="-X github.com/root-gg/plik/server/common.buildInfoString=$(BUILD_INFO)" + +GO_BUILD=go build $(BUILD_FLAG) +GO_TEST=GORACE="halt_on_error=1" go test $(BUILD_FLAG) -race -cover -p 1 + ifdef ENABLE_RACE_DETECTOR - build = $(race_detector) -else - build = go build + GO_BUILD:=GORACE="halt_on_error=1" $(GO_BUILD) -race endif -test: build = $(race_detector) all: clean clean-frontend frontend clients server @@ -34,15 +36,15 @@ frontend: # Build plik server for the current architecture ### server: - @server/gen_build_info.sh $(RELEASE_VERSION) + @server/gen_build_info.sh $(RELEASE_VERSION) info @echo "Building Plik server" - @cd server && $(build) -o plikd ./ + @cd server && $(GO_BUILD) -o plikd ### # Build plik server for all architectures ### servers: frontend - @server/gen_build_info.sh $(RELEASE_VERSION) + @server/gen_build_info.sh $(RELEASE_VERSION) info @cd server && for target in $(RELEASE_TARGETS) ; do \ SERVER_DIR=../servers/$$target; \ SERVER_PATH=$$SERVER_DIR/plikd; \ @@ -52,23 +54,23 @@ servers: frontend if [ $$GOOS = "windows" ] ; then SERVER_PATH=$$SERVER_DIR/plikd.exe ; fi ; \ if [ -e $$SERVER_PATH ] ; then continue ; fi ; \ echo "Building Plik server for $$target to $$SERVER_PATH"; \ - $(build) -o $$SERVER_PATH ; \ + $(GO_BUILD) -o $$SERVER_PATH ; \ done ### # Build plik client for the current architecture ### client: - @server/gen_build_info.sh $(RELEASE_VERSION) + @server/gen_build_info.sh $(RELEASE_VERSION) info @echo "Building Plik client" - @cd client && $(build) -o plik ./ + @cd client && $(GO_BUILD) -o plik ./ ### # Build plik client for all architectures ### clients: - @server/gen_build_info.sh $(RELEASE_VERSION) + @server/gen_build_info.sh $(RELEASE_VERSION) info @cd client && for target in $(RELEASE_TARGETS) ; do \ CLIENT_DIR=../clients/$$target; \ CLIENT_PATH=$$CLIENT_DIR/plik; \ @@ -79,7 +81,7 @@ clients: if [ $$GOOS = "windows" ] ; then CLIENT_PATH=$$CLIENT_DIR/plik.exe ; fi ; \ if [ -e $$CLIENT_PATH ] ; then continue ; fi ; \ echo "Building Plik client for $$target to $$CLIENT_PATH"; \ - $(build) -o $$CLIENT_PATH ; \ + $(GO_BUILD) -o $$CLIENT_PATH ; \ md5sum $$CLIENT_PATH | awk '{print $$1}' > $$CLIENT_MD5; \ done @mkdir -p clients/bash && cp client/plik.sh clients/bash @@ -185,7 +187,7 @@ releases: release-template servers # Generate build info ### build-info: - @server/gen_build_info.sh $(RELEASE_VERSION) + @server/gen_build_info.sh $(RELEASE_VERSION) info ### # Run linters @@ -210,8 +212,7 @@ fmt: ### test: @if curl -s 127.0.0.1:8080 > /dev/null ; then echo "Plik server probably already running" && exit 1 ; fi - @server/gen_build_info.sh $(RELEASE_VERSION) - @GORACE="halt_on_error=1" go test -race -cover -p 1 ./... 2>&1 | grep -v "no test files"; test $${PIPESTATUS[0]} -eq 0 + @$(GO_TEST) ./... 2>&1 | grep -v "no test files"; test $${PIPESTATUS[0]} -eq 0 @echo "cli client integration tests :" && cd client && ./test.sh ### @@ -230,7 +231,6 @@ docker: # Remove server build files ### clean: - @rm -rf server/common/version.go @rm -rf server/plikd @rm -rf client/plik @rm -rf clients diff --git a/README.md b/README.md index 83770307..6fd73600 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ To compile plik from sources, you'll need golang and npm installed on your syste First, get the project and libs via go get : ```sh $ go get github.com/root-gg/plik/server -go/src/github.com/root-gg/plik/server/handlers/misc.go:51: undefined: common.GetBuildInfo <== ignore this warning $ cd $GOPATH/src/github.com/root-gg/plik/ ``` diff --git a/client/config.go b/client/config.go index 495b6f31..b18dce7d 100644 --- a/client/config.go +++ b/client/config.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/BurntSushi/toml" + "github.com/docopt/docopt-go" "github.com/mitchellh/go-homedir" "github.com/root-gg/plik/server/common" @@ -73,7 +74,7 @@ func LoadConfigFromFile(path string) (*CliConfig, error) { // LoadConfig creates a new default configuration and override it with .plikrc fike. // If .plikrc does not exist, ask domain, and create a new one in user HOMEDIR -func LoadConfig() (config *CliConfig, err error) { +func LoadConfig(opts docopt.Opts) (config *CliConfig, err error) { // Load config file from environment variable path := os.Getenv("PLIKRC") if path != "" { @@ -115,11 +116,9 @@ func LoadConfig() (config *CliConfig, err error) { config = NewUploadConfig() - // Check if quiet mode ( you'll have to pass --server flag ) - for _, arg := range os.Args[1:] { - if arg == "-q" || arg == "--quiet" { - return config, nil - } + // Bypass ~/.plikrc file creation if quiet mode and/or --server flag + if opts["--quiet"].(bool) || opts["--server"].(string) != "" { + return config, nil } // Config file not found. Create one. @@ -192,22 +191,22 @@ func LoadConfig() (config *CliConfig, err error) { // UnmarshalArgs turns command line arguments into upload settings // Command line arguments override config file settings -func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err error) { - if arguments["--debug"].(bool) { +func (config *CliConfig) UnmarshalArgs(opts docopt.Opts) (err error) { + if opts["--debug"].(bool) { config.Debug = true } - if arguments["--quiet"].(bool) { + if opts["--quiet"].(bool) { config.Quiet = true } // Plik server url - if arguments["--server"] != nil && arguments["--server"].(string) != "" { - config.URL = arguments["--server"].(string) + if opts["--server"] != nil && opts["--server"].(string) != "" { + config.URL = opts["--server"].(string) } // Paths - if _, ok := arguments["FILE"].([]string); ok { - config.filePaths = arguments["FILE"].([]string) + if _, ok := opts["FILE"].([]string); ok { + config.filePaths = opts["FILE"].([]string) } else { return fmt.Errorf("No files specified") } @@ -226,29 +225,29 @@ func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err er } // Override file name if specified - if arguments["--name"] != nil && arguments["--name"].(string) != "" { - config.filenameOverride = arguments["--name"].(string) + if opts["--name"] != nil && opts["--name"].(string) != "" { + config.filenameOverride = opts["--name"].(string) } // Upload options - if arguments["--oneshot"].(bool) { + if opts["--oneshot"].(bool) { config.OneShot = true } - if arguments["--removable"].(bool) { + if opts["--removable"].(bool) { config.Removable = true } - if arguments["--stream"].(bool) { + if opts["--stream"].(bool) { config.Stream = true } - if arguments["--comments"] != nil && arguments["--comments"].(string) != "" { - config.Comments = arguments["--comments"].(string) + if opts["--comments"] != nil && opts["--comments"].(string) != "" { + config.Comments = opts["--comments"].(string) } // Configure upload expire date - if arguments["--ttl"] != nil && arguments["--ttl"].(string) != "" { - ttlStr := arguments["--ttl"].(string) + if opts["--ttl"] != nil && opts["--ttl"].(string) != "" { + ttlStr := opts["--ttl"].(string) mul := 1 if string(ttlStr[len(ttlStr)-1]) == "m" { mul = 60 @@ -262,32 +261,32 @@ func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err er } ttl, err := strconv.Atoi(ttlStr) if err != nil { - return fmt.Errorf("Invalid TTL %s", arguments["--ttl"].(string)) + return fmt.Errorf("Invalid TTL %s", opts["--ttl"].(string)) } config.TTL = ttl * mul } // Enable archive mode ? - if arguments["-a"].(bool) || arguments["--archive"] != nil || config.Archive { + if opts["-a"].(bool) || opts["--archive"] != nil || config.Archive { config.Archive = true - if arguments["--archive"] != nil && arguments["--archive"] != "" { - config.ArchiveMethod = arguments["--archive"].(string) + if opts["--archive"] != nil && opts["--archive"] != "" { + config.ArchiveMethod = opts["--archive"].(string) } } // Enable secure mode ? - if arguments["--not-secure"].(bool) { + if opts["--not-secure"].(bool) { config.Secure = false - } else if arguments["-s"].(bool) || arguments["--secure"] != nil || config.Secure { + } else if opts["-s"].(bool) || opts["--secure"] != nil || config.Secure { config.Secure = true - if arguments["--secure"] != nil && arguments["--secure"].(string) != "" { - config.SecureMethod = arguments["--secure"].(string) + if opts["--secure"] != nil && opts["--secure"].(string) != "" { + config.SecureMethod = opts["--secure"].(string) } } // Enable password protection ? - if arguments["-p"].(bool) { + if opts["-p"].(bool) { fmt.Printf("Login [plik]: ") var err error _, err = fmt.Scanln(&config.Login) @@ -302,8 +301,8 @@ func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err er if err != nil { return fmt.Errorf("Unable to get password : %s", err) } - } else if arguments["--password"] != nil && arguments["--password"].(string) != "" { - credentials := arguments["--password"].(string) + } else if opts["--password"] != nil && opts["--password"].(string) != "" { + credentials := opts["--password"].(string) sepIndex := strings.Index(credentials, ":") var login, password string if sepIndex > 0 { @@ -318,8 +317,8 @@ func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err er } // Override upload token ? - if arguments["--token"] != nil && arguments["--token"].(string) != "" { - config.Token = arguments["--token"].(string) + if opts["--token"] != nil && opts["--token"].(string) != "" { + config.Token = opts["--token"].(string) } // Ask for token @@ -332,7 +331,7 @@ func (config *CliConfig) UnmarshalArgs(arguments map[string]interface{}) (err er } } - if arguments["--stdin"].(bool) { + if opts["--stdin"].(bool) { config.DisableStdin = false } diff --git a/client/plik.go b/client/plik.go index d6483534..c2cdbf6d 100644 --- a/client/plik.go +++ b/client/plik.go @@ -79,7 +79,7 @@ Options: } // Load config - config, err = LoadConfig() + config, err = LoadConfig(arguments) if err != nil { fmt.Fprintf(os.Stderr, "Unable to load configuration : %s\n", err) os.Exit(1) @@ -105,7 +105,12 @@ Options: // Display info if arguments["--info"].(bool) { - info(client) + err = info(client) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + os.Exit(0) } // Update @@ -307,29 +312,27 @@ Options: } } -func info(client *plik.Client) { +func info(client *plik.Client) (err error) { fmt.Printf("Plik client version : %s\n\n", common.GetBuildInfo()) fmt.Printf("Plik server url : %s\n", config.URL) serverBuildInfo, err := client.GetServerVersion() if err != nil { - fmt.Printf("Plik server unreachable %s\n", err) - return + return fmt.Errorf("Plik server unreachable : %s", err) } fmt.Printf("Plik server version : %s\n", serverBuildInfo) serverConfig, err := client.GetServerConfig() if err != nil { - fmt.Printf("Plik server unreachable %s\n", err) - return + return fmt.Errorf("Plik server unreachable : %s", err) } fmt.Printf("\nPlik server configuration :\n") fmt.Printf(serverConfig.String()) - os.Exit(0) + return nil } func getFileCommand(file *plik.File) (command string, err error) { diff --git a/go.mod b/go.mod index 25bdea42..4dc7b69e 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/gorilla/mux v1.7.1 github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 // indirect + github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jinzhu/gorm v1.9.13-0.20200126152832-7180bd0f27d1 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/lib/pq v1.3.1-0.20200116171513-9eb3fc897d6f // indirect diff --git a/go.sum b/go.sum index 95c4f504..ee9af216 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,8 @@ github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFE github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/gorm v1.9.13-0.20200126152832-7180bd0f27d1 h1:3FjnhIYXVZpGs9h4eA1mSe65h0ocfwoaO8ehiqW0sf8= diff --git a/server/common/config.go b/server/common/config.go index a1faa11e..c7b67125 100644 --- a/server/common/config.go +++ b/server/common/config.go @@ -72,7 +72,7 @@ func NewConfiguration() (config *Configuration) { config.ListenAddress = "0.0.0.0" config.ListenPort = 8080 - config.EnhancedWebSecurity = true + config.EnhancedWebSecurity = false config.MaxFileSize = 10000000000 // 10GB config.MaxFilePerUpload = 1000 diff --git a/server/common/version.go b/server/common/version.go new file mode 100644 index 00000000..e8107316 --- /dev/null +++ b/server/common/version.go @@ -0,0 +1,127 @@ +package common + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/jinzhu/copier" + + "github.com/root-gg/plik/version" +) + +// This variable content is meant to be passed the output of the gen_build_info.sh script at compile time using -ldflags +// BUILD_INFO=$(shell server/gen_build_info.sh $(RELEASE_VERSION) base64) +// BUILD_FLAG=-ldflags="-X github.com/root-gg/plik/server/common.buildInfoString=$(BUILD_INFO)" +var buildInfoString string + +var buildInfo *BuildInfo + +func init() { + buildInfo = &BuildInfo{} + + if buildInfoString != "" { + jsonString, err := base64.StdEncoding.DecodeString(buildInfoString) + if err != nil { + panic(fmt.Errorf("Unable to parse build info base64 string : %s", err)) + } + + err = json.Unmarshal(jsonString, buildInfo) + if err != nil { + panic(fmt.Errorf("Unable to parse build info json string : %s", err)) + } + } + + buildInfo.Version = version.Get() +} + +// BuildInfo export build related variables +type BuildInfo struct { + Version string `json:"version"` + Date int64 `json:"date"` + + User string `json:"user,omitempty"` + Host string `json:"host,omitempty"` + + GitShortRevision string `json:"gitShortRevision,omitempty"` + GitFullRevision string `json:"gitFullRevision,omitempty"` + + IsRelease bool `json:"isRelease"` + IsMint bool `json:"isMint"` + + GoVersion string `json:"goVersion,omitempty"` + + Clients []*Client `json:"clients"` + Releases []*Release `json:"releases"` +} + +// Client export client build related variables +type Client struct { + Name string `json:"name"` + Md5 string `json:"md5"` + Path string `json:"path"` + OS string `json:"os"` + ARCH string `json:"arch"` +} + +// Release export releases related variables +type Release struct { + Name string `json:"name"` + Date int64 `json:"date"` +} + +// GetBuildInfo get build info +func GetBuildInfo() (bi *BuildInfo) { + bi = &BuildInfo{} + + // Defensive copy + err := copier.Copy(bi, buildInfo) + if err != nil { + panic(fmt.Errorf("Unable to copy build info : %s", err)) + } + + return bi +} + +// Sanitize removes sensitive info from BuildInfo +func (bi *BuildInfo) Sanitize() { + // Version is needed for the client update to work + bi.Date = 0 + bi.User = "" + bi.Host = "" + bi.GitShortRevision = "" + bi.GitFullRevision = "" + bi.IsRelease = false + bi.IsMint = false + bi.GoVersion = "" +} + +func (bi *BuildInfo) String() string { + + v := fmt.Sprintf("v%s", bi.Version) + + if bi.GitShortRevision != "" { + v += fmt.Sprintf(" built from git rev %s", bi.GitShortRevision) + } + + // Compute flags + var flags []string + if bi.IsMint { + flags = append(flags, "mint") + } + if bi.IsRelease { + flags = append(flags, "release") + } + + if len(flags) > 0 { + v += fmt.Sprintf(" [%s]", strings.Join(flags, ",")) + } + + if bi.Date > 0 && bi.GoVersion != "" { + v += fmt.Sprintf(" at %s with %s)", time.Unix(bi.Date, 0), bi.GoVersion) + } + + return v +} diff --git a/server/common/version_test.go b/server/common/version_test.go index 6956b1b2..60492989 100644 --- a/server/common/version_test.go +++ b/server/common/version_test.go @@ -1,6 +1,9 @@ package common import ( + "fmt" + "github.com/root-gg/plik/version" + "strings" "testing" "github.com/stretchr/testify/require" @@ -14,6 +17,15 @@ func TestGetBuildInfo(t *testing.T) { func TestGetBuildInfoString(t *testing.T) { buildInfo := GetBuildInfo() - version := buildInfo.String() - require.NotZero(t, version, "invalid build string") + buildInfo.GitShortRevision = "foobar" + v := buildInfo.String() + require.NotZero(t, v, "empty build string") + require.True(t, strings.Contains(v, "foobar"), "invalid version string") +} + +func TestGetBuildInfoStringSanitize(t *testing.T) { + buildInfo := GetBuildInfo() + buildInfo.Sanitize() + v := buildInfo.String() + require.Equal(t, fmt.Sprintf("v%s", version.Get()), v, "invalid build string") } diff --git a/server/gen_build_info.sh b/server/gen_build_info.sh index 498ae35b..eafbde89 100755 --- a/server/gen_build_info.sh +++ b/server/gen_build_info.sh @@ -2,8 +2,11 @@ set -e -# some variables +# arguments version=$1 +output=$2 + +# some variables user=$(whoami) host=$(hostname) repo=$(pwd) @@ -33,11 +36,17 @@ if is_mint_repo; then isMint=true fi -echo "Plik $version with go $goVersion" -echo "Commit $full_rev mint=$isMint release=$isRelease" +if [[ "$output" == "info" ]]; then + echo "Plik $version with go $goVersion" + echo "Commit $full_rev mint=$isMint release=$isRelease" + exit 0 +fi + +# join strings from array +function join_by { local IFS="$1"; shift; echo "$*"; } # compute clients code -clients="" +declare -a clients clientList=$(find clients -name "plik*" 2> /dev/null | sort -n) for client in $clientList ; do folder=$(echo $client | cut -d "/" -f2) @@ -65,120 +74,47 @@ for client in $clientList ; do esac fullName="$prettyOs $prettyArch" - clientCode="&Client{Name: \"$fullName\", Md5: \"$md5\", Path: \"$client\", OS: \"$os\", ARCH: \"$arch\"}" - clients+=$'\t\t'"buildInfo.Clients = append(buildInfo.Clients, $clientCode)"$'\n' + client_json="{\"name\": \"$fullName\", \"md5\": \"$md5\", \"path\": \"$client\", \"os\": \"$os\", \"arch\": \"$arch\"}" + clients+=("$client_json") done +clients_json="[$(join_by , "${clients[@]}")]" # get releases -releases="" +declare -a releases git config versionsort.prereleaseSuffix -RC for gitTag in $(git tag --sort version:refname) do if [ -f "changelog/$gitTag" ]; then # '%at': author date, UNIX timestamp - releaseDate=$(git show -s --pretty="format:%at" "refs/tags/$gitTag") - releaseCode="&Release{Name: \"$gitTag\", Date: $releaseDate}" - releases+=$'\t\t'"buildInfo.Releases = append(buildInfo.Releases, $releaseCode)"$'\n' + release_date=$(git show -s --pretty="format:%at" "refs/tags/$gitTag") + release_json="{\"name\": \"$gitTag\", \"date\": $release_date}" + releases+=("$release_json") fi done +releases_json="[$(join_by , "${releases[@]}")]" -cat > "server/common/version.go" < 0 { - v += fmt.Sprintf(" [%s]", strings.Join(flags, ",")) - } - - v += fmt.Sprintf(" at %s with %s)", time.Unix(bi.Date, 0), bi.GoVersion) - - return v + "clients" : $clients_json, + "releases" : $releases_json } EOF +) + +if [[ "$output" == "base64" ]]; then + echo $json | base64 -w 0 +else + echo $json +fi \ No newline at end of file diff --git a/server/handlers/misc.go b/server/handlers/misc.go index 348238f2..6d706340 100644 --- a/server/handlers/misc.go +++ b/server/handlers/misc.go @@ -15,7 +15,12 @@ import ( // GetVersion return the build information. func GetVersion(ctx *context.Context, resp http.ResponseWriter, req *http.Request) { - common.WriteJSONResponse(resp, common.GetBuildInfo()) + bi := common.GetBuildInfo() + if ctx.GetConfig().EnhancedWebSecurity { + // Remove sensible info from BuildInfo + bi.Sanitize() + } + common.WriteJSONResponse(resp, bi) } // GetConfiguration return the server configuration diff --git a/server/handlers/misc_test.go b/server/handlers/misc_test.go index 96ce4f2f..e9953cb9 100644 --- a/server/handlers/misc_test.go +++ b/server/handlers/misc_test.go @@ -60,6 +60,37 @@ func TestGetVersion(t *testing.T) { require.EqualValues(t, common.GetBuildInfo(), result, "invalid build info") } +func TestGetVersionEnhancedWebSecurity(t *testing.T) { + ctx := newTestingContext(common.NewConfiguration()) + ctx.GetConfig().EnhancedWebSecurity = true + + req, err := http.NewRequest("GET", "/version", bytes.NewBuffer([]byte{})) + require.NoError(t, err, "unable to create new request") + + rr := ctx.NewRecorder(req) + GetVersion(ctx, rr, req) + + // Check the status code is what we expect. + context.TestOK(t, rr) + + respBody, err := ioutil.ReadAll(rr.Body) + require.NoError(t, err, "unable to read response body") + + var result *common.BuildInfo + err = json.Unmarshal(respBody, &result) + require.NoError(t, err, "unable to unmarshal response body") + + require.NotEmpty(t, result.Version, "invalid build info") + require.Empty(t, result.GoVersion, result, "invalid build info") + require.Empty(t, result.GitFullRevision, result, "invalid build info") + require.Empty(t, result.GitShortRevision, result, "invalid build info") + require.Zero(t, result.Date, result, "invalid build info") + require.False(t, result.IsMint, result, "invalid build info") + require.False(t, result.IsRelease, result, "invalid build info") + require.Empty(t, result.Host, result, "invalid build info") + require.Empty(t, result.User, result, "invalid build info") +} + func TestGetConfiguration(t *testing.T) { ctx := newTestingContext(common.NewConfiguration()) diff --git a/server/plikd.cfg b/server/plikd.cfg index 4df043fd..0d4761d2 100644 --- a/server/plikd.cfg +++ b/server/plikd.cfg @@ -24,7 +24,7 @@ SslCert = "plik.crt" # Path to your certificate file SslKey = "plik.key" # Path to your certificate private key file NoWebInterface = false # Disable web user interface DownloadDomain = "" # Enforce download domain ( ex : https://dl.plik.root.gg ) ( necessary for quick upload to work ) -EnhancedWebSecurity = false # Enable additional security headers ( X-Content-Type-Options, X-XSS-Protection, X-Frame-Options, Content-Security-Policy, Secure Cookies, ... ) +EnhancedWebSecurity = false # Enable additional security headers ( X-Content-Type-Options, X-XSS-Protection, X-Frame-Options, Content-Security-Policy, Secure Cookies, ... ) SourceIpHeader = "" # If behind reverse proxy ( ex : X-FORWARDED-FOR ) UploadWhitelist = [] # Restrict upload ans user creation to one or more IP range ( CIDR notation, /32 can be omitted ) diff --git a/version/version.sh b/version/version.sh index 7d9349f1..9e46ec4b 100755 --- a/version/version.sh +++ b/version/version.sh @@ -1,7 +1,5 @@ #!/bin/bash - - set -e FILE=$(dirname $0)/version.go From c0fecfab47b5d5e1f576cd53c86497d51c2fb792 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Sun, 27 Sep 2020 19:29:24 +0200 Subject: [PATCH 05/11] Fix typo in documentation/api.md #318 --- documentation/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/api.md b/documentation/api.md index 0d73921b..b64eea7b 100644 --- a/documentation/api.md +++ b/documentation/api.md @@ -85,7 +85,7 @@ User authentication : The /auth API is designed for the Plik web application nevertheless if you want to automatize it be sure to provide a valid Referrer HTTP header and forward all session cookies. Plik session cookies have the "secure" flag set, so they can only be transmitted over secure HTTPS connections. - To avoid CSRF attacks the value of the plik-xsrf cookie MUST be copied in the X-XRSFToken HTTP header of each + To avoid CSRF attacks the value of the plik-xsrf cookie MUST be copied in the X-XSRFToken HTTP header of each authenticated request. Once authenticated a user can generate upload tokens. Those tokens can be used in the X-PlikToken HTTP header used to link an upload to the user account. It can be put in the ~/.plikrc file of the Plik command line client. From 0b509ed602d2872c3fbfd552c2c6e8e09980659b Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Sun, 27 Sep 2020 19:43:52 +0200 Subject: [PATCH 06/11] Fix getHumanReadableTTL in webapp #321 --- webapp/js/ctrl/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/js/ctrl/main.js b/webapp/js/ctrl/main.js index dade82f6..02bf78d3 100644 --- a/webapp/js/ctrl/main.js +++ b/webapp/js/ctrl/main.js @@ -495,7 +495,7 @@ plik.controller('MainCtrl', ['$scope', '$api', '$config', '$route', '$location', } else if (ttl < 86400) { value = Math.round(ttl / 3600); unit = "hours" - } else if (ttl > 86400) { + } else if (ttl >= 86400) { value = Math.round(ttl / 86400); unit = "days" } else { From d96d89233140a2f24ca76b67747dd2538e0b97d5 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Mon, 28 Sep 2020 00:11:29 +0200 Subject: [PATCH 07/11] Missing downloadDomain in bash script if not given in plikd.cfg #314 --- client/plik.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/client/plik.sh b/client/plik.sh index 7874a325..9c05ed8c 100755 --- a/client/plik.sh +++ b/client/plik.sh @@ -37,7 +37,6 @@ function setTtl() { # ## Vars # -PLIK_URL=${PLIK_URL-"http://127.0.0.1:8080"} PLIK_TOKEN=${PLIK_TOKEN-""} QUIET=false SECURE=false @@ -57,9 +56,12 @@ if [ ! -f "$PLIKRC" ]; then fi if [ -f "$PLIKRC" ]; then - URL=$(grep URL $PLIKRC | grep -Po '(http[^\"]*)') - if [ "$URL" != "" ]; then - PLIK_URL=$URL + # Evironment variable takes precedence over plikrc file + if [ "$PLIK_URL" == "" ]; then + URL=$(grep URL $PLIKRC | grep -Po '(http[^\"]*)') + if [ "$URL" != "" ]; then + PLIK_URL=$URL + fi fi TOKEN=$(grep Token $PLIKRC | sed -n 's/^.*"\(.*\)".*$/\1/p' ) if [ "$TOKEN" != "" ]; then @@ -67,6 +69,9 @@ if [ -f "$PLIKRC" ]; then fi fi +# Default URL to local instance +PLIK_URL=${PLIK_URL-"http://127.0.0.1:8080"} + # ## Parse arguments # @@ -108,7 +113,11 @@ qecho -e "Create new upload on $PLIK_URL...\n" CREATE_UPLOAD_CMD="curl -s -X POST $AUTH_TOKEN_HEADER -d '$OPTIONS' ${PLIK_URL}/upload" NEW_UPLOAD_RESP=$(eval $CREATE_UPLOAD_CMD) UPLOAD_ID=$(echo $NEW_UPLOAD_RESP | jsonValue id) + DOWNLOAD_DOMAIN=$(echo $NEW_UPLOAD_RESP | jsonValue downloadDomain) +if [ "$DOWNLOAD_DOMAIN" == "" ]; then + DOWNLOAD_DOMAIN=$PLIK_URL +fi # Handle error if [ "$UPLOAD_ID" == "" ]; then From 839e400a88a4d12b78ae3800ddfb3f037510a1e6 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Mon, 28 Sep 2020 12:03:39 +0200 Subject: [PATCH 08/11] S3 backend path prefix #316 --- server/data/s3/s3.go | 22 +++++++++++++++------- server/plikd.cfg | 4 +++- testing/minio/plikd.cfg | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/server/data/s3/s3.go b/server/data/s3/s3.go index 783cec9b..125b26fd 100644 --- a/server/data/s3/s3.go +++ b/server/data/s3/s3.go @@ -21,6 +21,7 @@ type Config struct { SecretAccessKey string Bucket string Location string + Prefix string PartSize uint64 UseSSL bool } @@ -31,7 +32,7 @@ func NewConfig(params map[string]interface{}) (config *Config) { config = new(Config) config.Bucket = "plik" config.Location = "us-east-1" - config.PartSize = 32 * 1024 * 1024 // 32MB + config.PartSize = 16 * 1000 * 1000 // 16MB utils.Assign(config, params) return } @@ -53,7 +54,7 @@ func (config *Config) Validate() error { if config.Location == "" { return fmt.Errorf("missing location") } - if config.PartSize < 5*1024*1024 { + if config.PartSize < 5*1000*1000 { return fmt.Errorf("invalid part size") } return nil @@ -100,24 +101,31 @@ func NewBackend(config *Config) (b *Backend, err error) { // GetFile implementation for S3 Data Backend func (b *Backend) GetFile(file *common.File) (reader io.ReadCloser, err error) { - return b.client.GetObject(b.config.Bucket, file.ID, minio.GetObjectOptions{}) + return b.client.GetObject(b.config.Bucket, b.getObjectName(file.ID), minio.GetObjectOptions{}) } // AddFile implementation for S3 Data Backend func (b *Backend) AddFile(file *common.File, fileReader io.Reader) (backendDetails string, err error) { if file.Size > 0 { - _, err = b.client.PutObject(b.config.Bucket, file.ID, fileReader, file.Size, minio.PutObjectOptions{ContentType: file.Type}) + _, err = b.client.PutObject(b.config.Bucket, b.getObjectName(file.ID), fileReader, file.Size, minio.PutObjectOptions{ContentType: file.Type}) } else { // https://github.com/minio/minio-go/issues/989 // Minio defaults to 128MB chunks and has to actually allocate a buffer of this size before uploading the chunk // This can lead to very high memory usage when uploading a lot of small files in parallel - // We default to 32MB which allow to store files up to 320GB ( 10000 chunks of 32MB ), feel free to adjust this parameter to your needs. - _, err = b.client.PutObject(b.config.Bucket, file.ID, fileReader, -1, minio.PutObjectOptions{ContentType: file.Type, PartSize: b.config.PartSize}) + // We default to 16MB which allow to store files up to 160GB ( 10000 chunks of 16MB ), feel free to adjust this parameter to your needs. + _, err = b.client.PutObject(b.config.Bucket, b.getObjectName(file.ID), fileReader, -1, minio.PutObjectOptions{ContentType: file.Type, PartSize: b.config.PartSize}) } return "", err } // RemoveFile implementation for S3 Data Backend func (b *Backend) RemoveFile(file *common.File) (err error) { - return b.client.RemoveObject(b.config.Bucket, file.ID) + return b.client.RemoveObject(b.config.Bucket, b.getObjectName(file.ID)) +} + +func (b *Backend) getObjectName(name string) string { + if b.config.Prefix != "" { + return fmt.Sprintf("%s/%s", b.config.Prefix, name) + } + return name } diff --git a/server/plikd.cfg b/server/plikd.cfg index 0d4761d2..539ab96d 100644 --- a/server/plikd.cfg +++ b/server/plikd.cfg @@ -68,8 +68,10 @@ OvhApiEndpoint = "" # OVH api endpoint to use. Defaults to https # SecretAccessKey = "access_key_secret" # Bucket = "plik" # Location = "us-east-1" +# Prefix = "" # UseSSL = true -# PartSize = 33554432 // Chunk size when file size is not known ( default to 32MB ) +# PartSize = 16000000 // Chunk size when file size is not known. (default to 16MB) +# // Multiply by 10000 to get the max upload file size (max upload file size 160GB) DataBackend = "file" [DataBackendConfig] diff --git a/testing/minio/plikd.cfg b/testing/minio/plikd.cfg index cb4cfe00..39d6f491 100644 --- a/testing/minio/plikd.cfg +++ b/testing/minio/plikd.cfg @@ -12,6 +12,7 @@ DataBackend = "s3" Endpoint = "127.0.0.1:2604" AccessKeyID = "access_key" SecretAccessKey = "access_key_secret" + Prefix = "" PartSize = 5242880 # 5MB [MetadataBackendConfig] From 5d55a17a1ce7afd987f7add1eee090f6068cdb2a Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Mon, 28 Sep 2020 15:51:04 +0200 Subject: [PATCH 09/11] Improved cross-compilation --- Dockerfile | 10 +++++++++- Makefile | 37 ++++++++++++++++++++++++------------- README.md | 14 ++++++++++++++ server/gen_build_info.sh | 4 ++-- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6df1df97..0105b600 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,8 +25,16 @@ WORKDIR /go/src/github.com/root-gg/plik # Add the source code ( see .dockerignore ) ADD . . -# Build everything +# Build clients ( all arch ) RUN make clients + +# Set server target arch +ARG GOOS="" +ARG GOARCH="" +ENV GOOS=${GOOS} +ENV GOARCH=${GOARCH} + +# Build server RUN make server ################################################################################## diff --git a/Makefile b/Makefile index 5f3f3973..ed93a128 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,25 @@ SHELL = /bin/bash -RELEASE_VERSION=$(shell version/version.sh) -RELEASE_DIR="release/plik-$(RELEASE_VERSION)" -RELEASE_TARGETS=darwin-386 darwin-amd64 freebsd-386 \ +RELEASE_VERSION = $(shell version/version.sh) +RELEASE_DIR = "release/plik-$(RELEASE_VERSION)" +RELEASE_TARGETS = darwin-386 darwin-amd64 freebsd-386 \ freebsd-amd64 linux-386 linux-amd64 linux-arm openbsd-386 \ openbsd-amd64 windows-amd64 windows-386 -GOHOSTOS=$(shell go env GOHOSTOS) -GOHOSTARCH=$(shell go env GOHOSTARCH) +GOHOSTOS = $(if $(GOOS),$(GOOS),$(shell go env GOHOSTOS)) +GOHOSTARCH = $(if $(GOARCH),$(GOARCH),$(shell go env GOHOSTARCH)) -DEBROOT_SERVER=debs/server -DEBROOT_CLIENT=debs/client +DEBROOT_SERVER = debs/server +DEBROOT_CLIENT = debs/client -BUILD_INFO=$(shell server/gen_build_info.sh $(RELEASE_VERSION) base64) -BUILD_FLAG=-ldflags="-X github.com/root-gg/plik/server/common.buildInfoString=$(BUILD_INFO)" +BUILD_INFO = $(shell server/gen_build_info.sh $(RELEASE_VERSION) base64) +BUILD_FLAG = -ldflags="-X github.com/root-gg/plik/server/common.buildInfoString=$(BUILD_INFO)" -GO_BUILD=go build $(BUILD_FLAG) -GO_TEST=GORACE="halt_on_error=1" go test $(BUILD_FLAG) -race -cover -p 1 +GO_BUILD = go build $(BUILD_FLAG) +GO_TEST = GORACE="halt_on_error=1" go test $(BUILD_FLAG) -race -cover -p 1 ifdef ENABLE_RACE_DETECTOR - GO_BUILD:=GORACE="halt_on_error=1" $(GO_BUILD) -race + GO_BUILD := GORACE="halt_on_error=1" $(GO_BUILD) -race endif all: clean clean-frontend frontend clients server @@ -225,7 +225,18 @@ test-backends: # Build docker ### docker: - docker build -t rootgg/plik:$(RELEASE_VERSION) . + docker build --build-arg "GOOS=$$GOOS" --build-arg "GOARCH=$$GOARCH" -t rootgg/plik-$(GOHOSTOS)-$(GOHOSTARCH):$(RELEASE_VERSION) . + +### +# Build dockers +### +dockers: + @for target in $(RELEASE_TARGETS) ; do \ + GOOS=`echo $$target | cut -d "-" -f 1`; \ + GOARCH=`echo $$target | cut -d "-" -f 2`; \ + docker build --build-arg "GOOS=$$GOOS" --build-arg "GOARCH=$$GOARCH" -t rootgg/plik-$$target:$(RELEASE_VERSION) . ; \ + done + ### # Remove server build files diff --git a/README.md b/README.md index 6fd73600..5621e32e 100644 --- a/README.md +++ b/README.md @@ -349,3 +349,17 @@ Please be sure to also run/update the test suite : make test make test-backends ``` + +* Cross compilation + +To target a specific architecture : +``` + GOOS=linux GOARCH=arm make server + GOOS=linux GOARCH=arm make client + GOOS=linux GOARCH=arm make docker +``` + +The `make releases` target build a release package for each architecture specified in Makefile +The `make dockers` target build a docker image for each architecture specified in Makefile +The `make clients` target build the plik clients for each architecture specified in Makefile +The `make servers` target build the plik servers for each architecture specified in Makefile diff --git a/server/gen_build_info.sh b/server/gen_build_info.sh index eafbde89..c2ab65d1 100755 --- a/server/gen_build_info.sh +++ b/server/gen_build_info.sh @@ -37,7 +37,7 @@ if is_mint_repo; then fi if [[ "$output" == "info" ]]; then - echo "Plik $version with go $goVersion" + echo "Plik $version built with $goVersion" echo "Commit $full_rev mint=$isMint release=$isRelease" exit 0 fi @@ -114,7 +114,7 @@ EOF ) if [[ "$output" == "base64" ]]; then - echo $json | base64 -w 0 + echo $json | base64 | tr -d '\n' else echo $json fi \ No newline at end of file From 161f86be8c48a060b582af65b33485781561cd6c Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Mon, 28 Sep 2020 21:50:32 +0200 Subject: [PATCH 10/11] Login form focus and submit --- webapp/js/ctrl/login.js | 5 +++++ webapp/partials/login.html | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/webapp/js/ctrl/login.js b/webapp/js/ctrl/login.js index f28480b5..f9405c79 100644 --- a/webapp/js/ctrl/login.js +++ b/webapp/js/ctrl/login.js @@ -2,6 +2,11 @@ plik.controller('LoginCtrl', ['$scope', '$api', '$config', '$location', '$dialog', function ($scope, $api, $config, $location, $dialog) { + // Ugly but it works + setTimeout(function () { + $("#login").focus(); + }, 100); + // Get server config $config.getConfig() .then(function (config) { diff --git a/webapp/partials/login.html b/webapp/partials/login.html index 1cfa3c0b..fe0a38e1 100644 --- a/webapp/partials/login.html +++ b/webapp/partials/login.html @@ -8,7 +8,10 @@
-
+ + + +
@@ -20,8 +23,7 @@
- +
From 458651a0272c905d6f74c7c7258884ea24055b05 Mon Sep 17 00:00:00 2001 From: Charles-Antoine Mathieu Date: Mon, 28 Sep 2020 17:03:17 +0200 Subject: [PATCH 11/11] Plik 1.3 Release --- .travis.yml | 2 +- Makefile | 2 +- README.md | 8 ++++---- changelog/1.3 | 29 +++++++++++++++++++++++++++++ client/test_downgrade.sh | 1 + client/test_upgrade.sh | 1 + version/version.go | 2 +- version/version_test.go | 3 ++- 8 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 changelog/1.3 diff --git a/.travis.yml b/.travis.yml index 616f90c1..922c9f50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: go sudo: required go: - - 1.14 + - 1.15.2 go_import_path: github.com/root-gg/plik diff --git a/Makefile b/Makefile index ed93a128..b252be5e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SHELL = /bin/bash RELEASE_VERSION = $(shell version/version.sh) RELEASE_DIR = "release/plik-$(RELEASE_VERSION)" -RELEASE_TARGETS = darwin-386 darwin-amd64 freebsd-386 \ +RELEASE_TARGETS = darwin-amd64 freebsd-386 \ freebsd-amd64 linux-386 linux-amd64 linux-arm openbsd-386 \ openbsd-amd64 windows-amd64 windows-386 diff --git a/README.md b/README.md index 5621e32e..26635546 100644 --- a/README.md +++ b/README.md @@ -27,16 +27,16 @@ Plik is a scalable & friendly temporary file upload system ( wetransfer like ) i - [Filelink for Plik](https://gitlab.com/joendres/filelink-plik) : Thunderbird Addon to upload attachments to Plik ### Version -1.3-RC1 +1.3 ### Installation ##### From release To run plik, it's very simple : ```sh -$ wget https://github.com/root-gg/plik/releases/download/1.3-RC1/plik-1.3-RC1-linux-64bits.tar.gz -$ tar xzvf plik-1.3-RC1-linux-64bits.tar.gz -$ cd plik-1.3-RC1/server +$ wget https://github.com/root-gg/plik/releases/download/1.3/plik-1.3-linux-64bits.tar.gz +$ tar xzvf plik-1.3-linux-64bits.tar.gz +$ cd plik-1.3/server $ ./plikd ``` Et voilà ! You now have a fully functional instance of Plik running on http://127.0.0.1:8080. diff --git a/changelog/1.3 b/changelog/1.3 new file mode 100644 index 00000000..411c3274 --- /dev/null +++ b/changelog/1.3 @@ -0,0 +1,29 @@ +Plik 1.3 + + Hi, today we're releasing Plik 1.3 ! + + Here is the changelog : + + New + - Add --info to cli client to display server configuration + + Fixed + - Fix common.AskConfirmation handling of no input + - Fix missing unit in frontend menu when default TTL equals 86400s + - Fix missing downloadDomain in bash script if not given in plikd.cfg + - Fix missing focus and submit in login form + - Fix bypass ~/.plikrc creation if --server cli param is provided + + Removed + - darwin-386 target ( https://github.com/golang/go/issues/37610 ) + + Misc + - Improved cross-compilation in Makefile + - Cross-compiled docker images + - Pass build info using ldflags + - EnhancedWebSecurity configuration parameter removes sensible information form /version API endpoint + + Binaries are compiled using Go v1.15.2 + +Faithfully, +The Plik team \ No newline at end of file diff --git a/client/test_downgrade.sh b/client/test_downgrade.sh index 6131a24f..c04a04c7 100755 --- a/client/test_downgrade.sh +++ b/client/test_downgrade.sh @@ -24,6 +24,7 @@ RELEASES=( 1.2.2 1.2.3 1.2.4 + 1.3-RC1 ) ### diff --git a/client/test_upgrade.sh b/client/test_upgrade.sh index 40f7081b..f4e11bf5 100755 --- a/client/test_upgrade.sh +++ b/client/test_upgrade.sh @@ -25,6 +25,7 @@ RELEASES=( 1.2.2 1.2.3 1.2.4 + 1.3-RC1 ) ### diff --git a/version/version.go b/version/version.go index d4b1c6d3..df12a849 100644 --- a/version/version.go +++ b/version/version.go @@ -1,6 +1,6 @@ package version -const version = "1.3-RC1" +const version = "1.3" // Get return the current package version func Get() string { diff --git a/version/version_test.go b/version/version_test.go index e57d589e..bdb683c1 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -8,7 +8,7 @@ import ( ) func getVersionRegex() string { - return `^\d+\.\d+((\.\d+)|(\-RC\d+))$` + return `^\d+\.\d+((\.\d+)?|(\-RC\d+))$` } func validateVersion(t *testing.T, version string, ok bool) { @@ -23,6 +23,7 @@ func validateVersion(t *testing.T, version string, ok bool) { } func TestValidateVersionRegex(t *testing.T) { + validateVersion(t, "1.1", true) validateVersion(t, "1.1.1", true) validateVersion(t, "1.1-RC1", true) validateVersion(t, "1.1.1-RC1", false)