package main import ( "errors" "fmt" "io" "os" "path" "path/filepath" "strings" "time" "flag" "log" "goftp.io/server" "github.com/ProtonMail/gopenpgp/v3/crypto" ) type ForwarderDriver struct { RecipientKey *crypto.Key OutputPath string server.Perm } type myFileInfo struct { mode os.FileMode owner string group string } func (f *myFileInfo) Mode() os.FileMode { return os.ModeDir } func (f *myFileInfo) Owner() string { return "" } func (f *myFileInfo) Group() string { return "" } func (f *myFileInfo) Name() string { return "" } func (f *myFileInfo) Size() int64 { return 0 } func (f *myFileInfo) Sys() any { return 0 } func (f *myFileInfo) ModTime() time.Time { return time.Now() } func (f *myFileInfo) IsDir() bool { return true } func (driver *ForwarderDriver) Init(conn *server.Conn) { //driver.conn = conn } func (driver *ForwarderDriver) ChangeDir(path string) error { log.Printf("ChangeDir: %v", path) return nil } func (driver *ForwarderDriver) Stat(path string) (server.FileInfo, error) { log.Printf("Stat: %v", path) if (path == "/") { return &myFileInfo{}, nil } else { return nil, errors.New("Not Implemented") } } func (driver *ForwarderDriver) ListDir(path string, callback func(server.FileInfo) error) error { return errors.New("Not Implemented") } func (driver *ForwarderDriver) DeleteDir(path string) error { return errors.New("Not Implemented") } func (driver *ForwarderDriver) DeleteFile(path string) error { return errors.New("Not Implemented") } func (driver *ForwarderDriver) Rename(fromPath string, toPath string) error { return errors.New("Not Implemented") } func (driver *ForwarderDriver) MakeDir(path string) error { return errors.New("Not Implemented") } func (driver *ForwarderDriver) GetFile(path string, offset int64) (int64, io.ReadCloser, error) { return 0, nil, errors.New("Not Implemented") } func (driver *ForwarderDriver) PutFile(destPath string, data io.Reader, appendData bool) (int64, error) { log.Printf("Receiving file %v", destPath) dest_filename := path.Base(destPath) t := time.Now() encrypted_filename := fmt.Sprintf("scan_%04d-%02d-%02d-%02d-%02d_%v.asc", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), dest_filename) encrypted_file_path := filepath.Join(driver.OutputPath, encrypted_filename) log.Printf("Writing to %v", encrypted_file_path) log.Printf("Opening output file") encryptedFile, err := os.Create(encrypted_file_path) if err != nil { log.Printf("Error: %v", err) return 0, err } log.Printf("Preparing GPG encryption handle") pgp := crypto.PGP() encHandle, err := pgp.Encryption().Recipient(driver.RecipientKey).New() if err != nil { log.Printf("Error: %v", err) return 0, err } log.Printf("Preparing encrypting writer") encryptingWriter, err := encHandle.EncryptingWriter(encryptedFile, crypto.Armor) if err != nil { log.Printf("Error: %v", err) return 0, err } log.Printf("Read, encrypt and write data") transferred_bytes, err := io.Copy(encryptingWriter, data) if err != nil { log.Printf("Error: %v", err) return 0, err } encryptingWriter.Close() encryptedFile.Close() log.Printf("Transferred bytes: %v", transferred_bytes) return transferred_bytes, err } type ForwarderDriverFactory struct { RecipientKey *crypto.Key OutputPath string server.Perm } func (factory *ForwarderDriverFactory) NewDriver() (server.Driver, error) { return &ForwarderDriver{factory.RecipientKey, factory.OutputPath, factory.Perm}, nil } func main() { var ( user = flag.String("user", "admin", "Username for login") pass = flag.String("pass", "123456", "Password for login") port = flag.Int("port", 2121, "Port") host = flag.String("host", "localhost", "Host") passiveports = flag.String("passiveports", "2130-2134", "Passive ports") gpgkey_path = flag.String("gpgkey", "", "File of the public GPG key to encrypt files to") output_path = flag.String("output", ".", "Path to directory to write encrypted files to") ) flag.Parse() absolute_output_path, err := filepath.Abs(*output_path) if err != nil { log.Fatalf("Error: %v", err) } log.Printf("Writing encrypted files to %v", absolute_output_path) if *gpgkey_path == "" { log.Fatalf("Specify path to GPG key with -gpgkey") } gpgkey_file, err := os.Open(*gpgkey_path) if err != nil { log.Fatalf("Error: %v", err) } gpgkey, err := crypto.NewKeyFromReader(gpgkey_file) if err != nil { log.Fatalf("Error: %v", err) } gpgkey_file.Close() log.Printf("Encrypting files to %v", strings.ToUpper(gpgkey.GetFingerprint())) if !gpgkey.CanEncrypt(time.Now().Unix()) { log.Fatalf("Error: Provided GPG key does not support encryption") } factory := &ForwarderDriverFactory{ RecipientKey: gpgkey, OutputPath: absolute_output_path, Perm: server.NewSimplePerm("user","group"), } opts := &server.ServerOpts{ Factory: factory, Port: *port, Hostname: *host, Auth: &server.SimpleAuth{Name: *user, Password: *pass}, PassivePorts: *passiveports, } log.Printf("Starting ftp server on %v:%v", opts.Hostname, opts.Port) log.Printf("Username %v, Password %v", *user, *pass) server := server.NewServer(opts) server.ListenAndServe() if err != nil { log.Fatal("Error starting server:", err) } }