2019-10-29 15:22:29 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2024-11-24 18:56:45 +01:00
|
|
|
"fmt"
|
2019-10-29 15:22:29 +01:00
|
|
|
"io"
|
|
|
|
"os"
|
2024-11-24 18:56:45 +01:00
|
|
|
"path"
|
2024-11-24 19:23:46 +01:00
|
|
|
"path/filepath"
|
2024-11-24 17:42:39 +01:00
|
|
|
"strings"
|
2023-07-08 11:49:14 +02:00
|
|
|
"time"
|
2024-11-24 16:43:16 +01:00
|
|
|
"flag"
|
|
|
|
"log"
|
2019-10-29 15:22:29 +01:00
|
|
|
"goftp.io/server"
|
2024-11-24 16:43:16 +01:00
|
|
|
"github.com/ProtonMail/gopenpgp/v3/crypto"
|
2019-10-29 15:22:29 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type ForwarderDriver struct {
|
2024-11-24 17:34:12 +01:00
|
|
|
RecipientKey *crypto.Key
|
2024-11-24 19:23:46 +01:00
|
|
|
OutputPath string
|
2019-10-29 15:22:29 +01:00
|
|
|
server.Perm
|
|
|
|
}
|
|
|
|
|
2023-07-08 11:49:14 +02:00
|
|
|
type myFileInfo struct {
|
2019-10-29 15:22:29 +01:00
|
|
|
mode os.FileMode
|
|
|
|
owner string
|
|
|
|
group string
|
|
|
|
}
|
|
|
|
|
2023-07-08 11:49:14 +02:00
|
|
|
func (f *myFileInfo) Mode() os.FileMode {
|
|
|
|
return os.ModeDir
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *myFileInfo) Owner() string {
|
|
|
|
return ""
|
2019-10-29 15:22:29 +01:00
|
|
|
}
|
|
|
|
|
2023-07-08 11:49:14 +02:00
|
|
|
func (f *myFileInfo) Group() string {
|
2019-10-29 15:22:29 +01:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2023-07-08 11:49:14 +02:00
|
|
|
func (f *myFileInfo) Name() string {
|
2019-10-29 15:22:29 +01:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2023-07-08 11:49:14 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:22:29 +01:00
|
|
|
func (driver *ForwarderDriver) Init(conn *server.Conn) {
|
|
|
|
//driver.conn = conn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (driver *ForwarderDriver) ChangeDir(path string) error {
|
2023-07-08 11:49:14 +02:00
|
|
|
log.Printf("ChangeDir: %v", path)
|
2019-10-29 15:22:29 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (driver *ForwarderDriver) Stat(path string) (server.FileInfo, error) {
|
2023-07-08 11:49:14 +02:00
|
|
|
log.Printf("Stat: %v", path)
|
|
|
|
if (path == "/") {
|
|
|
|
return &myFileInfo{}, nil
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("Not Implemented")
|
|
|
|
}
|
2019-10-29 15:22:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2024-11-24 18:06:27 +01:00
|
|
|
log.Printf("Receiving file %v", destPath)
|
2024-11-24 16:43:16 +01:00
|
|
|
|
2024-11-24 18:56:45 +01:00
|
|
|
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)
|
|
|
|
|
2024-11-24 19:23:46 +01:00
|
|
|
encrypted_file_path := filepath.Join(driver.OutputPath, encrypted_filename)
|
|
|
|
|
|
|
|
log.Printf("Writing to %v", encrypted_file_path)
|
2024-11-24 18:56:45 +01:00
|
|
|
|
2024-11-24 18:06:27 +01:00
|
|
|
log.Printf("Opening output file")
|
2024-11-24 19:23:46 +01:00
|
|
|
encryptedFile, err := os.Create(encrypted_file_path)
|
2024-11-24 16:43:16 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error: %v", err)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2024-11-24 18:06:27 +01:00
|
|
|
log.Printf("Preparing GPG encryption handle")
|
2024-11-24 16:43:16 +01:00
|
|
|
pgp := crypto.PGP()
|
2024-11-24 17:34:12 +01:00
|
|
|
encHandle, err := pgp.Encryption().Recipient(driver.RecipientKey).New()
|
2024-11-24 16:43:16 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error: %v", err)
|
|
|
|
return 0, err
|
|
|
|
}
|
2024-11-24 18:06:27 +01:00
|
|
|
|
|
|
|
log.Printf("Preparing encrypting writer")
|
|
|
|
encryptingWriter, err := encHandle.EncryptingWriter(encryptedFile, crypto.Armor)
|
2024-11-24 16:43:16 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error: %v", err)
|
|
|
|
return 0, err
|
|
|
|
}
|
2024-11-24 18:06:27 +01:00
|
|
|
|
|
|
|
log.Printf("Read, encrypt and write data")
|
|
|
|
transferred_bytes, err := io.Copy(encryptingWriter, data)
|
2024-11-24 16:43:16 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error: %v", err)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2024-11-24 18:06:27 +01:00
|
|
|
encryptingWriter.Close()
|
|
|
|
encryptedFile.Close()
|
2024-11-24 16:43:16 +01:00
|
|
|
|
2024-11-24 18:06:27 +01:00
|
|
|
log.Printf("Transferred bytes: %v", transferred_bytes)
|
|
|
|
return transferred_bytes, err
|
2019-10-29 15:22:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type ForwarderDriverFactory struct {
|
2024-11-24 17:34:12 +01:00
|
|
|
RecipientKey *crypto.Key
|
2024-11-24 19:23:46 +01:00
|
|
|
OutputPath string
|
2019-10-29 15:22:29 +01:00
|
|
|
server.Perm
|
|
|
|
}
|
|
|
|
|
|
|
|
func (factory *ForwarderDriverFactory) NewDriver() (server.Driver, error) {
|
2024-11-24 19:23:46 +01:00
|
|
|
return &ForwarderDriver{factory.RecipientKey, factory.OutputPath, factory.Perm}, nil
|
2019-10-29 15:22:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
2023-07-08 12:22:27 +02:00
|
|
|
passiveports = flag.String("passiveports", "2130-2134", "Passive ports")
|
2024-11-24 17:34:12 +01:00
|
|
|
gpgkey_path = flag.String("gpgkey", "", "File of the public GPG key to encrypt files to")
|
2024-11-24 19:23:46 +01:00
|
|
|
output_path = flag.String("output", ".", "Path to directory to write encrypted files to")
|
2019-10-29 15:22:29 +01:00
|
|
|
)
|
|
|
|
flag.Parse()
|
2024-11-24 19:23:46 +01:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2024-11-24 17:34:12 +01:00
|
|
|
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)
|
|
|
|
}
|
2024-11-24 16:43:16 +01:00
|
|
|
|
2024-11-24 17:34:12 +01:00
|
|
|
gpgkey, err := crypto.NewKeyFromReader(gpgkey_file)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-11-24 17:46:38 +01:00
|
|
|
gpgkey_file.Close()
|
|
|
|
|
2024-11-24 17:42:39 +01:00
|
|
|
log.Printf("Encrypting files to %v", strings.ToUpper(gpgkey.GetFingerprint()))
|
2024-11-24 17:34:12 +01:00
|
|
|
|
2024-11-24 17:42:39 +01:00
|
|
|
if !gpgkey.CanEncrypt(time.Now().Unix()) {
|
|
|
|
log.Fatalf("Error: Provided GPG key does not support encryption")
|
|
|
|
}
|
2024-11-24 17:34:12 +01:00
|
|
|
|
|
|
|
factory := &ForwarderDriverFactory{
|
|
|
|
RecipientKey: gpgkey,
|
2024-11-24 19:23:46 +01:00
|
|
|
OutputPath: absolute_output_path,
|
2024-11-24 17:34:12 +01:00
|
|
|
Perm: server.NewSimplePerm("user","group"),
|
|
|
|
}
|
2019-10-29 15:22:29 +01:00
|
|
|
|
|
|
|
opts := &server.ServerOpts{
|
|
|
|
Factory: factory,
|
|
|
|
Port: *port,
|
|
|
|
Hostname: *host,
|
|
|
|
Auth: &server.SimpleAuth{Name: *user, Password: *pass},
|
2023-07-08 12:22:27 +02:00
|
|
|
PassivePorts: *passiveports,
|
2019-10-29 15:22:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Starting ftp server on %v:%v", opts.Hostname, opts.Port)
|
|
|
|
log.Printf("Username %v, Password %v", *user, *pass)
|
|
|
|
server := server.NewServer(opts)
|
2024-11-24 17:34:12 +01:00
|
|
|
server.ListenAndServe()
|
2019-10-29 15:22:29 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error starting server:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|