From 34ab765a5c0d603971af799f5438c4f92d9896ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Nu=C8=9Biu?= Date: Sun, 26 Nov 2017 23:03:15 +0200 Subject: [PATCH] Implementing upload server --- README.md | 23 +++++++++--- server/server/commands.go | 46 ++++++++++++++++++++++++ server/server/config/config.go | 14 +++++--- server/server/config/config_test.go | 6 ++-- server/server/connection.go | 55 ++++++++++++++++++++++++++--- server/server/path_test.go | 2 ++ server/simplFTP.go | 3 ++ 7 files changed, 132 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9bc0659..c89aa0c 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,12 @@ The server accepts the following commands: //todo +#### The upload server + +If the upload server is running, the user will be able to put files +on the **absoluteServePath**. After the file is uploaded successfully, +if the timeout is not reached, the user will get back the filename. + #### Sending commands via netcat To grab a file the following command can be send: @@ -32,13 +38,19 @@ Sample Configuration File: ``` { "address": "localhost", - "port": "8080", + "port": 8080, "maxDirDepth": 30, "absoluteServePath": "/Users/denis/Dropbox/Pictures/CuteAvatars", "pic": { - "color": false, - "x": 0, - "y": 0 + "color": true, + "x": 197, + "y": 50 + }, + "upload": { + "enabled": false, + "timeout": 5, + "address": "localhost", + "port": 8081 } } ``` @@ -53,7 +65,8 @@ The **config.json** file contains the following settings: 4. absoluteServePath - The path from where to serve the files. -5. pic - The X and Y max size for the pic command. A value of 0 means original size +5. pic - The X and Y max size for the pic command. A value of 0 means original size. +6. upload - Settings for the upload server. If one of the settings are changed, the server will reload the configuration. Except for the absoluteServePath. \ No newline at end of file diff --git a/server/server/commands.go b/server/server/commands.go index f12890e..898f5df 100644 --- a/server/server/commands.go +++ b/server/server/commands.go @@ -5,14 +5,60 @@ import ( "io" "io/ioutil" "log" + "math/rand" "os" "strconv" "strings" + "bufio" + "time" + "github.com/spf13/viper" "github.com/zyxar/image2ascii/ascii" ) +func randSeq(n int) string { + var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} + +// UploadFile uploads a file to the server +func UploadFile(c Client) (string, error) { + + input := bufio.NewScanner(c.Connection()) + start := time.Now() + timeout := time.Duration(viper.GetInt("upload.timeout")) * time.Second + + var filename = randSeq(10) + var _, err = os.Stat(MakePathFromStringStack(c.Stack()) + filename) + + // Make sure that the filename is random. + for !os.IsNotExist(err) { + filename = randSeq(10) + _, err = os.Stat(MakePathFromStringStack(c.Stack()) + filename) + } + + f, err := os.Create(MakePathFromStringStack(c.Stack()) + filename) + if err != nil { + return filename, err + } + defer f.Close() + + for input.Scan() { + if time.Since(start) >= timeout { + log.Println(c.Connection().RemoteAddr().String() + " has reached timeout!") + break + } + f.WriteString(input.Text() + "\n") + } + + return filename, nil +} + // SendAsciiPic sends an image as ascii text to the client. func SendAsciiPic(c Client, path string) error { f, err := os.Open(MakePathFromStringStack(c.Stack()) + path) diff --git a/server/server/config/config.go b/server/server/config/config.go index ca467e0..53ae35e 100644 --- a/server/server/config/config.go +++ b/server/server/config/config.go @@ -28,17 +28,20 @@ func loadConfigFromFile() error { // setDefaultConfiguration will set the default configuration settings. func setDefaultConfiguration() { viper.SetDefault("address", "localhost") - viper.SetDefault("port", "8080") + viper.SetDefault("port", 8080) viper.SetDefault("configPath", ConfigPath) viper.SetDefault("maxDirDepth", 30) viper.SetDefault("absoluteServePath", "./") viper.SetDefault("pic.x", 0) viper.SetDefault("pic.y", 0) viper.SetDefault("pic.color", false) + viper.SetDefault("upload.enabled", false) + viper.SetDefault("upload.address", "localhost") + viper.SetDefault("upload.port", 8081) } -// InitializedConfiguration initializes the configuration for the application. -func InitializedConfiguration(callback func(e fsnotify.Event)) { +// InitializeConfiguration initializes the configuration for the application. +func InitializeConfiguration() { flag.StringVar(&ConfigPath, "config", ".", "Set the location of the config file.") flag.Parse() @@ -46,5 +49,8 @@ func InitializedConfiguration(callback func(e fsnotify.Event)) { loadConfigFromFile() viper.WatchConfig() - viper.OnConfigChange(callback) +} + +func ConfigChangeCallback(cb func(event fsnotify.Event)) { + viper.OnConfigChange(cb) } diff --git a/server/server/config/config_test.go b/server/server/config/config_test.go index b279100..22993fe 100644 --- a/server/server/config/config_test.go +++ b/server/server/config/config_test.go @@ -8,15 +8,15 @@ import ( func TestLoadConfigFromFile(t *testing.T) { // SetDefaultConfiguration must be called BEFORE LoadConfigFromFile. - InitializedConfiguration() + InitializeConfiguration() Address := viper.GetString("address") if Address == "" { t.Error("TestLoadConfigFromFile: Can't get Address!") } - Port := viper.GetString("port") - if Port == "" { + Port := viper.GetInt("port") + if Port == 0 { t.Error("TestLoadConfigFromFile: Can't get Port!") } diff --git a/server/server/connection.go b/server/server/connection.go index 94487c8..9325f66 100644 --- a/server/server/connection.go +++ b/server/server/connection.go @@ -88,18 +88,21 @@ func HandleConnection(client Client) { log.Println(client.Connection().RemoteAddr(), "has disconnected.") } -func StartFtpServer() { - config.InitializedConfiguration(func(e fsnotify.Event) { - log.Println("Configuration reloaded!") +func Init() { + config.InitializeConfiguration() + config.ConfigChangeCallback(func(event fsnotify.Event) { + log.Println("Configuration reloaded successfully!") }) +} +func StartFtpServer() { Addr := viper.GetString("address") - Port := viper.GetString("port") + Port := viper.GetInt("port") DirDepth := viper.GetInt("maxDirDepth") BasePath = viper.GetString("absoluteServePath") // Start the server - listener, err := net.Listen("tcp", Addr+":"+Port) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", Addr, Port)) if err != nil { log.Fatal(err) } @@ -122,3 +125,45 @@ func StartFtpServer() { go HandleConnection(&client) } } + +func StartUploadServer() { + if viper.GetBool("upload.enabled") == false { + log.Println("Uploading not enabled. To enable modify the config file and restart the server") + return + } + + Addr := viper.GetString("upload.address") + Port := viper.GetInt("upload.port") + + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", Addr, Port)) + if err != nil { + log.Fatal(err) + } + + log.Println("Upload server running on:", Addr, "port", Port) + + for { + + conn, err := listener.Accept() + if err != nil { + log.Print(err) + continue + } + + client := FTPClient{} + client.SetStack(MakeStringStack(1)) + client.SetConnection(conn) + + log.Println(conn.RemoteAddr().String() + " is uploading something.") + + filename, err := UploadFile(&client) + if err == nil { + io.WriteString(conn, filename) + } else { + log.Print(conn.RemoteAddr().String()) + log.Println(err) + } + + log.Println(conn.RemoteAddr().String() + "'s upload finished.") + } +} diff --git a/server/server/path_test.go b/server/server/path_test.go index deb6258..f628266 100644 --- a/server/server/path_test.go +++ b/server/server/path_test.go @@ -14,6 +14,8 @@ func TestMakePathFromStringStack(t *testing.T) { st.Push("folder two") st.Push("trinity") + BasePath = "./" + path := MakePathFromStringStack(st) expected := fmt.Sprintf("%s%s/%s/%s/", BasePath, "first", "folder two", "trinity") diff --git a/server/simplFTP.go b/server/simplFTP.go index d743fed..7b5ab76 100644 --- a/server/simplFTP.go +++ b/server/simplFTP.go @@ -5,5 +5,8 @@ import ( ) func main() { + server.Init() + + go server.StartUploadServer() server.StartFtpServer() }