scan-to-gpg/main.go

228 lines
5.2 KiB
Go

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)
}
}