shelfy-v2/main.go
2025-08-02 16:12:17 +02:00

155 lines
4.9 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"canguidev/shelfy/internal/db"
"canguidev/shelfy/internal/routes"
"canguidev/shelfy/internal/utils"
"crypto/tls"
"errors"
"log"
"net"
"os"
"path/filepath"
"strings"
"time"
ftpserver "github.com/fclairamb/ftpserverlib"
"github.com/gin-gonic/gin"
"github.com/spf13/afero"
)
// ---------- FTP SERVERLIB DRIVERS ----------
type mainDriver struct{}
type clientDriver struct {
fs afero.Fs
}
func (d *mainDriver) GetSettings() (*ftpserver.Settings, error) {
return &ftpserver.Settings{
ListenAddr: ":2121",
PublicHost: "163.172.68.103",
PassiveTransferPortRange: &ftpserver.PortRange{
Start: 30000,
End: 30100,
},
Banner: "Bienvenue sur le FTP Go!",
IdleTimeout: 0,
ConnectionTimeout: 0,
}, nil
}
func (d *mainDriver) ClientConnected(cc ftpserver.ClientContext) (string, error) {
log.Printf("[FTP] Nouvelle connexion depuis %s", cc.RemoteAddr())
return "Bienvenue FTP !", nil
}
func (d *mainDriver) ClientDisconnected(cc ftpserver.ClientContext) {
log.Printf("[FTP] Déconnexion client %s", cc.RemoteAddr())
}
func (d *mainDriver) GetTLSConfig() (*tls.Config, error) {
return nil, nil // Pas de TLS, à gérer si tu veux FTPS
}
func (d *mainDriver) AuthUser(cc ftpserver.ClientContext, user, pass string) (ftpserver.ClientDriver, error) {
log.Printf("[FTP] Tentative login user='%s' pass='%s'", user, pass)
remoteAddr := cc.RemoteAddr().String()
host, _, _ := net.SplitHostPort(remoteAddr)
if user == "cangui2089" && pass == "GHT30k7!" {
uploadPath, _ := filepath.Abs("upload")
fi, err := os.Stat(uploadPath)
if err != nil || !fi.IsDir() {
log.Printf("[FTP] Le dossier upload/ est manquant ou non valide: %v", err)
return nil, errors.New("le dossier upload/ doit exister")
}
log.Printf("[FTP] Connexion OK, exposé: %s", uploadPath)
return &clientDriver{
fs: afero.NewBasePathFs(afero.NewOsFs(), uploadPath),
}, nil
}
// 2. Autoriser anonymous depuis 192.168.1.123 uniquement
if user == "anonymous" && host == "82.65.73.115" {
base := filepath.Clean("upload")
fs := afero.NewBasePathFs(afero.NewOsFs(), base)
log.Printf("[FTP] Login ANONYMOUS autorisé pour %s", host)
return &clientDriver{fs: fs}, nil
}
// 3. Sinon refuse tout anonyme ou mauvais login
if user == "" || user == "anonymous" {
log.Printf("[FTP] Login anonymous refusé pour %s", host)
return nil, errors.New("anonymous login not allowed")
}
return nil, errors.New("identifiants invalides")
}
// ---------- clientDriver = wrapper sur afero.Fs ----------
func (c *clientDriver) Name() string { return "aferofs" }
func (c *clientDriver) Create(name string) (afero.File, error) { return c.fs.Create(name) }
func (c *clientDriver) Mkdir(name string, perm os.FileMode) error { return c.fs.Mkdir(name, perm) }
func (c *clientDriver) MkdirAll(path string, perm os.FileMode) error { return c.fs.MkdirAll(path, perm) }
func (c *clientDriver) Open(name string) (afero.File, error) { return c.fs.Open(name) }
func (c *clientDriver) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
log.Printf("[FTP][DEBUG] Open: %s", name)
return c.fs.OpenFile(name, flag, perm)
}
func (c *clientDriver) Remove(name string) error { return c.fs.Remove(name) }
func (c *clientDriver) RemoveAll(path string) error { return c.fs.RemoveAll(path) }
func (c *clientDriver) Rename(old, new string) error { return c.fs.Rename(old, new) }
func (c *clientDriver) Stat(name string) (os.FileInfo, error) {
return c.fs.Stat(name)
}
func (c *clientDriver) LstatIfPossible(name string) (os.FileInfo, bool, error) {
fi, err := c.fs.Stat(name)
return fi, false, err
}
func (c *clientDriver) Chmod(name string, mode os.FileMode) error {
fullPath := filepath.Join("upload", name)
return os.Chmod(fullPath, mode)
}
func (c *clientDriver) Chown(name string, uid, gid int) error {
fullPath := filepath.Join("upload", name)
return os.Chown(fullPath, uid, gid)
}
func (c *clientDriver) Chtimes(name string, atime, mtime time.Time) error {
fullPath := filepath.Join("upload", name)
return os.Chtimes(fullPath, atime, mtime)
}
// ---------- MAIN ----------
func main() {
// Serveur FTP dans une goroutine
go func() {
ftp := ftpserver.NewFtpServer(&mainDriver{})
log.Println("[FTP] Serveur FTP en écoute sur ftp://cangui2089:GHT30k7!@localhost:2121 (upload/)")
if err := ftp.ListenAndServe(); err != nil {
log.Fatal("[FTP] Erreur:", err)
}
}()
// Serveur HTTP Gin (classique)
bd := db.InitDB()
app := gin.Default()
api := app.Group("/api/v1")
routes.AddRoutes(api, bd)
utils.CreateDefaultFolder(bd)
app.Static("/static", "./web")
app.NoRoute(func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.Path, "/api/") {
c.JSON(404, gin.H{"error": "Not found"})
return
}
c.File("./web/index.html")
})
log.Println("[HTTP] Serveur Gin sur http://localhost:8080")
app.Run(":8080")
}