| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- package cmd
- import (
- "errors"
- "fmt"
- "log"
- "os"
- "strings"
- "github.com/dutchcoders/transfer.sh/server/storage"
- "github.com/dutchcoders/transfer.sh/server"
- "github.com/fatih/color"
- "github.com/urfave/cli/v2"
- "google.golang.org/api/googleapi"
- )
- // Version is inject at build time
- var Version = "0.0.0"
- var helpTemplate = `NAME:
- {{.Name}} - {{.Usage}}
- DESCRIPTION:
- {{.Description}}
- USAGE:
- {{.Name}} {{if .Flags}}[flags] {{end}}command{{if .Flags}}{{end}} [arguments...]
- COMMANDS:
- {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
- {{end}}{{if .Flags}}
- FLAGS:
- {{range .Flags}}{{.}}
- {{end}}{{end}}
- VERSION:
- ` + Version +
- `{{ "\n"}}`
- var globalFlags = []cli.Flag{
- &cli.StringFlag{
- Name: "listener",
- Usage: "127.0.0.1:8080",
- Value: "127.0.0.1:8080",
- EnvVars: []string{"LISTENER"},
- },
- // redirect to https?
- // hostnames
- &cli.StringFlag{
- Name: "profile-listener",
- Usage: "127.0.0.1:6060",
- Value: "",
- EnvVars: []string{"PROFILE_LISTENER"},
- },
- &cli.BoolFlag{
- Name: "force-https",
- Usage: "",
- EnvVars: []string{"FORCE_HTTPS"},
- },
- &cli.StringFlag{
- Name: "tls-listener",
- Usage: "127.0.0.1:8443",
- Value: "",
- EnvVars: []string{"TLS_LISTENER"},
- },
- &cli.BoolFlag{
- Name: "tls-listener-only",
- Usage: "",
- EnvVars: []string{"TLS_LISTENER_ONLY"},
- },
- &cli.StringFlag{
- Name: "tls-cert-file",
- Value: "",
- EnvVars: []string{"TLS_CERT_FILE"},
- },
- &cli.StringFlag{
- Name: "tls-private-key",
- Value: "",
- EnvVars: []string{"TLS_PRIVATE_KEY"},
- },
- &cli.StringFlag{
- Name: "temp-path",
- Usage: "path to temp files",
- Value: os.TempDir(),
- EnvVars: []string{"TEMP_PATH"},
- },
- &cli.StringFlag{
- Name: "web-path",
- Usage: "path to static web files",
- Value: "",
- EnvVars: []string{"WEB_PATH"},
- },
- &cli.StringFlag{
- Name: "proxy-path",
- Usage: "path prefix when service is run behind a proxy",
- Value: "",
- EnvVars: []string{"PROXY_PATH"},
- },
- &cli.StringFlag{
- Name: "proxy-port",
- Usage: "port of the proxy when the service is run behind a proxy",
- Value: "",
- EnvVars: []string{"PROXY_PORT"},
- },
- &cli.StringFlag{
- Name: "email-contact",
- Usage: "email address to link in Contact Us (front end)",
- Value: "",
- EnvVars: []string{"EMAIL_CONTACT"},
- },
- &cli.StringFlag{
- Name: "ga-key",
- Usage: "key for google analytics (front end)",
- Value: "",
- EnvVars: []string{"GA_KEY"},
- },
- &cli.StringFlag{
- Name: "uservoice-key",
- Usage: "key for user voice (front end)",
- Value: "",
- EnvVars: []string{"USERVOICE_KEY"},
- },
- &cli.StringFlag{
- Name: "provider",
- Usage: "s3|gdrive|local",
- Value: "",
- EnvVars: []string{"PROVIDER"},
- },
- &cli.StringFlag{
- Name: "s3-endpoint",
- Usage: "",
- Value: "",
- EnvVars: []string{"S3_ENDPOINT"},
- },
- &cli.StringFlag{
- Name: "s3-region",
- Usage: "",
- Value: "eu-west-1",
- EnvVars: []string{"S3_REGION"},
- },
- &cli.StringFlag{
- Name: "aws-access-key",
- Usage: "",
- Value: "",
- EnvVars: []string{"AWS_ACCESS_KEY"},
- },
- &cli.StringFlag{
- Name: "aws-secret-key",
- Usage: "",
- Value: "",
- EnvVars: []string{"AWS_SECRET_KEY"},
- },
- &cli.StringFlag{
- Name: "bucket",
- Usage: "",
- Value: "",
- EnvVars: []string{"BUCKET"},
- },
- &cli.BoolFlag{
- Name: "s3-no-multipart",
- Usage: "Disables S3 Multipart Puts",
- EnvVars: []string{"S3_NO_MULTIPART"},
- },
- &cli.BoolFlag{
- Name: "s3-path-style",
- Usage: "Forces path style URLs, required for Minio.",
- EnvVars: []string{"S3_PATH_STYLE"},
- },
- &cli.StringFlag{
- Name: "gdrive-client-json-filepath",
- Usage: "",
- Value: "",
- EnvVars: []string{"GDRIVE_CLIENT_JSON_FILEPATH"},
- },
- &cli.StringFlag{
- Name: "gdrive-local-config-path",
- Usage: "",
- Value: "",
- EnvVars: []string{"GDRIVE_LOCAL_CONFIG_PATH"},
- },
- &cli.IntFlag{
- Name: "gdrive-chunk-size",
- Usage: "",
- Value: googleapi.DefaultUploadChunkSize / 1024 / 1024,
- EnvVars: []string{"GDRIVE_CHUNK_SIZE"},
- },
- &cli.StringFlag{
- Name: "storj-access",
- Usage: "Access for the project",
- Value: "",
- EnvVars: []string{"STORJ_ACCESS"},
- },
- &cli.StringFlag{
- Name: "storj-bucket",
- Usage: "Bucket to use within the project",
- Value: "",
- EnvVars: []string{"STORJ_BUCKET"},
- },
- &cli.IntFlag{
- Name: "rate-limit",
- Usage: "requests per minute",
- Value: 0,
- EnvVars: []string{"RATE_LIMIT"},
- },
- &cli.IntFlag{
- Name: "purge-days",
- Usage: "number of days after uploads are purged automatically",
- Value: 0,
- EnvVars: []string{"PURGE_DAYS"},
- },
- &cli.IntFlag{
- Name: "purge-interval",
- Usage: "interval in hours to run the automatic purge for",
- Value: 0,
- EnvVars: []string{"PURGE_INTERVAL"},
- },
- &cli.Int64Flag{
- Name: "max-upload-size",
- Usage: "max limit for upload, in kilobytes",
- Value: 0,
- EnvVars: []string{"MAX_UPLOAD_SIZE"},
- },
- &cli.StringFlag{
- Name: "lets-encrypt-hosts",
- Usage: "host1, host2",
- Value: "",
- EnvVars: []string{"HOSTS"},
- },
- &cli.StringFlag{
- Name: "log",
- Usage: "/var/log/transfersh.log",
- Value: "",
- EnvVars: []string{"LOG"},
- },
- &cli.StringFlag{
- Name: "basedir",
- Usage: "path to storage",
- Value: "",
- EnvVars: []string{"BASEDIR"},
- },
- &cli.StringFlag{
- Name: "clamav-host",
- Usage: "clamav-host",
- Value: "",
- EnvVars: []string{"CLAMAV_HOST"},
- },
- &cli.BoolFlag{
- Name: "perform-clamav-prescan",
- Usage: "perform-clamav-prescan",
- EnvVars: []string{"PERFORM_CLAMAV_PRESCAN"},
- },
- &cli.StringFlag{
- Name: "virustotal-key",
- Usage: "virustotal-key",
- Value: "",
- EnvVars: []string{"VIRUSTOTAL_KEY"},
- },
- &cli.BoolFlag{
- Name: "profiler",
- Usage: "enable profiling",
- EnvVars: []string{"PROFILER"},
- },
- &cli.StringFlag{
- Name: "http-auth-user",
- Usage: "user for http basic auth",
- Value: "",
- EnvVars: []string{"HTTP_AUTH_USER"},
- },
- &cli.StringFlag{
- Name: "http-auth-pass",
- Usage: "pass for http basic auth",
- Value: "",
- EnvVars: []string{"HTTP_AUTH_PASS"},
- },
- &cli.StringFlag{
- Name: "http-auth-htpasswd",
- Usage: "htpasswd file http basic auth",
- Value: "",
- EnvVars: []string{"HTTP_AUTH_HTPASSWD"},
- },
- &cli.StringFlag{
- Name: "http-auth-ip-whitelist",
- Usage: "comma separated list of ips allowed to upload without being challenged an http auth",
- Value: "",
- EnvVars: []string{"HTTP_AUTH_IP_WHITELIST"},
- },
- &cli.StringFlag{
- Name: "ip-whitelist",
- Usage: "comma separated list of ips allowed to connect to the service",
- Value: "",
- EnvVars: []string{"IP_WHITELIST"},
- },
- &cli.StringFlag{
- Name: "ip-blacklist",
- Usage: "comma separated list of ips not allowed to connect to the service",
- Value: "",
- EnvVars: []string{"IP_BLACKLIST"},
- },
- &cli.StringFlag{
- Name: "cors-domains",
- Usage: "comma separated list of domains allowed for CORS requests",
- Value: "",
- EnvVars: []string{"CORS_DOMAINS"},
- },
- &cli.IntFlag{
- Name: "random-token-length",
- Usage: "",
- Value: 10,
- EnvVars: []string{"RANDOM_TOKEN_LENGTH"},
- },
- }
- // Cmd wraps cli.app
- type Cmd struct {
- *cli.App
- }
- func versionCommand(_ *cli.Context) error {
- fmt.Println(color.YellowString("transfer.sh %s: Easy file sharing from the command line", Version))
- return nil
- }
- // New is the factory for transfer.sh
- func New() *Cmd {
- logger := log.New(os.Stdout, "[transfer.sh]", log.LstdFlags)
- app := cli.NewApp()
- app.Name = "transfer.sh"
- app.Authors = []*cli.Author{}
- app.Usage = "transfer.sh"
- app.Description = `Easy file sharing from the command line`
- app.Version = Version
- app.Flags = globalFlags
- app.CustomAppHelpTemplate = helpTemplate
- app.Commands = []*cli.Command{
- {
- Name: "version",
- Action: versionCommand,
- },
- }
- app.Before = func(c *cli.Context) error {
- return nil
- }
- app.Action = func(c *cli.Context) error {
- var options []server.OptionFn
- if v := c.String("listener"); v != "" {
- options = append(options, server.Listener(v))
- }
- if v := c.String("cors-domains"); v != "" {
- options = append(options, server.CorsDomains(v))
- }
- if v := c.String("tls-listener"); v == "" {
- } else if c.Bool("tls-listener-only") {
- options = append(options, server.TLSListener(v, true))
- } else {
- options = append(options, server.TLSListener(v, false))
- }
- if v := c.String("profile-listener"); v != "" {
- options = append(options, server.ProfileListener(v))
- }
- if v := c.String("web-path"); v != "" {
- options = append(options, server.WebPath(v))
- }
- if v := c.String("proxy-path"); v != "" {
- options = append(options, server.ProxyPath(v))
- }
- if v := c.String("proxy-port"); v != "" {
- options = append(options, server.ProxyPort(v))
- }
- if v := c.String("email-contact"); v != "" {
- options = append(options, server.EmailContact(v))
- }
- if v := c.String("ga-key"); v != "" {
- options = append(options, server.GoogleAnalytics(v))
- }
- if v := c.String("uservoice-key"); v != "" {
- options = append(options, server.UserVoice(v))
- }
- if v := c.String("temp-path"); v != "" {
- options = append(options, server.TempPath(v))
- }
- if v := c.String("log"); v != "" {
- options = append(options, server.LogFile(logger, v))
- } else {
- options = append(options, server.Logger(logger))
- }
- if v := c.String("lets-encrypt-hosts"); v != "" {
- options = append(options, server.UseLetsEncrypt(strings.Split(v, ",")))
- }
- if v := c.String("virustotal-key"); v != "" {
- options = append(options, server.VirustotalKey(v))
- }
- if v := c.String("clamav-host"); v != "" {
- options = append(options, server.ClamavHost(v))
- }
- if v := c.Bool("perform-clamav-prescan"); v {
- if c.String("clamav-host") == "" {
- return errors.New("clamav-host not set")
- }
- options = append(options, server.PerformClamavPrescan(v))
- }
- if v := c.Int64("max-upload-size"); v > 0 {
- options = append(options, server.MaxUploadSize(v))
- }
- if v := c.Int("rate-limit"); v > 0 {
- options = append(options, server.RateLimit(v))
- }
- v := c.Int("random-token-length")
- options = append(options, server.RandomTokenLength(v))
- purgeDays := c.Int("purge-days")
- purgeInterval := c.Int("purge-interval")
- if purgeDays > 0 && purgeInterval > 0 {
- options = append(options, server.Purge(purgeDays, purgeInterval))
- }
- if cert := c.String("tls-cert-file"); cert == "" {
- } else if pk := c.String("tls-private-key"); pk == "" {
- } else {
- options = append(options, server.TLSConfig(cert, pk))
- }
- if c.Bool("profiler") {
- options = append(options, server.EnableProfiler())
- }
- if c.Bool("force-https") {
- options = append(options, server.ForceHTTPS())
- }
- if httpAuthUser := c.String("http-auth-user"); httpAuthUser == "" {
- } else if httpAuthPass := c.String("http-auth-pass"); httpAuthPass == "" {
- } else {
- options = append(options, server.HTTPAuthCredentials(httpAuthUser, httpAuthPass))
- }
- if httpAuthHtpasswd := c.String("http-auth-htpasswd"); httpAuthHtpasswd != "" {
- options = append(options, server.HTTPAuthHtpasswd(httpAuthHtpasswd))
- }
- if httpAuthIPWhitelist := c.String("http-auth-ip-whitelist"); httpAuthIPWhitelist != "" {
- ipFilterOptions := server.IPFilterOptions{}
- ipFilterOptions.AllowedIPs = strings.Split(httpAuthIPWhitelist, ",")
- ipFilterOptions.BlockByDefault = true
- options = append(options, server.HTTPAUTHFilterOptions(ipFilterOptions))
- }
- applyIPFilter := false
- ipFilterOptions := server.IPFilterOptions{}
- if ipWhitelist := c.String("ip-whitelist"); ipWhitelist != "" {
- applyIPFilter = true
- ipFilterOptions.AllowedIPs = strings.Split(ipWhitelist, ",")
- ipFilterOptions.BlockByDefault = true
- }
- if ipBlacklist := c.String("ip-blacklist"); ipBlacklist != "" {
- applyIPFilter = true
- ipFilterOptions.BlockedIPs = strings.Split(ipBlacklist, ",")
- }
- if applyIPFilter {
- options = append(options, server.FilterOptions(ipFilterOptions))
- }
- switch provider := c.String("provider"); provider {
- case "s3":
- if accessKey := c.String("aws-access-key"); accessKey == "" {
- return errors.New("access-key not set.")
- } else if secretKey := c.String("aws-secret-key"); secretKey == "" {
- return errors.New("secret-key not set.")
- } else if bucket := c.String("bucket"); bucket == "" {
- return errors.New("bucket not set.")
- } else if store, err := storage.NewS3Storage(c.Context, accessKey, secretKey, bucket, purgeDays, c.String("s3-region"), c.String("s3-endpoint"), c.Bool("s3-no-multipart"), c.Bool("s3-path-style"), logger); err != nil {
- return err
- } else {
- options = append(options, server.UseStorage(store))
- }
- case "gdrive":
- chunkSize := c.Int("gdrive-chunk-size") * 1024 * 1024
- if clientJSONFilepath := c.String("gdrive-client-json-filepath"); clientJSONFilepath == "" {
- return errors.New("gdrive-client-json-filepath not set.")
- } else if localConfigPath := c.String("gdrive-local-config-path"); localConfigPath == "" {
- return errors.New("gdrive-local-config-path not set.")
- } else if basedir := c.String("basedir"); basedir == "" {
- return errors.New("basedir not set.")
- } else if store, err := storage.NewGDriveStorage(c.Context, clientJSONFilepath, localConfigPath, basedir, chunkSize, logger); err != nil {
- return err
- } else {
- options = append(options, server.UseStorage(store))
- }
- case "storj":
- if access := c.String("storj-access"); access == "" {
- return errors.New("storj-access not set.")
- } else if bucket := c.String("storj-bucket"); bucket == "" {
- return errors.New("storj-bucket not set.")
- } else if store, err := storage.NewStorjStorage(c.Context, access, bucket, purgeDays, logger); err != nil {
- return err
- } else {
- options = append(options, server.UseStorage(store))
- }
- case "local":
- if v := c.String("basedir"); v == "" {
- return errors.New("basedir not set.")
- } else if store, err := storage.NewLocalStorage(v, logger); err != nil {
- return err
- } else {
- options = append(options, server.UseStorage(store))
- }
- default:
- return errors.New("Provider not set or invalid.")
- }
- srvr, err := server.New(
- options...,
- )
- if err != nil {
- logger.Println(color.RedString("Error starting server: %s", err.Error()))
- return err
- }
- srvr.Run()
- return nil
- }
- return &Cmd{
- App: app,
- }
- }
|