From 2fd20db19b908e5cb8da28d993238cc62391b057 Mon Sep 17 00:00:00 2001 From: ungrentquest Date: Sat, 19 Apr 2025 23:11:19 +0000 Subject: [PATCH 1/3] Adopt cobra & viper. Define build sign and serve subcommands --- builder/build.go | 4 +- builder/feed/feed.go | 4 +- cmd/build.go | 120 +++++++++++++++++ cmd/root.go | 66 ++++++++++ cmd/serve.go | 90 +++++++++++++ cmd/sign.go | 86 +++++++++++++ config/config.go | 21 +++ go.mod | 15 +++ go.sum | 42 +++++- main.go | 298 +------------------------------------------ server/serve.go | 4 +- 11 files changed, 447 insertions(+), 303 deletions(-) create mode 100644 cmd/build.go create mode 100644 cmd/root.go create mode 100644 cmd/serve.go create mode 100644 cmd/sign.go create mode 100644 config/config.go diff --git a/builder/build.go b/builder/build.go index 8040d30..d9b7716 100644 --- a/builder/build.go +++ b/builder/build.go @@ -6,9 +6,9 @@ import ( "io/ioutil" "time" + newsfeed "github.com/go-i2p/newsgo/builder/feed" "github.com/google/uuid" "github.com/yosssi/gohtml" - newsfeed "github.com/go-i2p/newsgo/builder/feed" ) type NewsBuilder struct { @@ -101,7 +101,7 @@ func (nb *NewsBuilder) Build() (string, error) { return gohtml.Format(str), nil } -func Builder(newsFile, releasesJson, blocklistXML string) *NewsBuilder { +func Builder(newsFile string, releasesJson string, blocklistXML string) *NewsBuilder { nb := &NewsBuilder{ Feed: newsfeed.Feed{ EntriesHTMLPath: newsFile, diff --git a/builder/feed/feed.go b/builder/feed/feed.go index ed64a62..bc2f55f 100644 --- a/builder/feed/feed.go +++ b/builder/feed/feed.go @@ -18,7 +18,7 @@ type Feed struct { func (f *Feed) LoadHTML() error { data, err := ioutil.ReadFile(f.EntriesHTMLPath) if err != nil { - return fmt.Errorf("LoadHTML: error", err) + return fmt.Errorf("loadHTML: error %s", err) } f.doc = soup.HTMLParse(string(data)) f.HeaderTitle = f.doc.Find("header").FullText() @@ -29,7 +29,7 @@ func (f *Feed) LoadHTML() error { if f.BaseEntriesHTMLPath != "" { data, err := ioutil.ReadFile(f.BaseEntriesHTMLPath) if err != nil { - return fmt.Errorf("LoadHTML: error", err) + return fmt.Errorf("loadHTML: error %s", err) } f.doc = soup.HTMLParse(string(data)) f.HeaderTitle = f.doc.Find("header").FullText() diff --git a/cmd/build.go b/cmd/build.go new file mode 100644 index 0000000..e03cf54 --- /dev/null +++ b/cmd/build.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + builder "github.com/go-i2p/newsgo/builder" + "github.com/go-i2p/onramp" + "github.com/google/uuid" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// buildCmd represents the build command +var buildCmd = &cobra.Command{ + Use: "build", + Short: "Build newsfeeds from XML", + Run: func(cmd *cobra.Command, args []string) { + // For some reason this is the only way passing booleans from cobra to viper works + viper.GetViper().Set("i2p", i2p) + + viper.WriteConfigTo(os.Stdout) + viper.Unmarshal(c) + data, _ := json.MarshalIndent(&c, " ", "") + fmt.Print(string(data[:])) + + os.Exit(0) + + f, e := os.Stat(c.NewsFile) + if e != nil { + panic(e) + } + if f.IsDir() { + err := filepath.Walk(c.NewsFile, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + ext := filepath.Ext(path) + if ext == ".html" { + build(path) + } + return nil + }) + if err != nil { + log.Println(err) + } + } else { + build(c.NewsFile) + } + + }, +} + +func init() { + rootCmd.AddCommand(buildCmd) + buildCmd.Flags().String("newsfile", "data", "entries to pass to news generator. If passed a directory, all 'entries.html' files in the directory will be processed") + buildCmd.Flags().String("blocklist", "data/blocklist.xml", "block list file to pass to news generator") + buildCmd.Flags().String("releasejson", "data/releases.json", "json file describing an update to pass to news generator") + buildCmd.Flags().String("feedtitle", "I2P News", "title to use for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedsubtitle", "News feed, and router updates", "subtitle to use for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedsite", "http://i2p-projekt.i2p", "site for the RSS feed to pass to news generator") + buildCmd.Flags().String("feedmain", defaultFeedURL(), "Primary newsfeed for updates to pass to news generator") + buildCmd.Flags().String("feedbackup", "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/news.atom.xml", "Backup newsfeed for updates to pass to news generator") + buildCmd.Flags().String("feeduid", "", "UUID to use for the RSS feed to pass to news generator. Random if omitted") + buildCmd.Flags().String("builddir", "build", "Build directory to output feeds to") + buildCmd.Flags().BoolVar(&i2p, "i2p", false, "Enable I2P support") + + viper.BindPFlags(buildCmd.Flags()) + +} + +func defaultFeedURL() string { + if !c.I2P { + return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" + } + garlic := &onramp.Garlic{} + defer garlic.Close() + ln, err := garlic.Listen() + if err != nil { + return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" + } + defer ln.Close() + return "http://" + ln.Addr().String() + "/news.atom.xml" +} + +func build(newsFile string) { + news := builder.Builder(newsFile, c.ReleaseJsonFile, c.BlockList) + news.TITLE = c.FeedTitle + news.SITEURL = c.FeedSite + news.MAINFEED = c.FeedMain + news.BACKUPFEED = c.FeedBackup + news.SUBTITLE = c.FeedSubtitle + if c.FeedUuid == "" { + news.URNID = c.FeedUuid + } else { + news.URNID = uuid.NewString() + } + + base := filepath.Join(newsFile, "entries.html") + if newsFile != base { + news.Feed.BaseEntriesHTMLPath = base + } + if feed, err := news.Build(); err != nil { + log.Printf("Build error: %s", err) + } else { + filename := strings.Replace(strings.Replace(strings.Replace(strings.Replace(c.NewsFile, ".html", ".atom.xml", -1), "entries.", "news_", -1), "translations", "", -1), "news_atom", "news.atom", -1) + if err := os.MkdirAll(filepath.Join(c.BuildDir, filepath.Dir(filename)), 0755); err != nil { + panic(err) + } + if err = ioutil.WriteFile(filepath.Join(c.BuildDir, filename), []byte(feed), 0644); err != nil { + panic(err) + } + } +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..a61e947 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + "os" + "strings" + + "github.com/go-i2p/newsgo/config" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string +var i2p bool +var c *config.Conf = &config.Conf{} + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "newsgo", + Short: "I2P News Server Tool/Library. A whole lot faster than the python one. Otherwise compatible", +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.newsgo.yaml)") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".newsgo" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".newsgo") + } + + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } + +} diff --git a/cmd/serve.go b/cmd/serve.go new file mode 100644 index 0000000..34b7976 --- /dev/null +++ b/cmd/serve.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "log" + "net" + "net/http" + "os" + "os/signal" + "time" + + server "github.com/go-i2p/newsgo/server" + "github.com/go-i2p/onramp" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// serveCmd represents the serve command +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "Serve newsfeeds from a directory", + Run: func(cmd *cobra.Command, args []string) { + + viper.Unmarshal(c) + s := server.Serve(c.NewsDir, c.StatsFile) + if c.Http != "" { + go func() { + if err := serve(s); err != nil { + panic(err) + } + }() + } + if c.SamAddr != "" { + go func() { + if err := serveI2P(s); err != nil { + panic(err) + } + }() + } + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for sig := range c { + log.Println("captured: ", sig) + s.Stats.Save() + os.Exit(0) + } + }() + i := 0 + for { + time.Sleep(time.Minute) + log.Printf("Running for %d minutes.", i) + i++ + } + + }, +} + +func init() { + rootCmd.AddCommand(serveCmd) + + serveCmd.Flags().String("newsdir", "build", "directory to serve news from") + serveCmd.Flags().String("statsfile", "build/stats.json", "file to store stats in") + serveCmd.Flags().String("http", "127.0.0.1:9696", "listen for HTTP requests. Empty string to disable") + serveCmd.Flags().String("samaddr", onramp.SAM_ADDR, "SAMv3 gateway address. Empty string to disable") + + viper.BindPFlags(serveCmd.Flags()) + +} + +func serveI2P(s *server.NewsServer) error { + garlic, err := onramp.NewGarlic("newsgo", c.SamAddr, make([]string, 0)) + if err != nil { + return err + } + defer garlic.Close() + ln, err := garlic.Listen() + if err != nil { + return err + } + defer ln.Close() + return http.Serve(ln, s) +} + +func serve(s *server.NewsServer) error { + ln, err := net.Listen("tcp", c.Http) + if err != nil { + return err + } + return http.Serve(ln, s) +} diff --git a/cmd/sign.go b/cmd/sign.go new file mode 100644 index 0000000..c4e257a --- /dev/null +++ b/cmd/sign.go @@ -0,0 +1,86 @@ +package cmd + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "io/ioutil" + "log" + "os" + "path/filepath" + + signer "github.com/go-i2p/newsgo/signer" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// signCmd represents the sign command +var signCmd = &cobra.Command{ + Use: "sign", + Short: "Sign newsfeeds with local keys", + Run: func(cmd *cobra.Command, args []string) { + viper.Unmarshal(c) + + f, e := os.Stat(c.NewsFile) + if e != nil { + panic(e) + } + if f.IsDir() { + err := filepath.Walk(c.NewsFile, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + ext := filepath.Ext(path) + if ext == ".html" { + Sign(path) + } + return nil + }) + if err != nil { + log.Println(err) + } + } else { + Sign(c.NewsFile) + } + + }, +} + +func init() { + rootCmd.AddCommand(signCmd) + + // Here you will define your flags and configuration settings. + + signCmd.Flags().String("signerid", "null@example.i2p", "ID to use when signing the news") + signCmd.Flags().String("signingkey", "signing_key.pem", "Path to a signing key") + + viper.BindPFlags(signCmd.Flags()) +} + +func loadPrivateKey(path string) (*rsa.PrivateKey, error) { + privPem, err := ioutil.ReadFile(path) + if nil != err { + return nil, err + } + + privDer, _ := pem.Decode(privPem) + privKey, err := x509.ParsePKCS1PrivateKey(privDer.Bytes) + if nil != err { + return nil, err + } + + return privKey, nil +} + +func Sign(xmlfeed string) error { + sk, err := loadPrivateKey(c.SigningKey) + if err != nil { + return err + } + signer := signer.NewsSigner{ + SignerID: c.SignerId, + SigningKey: sk, + } + return signer.CreateSu3(xmlfeed) +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..e960cf1 --- /dev/null +++ b/config/config.go @@ -0,0 +1,21 @@ +package config + +type Conf struct { + NewsDir string + StatsFile string + I2P bool + Http string + SamAddr string + NewsFile string + BlockList string + ReleaseJsonFile string + FeedTitle string + FeedSubtitle string + FeedSite string + FeedMain string + FeedBackup string + FeedUuid string + BuildDir string + SignerId string + SigningKey string +} diff --git a/go.mod b/go.mod index 728356c..9903b41 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/anaskhan96/soup v1.2.5 github.com/go-i2p/onramp v0.33.92 github.com/google/uuid v1.6.0 + github.com/spf13/cobra v1.9.1 + github.com/spf13/viper v1.20.1 github.com/wcharczuk/go-chart/v2 v2.1.2 github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 gitlab.com/golang-commonmark/markdown v0.0.0-20211110145824-bf3e522c626a @@ -16,17 +18,30 @@ require ( require ( github.com/cretz/bine v0.2.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-i2p/i2pkeys v0.33.92 // indirect github.com/go-i2p/sam3 v0.33.92 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181 // indirect gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 // indirect gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84 // indirect gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/image v0.25.0 // indirect golang.org/x/net v0.37.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c4ac832..da202ce 100644 --- a/go.sum +++ b/go.sum @@ -81,6 +81,7 @@ github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobe github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -116,8 +117,12 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= @@ -151,6 +156,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -189,6 +196,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -248,6 +256,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -272,8 +282,12 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= @@ -344,6 +358,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -381,6 +397,8 @@ github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxz github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk= github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -388,6 +406,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -399,18 +419,30 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -424,9 +456,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/throttled/throttled/v2 v2.7.1/go.mod h1:fuOeyK9fmnA+LQnsBbfT/mmPHjmkdogRBQxaD8YsgZ8= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip/v6 v6.6.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= @@ -473,7 +508,11 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -784,6 +823,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/main.go b/main.go index 4125997..5af95e5 100644 --- a/main.go +++ b/main.go @@ -1,301 +1,7 @@ package main -import ( - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "flag" - "fmt" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "os/signal" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/go-i2p/onramp" - "github.com/google/uuid" - builder "github.com/go-i2p/newsgo/builder" - server "github.com/go-i2p/newsgo/server" - signer "github.com/go-i2p/newsgo/signer" -) - -func loadPrivateKey(path string) (*rsa.PrivateKey, error) { - privPem, err := ioutil.ReadFile(path) - if nil != err { - return nil, err - } - - privDer, _ := pem.Decode(privPem) - privKey, err := x509.ParsePKCS1PrivateKey(privDer.Bytes) - if nil != err { - return nil, err - } - - return privKey, nil -} - -func Sign(xmlfeed string) error { - sk, err := loadPrivateKey(*signingkey) - if err != nil { - return err - } - signer := signer.NewsSigner{ - SignerID: *signerid, - SigningKey: sk, - } - return signer.CreateSu3(xmlfeed) -} - -var ( - serve = flag.String("command", "help", "command to run(may be `serve`,`build`,`sign`, or `help`(default)") - dir = flag.String("newsdir", "build", "directory to serve news from") - statsfile = flag.String("statsfile", "build/stats.json", "file to store stats in") - host = flag.String("host", "127.0.0.1", "host to serve on") - port = flag.String("port", "9696", "port to serve on") - i2p = flag.Bool("i2p", isSamAround(), "automatically co-host on an I2P service using SAMv3") - tcp = flag.Bool("http", true, "host on an HTTP service at host:port") - //newsfile = flag.String("newsfile", "data/entries.html", "entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - newsfile = flag.String("newsfile", "data", "entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - bloclist = flag.String("blocklist", "data/blocklist.xml", "block list file to pass to news generator") - releasejson = flag.String("releasejson", "data/releases.json", "json file describing an update to pass to news generator") - title = flag.String("feedtitle", "I2P News", "title to use for the RSS feed to pass to news generator") - subtitle = flag.String("feedsubtitle", "News feed, and router updates", "subtitle to use for the RSS feed to pass to news generator") - site = flag.String("feedsite", "http://i2p-projekt.i2p", "site for the RSS feed to pass to news generator") - mainurl = flag.String("feedmain", DefaultFeedURL(), "Primary newsfeed for updates to pass to news generator") - backupurl = flag.String("feedbackup", "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/news.atom.xml", "Backup newsfeed for updates to pass to news generator") - urn = flag.String("feeduid", uuid.New().String(), "UUID to use for the RSS feed to pass to news generator") - builddir = flag.String("builddir", "build", "Build directory to output feeds to.") - signerid = flag.String("signerid", "null@example.i2p", "ID to use when signing the news") - signingkey = flag.String("signingkey", "signing_key.pem", "Path to a signing key") -) - -func validatePort(s *string) { - _, err := strconv.Atoi(*s) - if err != nil { - log.Println("Port is invalid") - os.Exit(1) - } -} - -func validateCommand(s *string) string { - switch *s { - case "serve": - return "serve" - case "build": - return "build" - case "sign": - return "sign" - default: - return "help" - } -} - -func Help() { - fmt.Println("newsgo") - fmt.Println("======") - fmt.Println("") - fmt.Println("I2P News Server Tool/Library. A whole lot faster than the python one. Otherwise compatible.") - fmt.Println("") - fmt.Println("Usage") - fmt.Println("-----") - fmt.Println("") - fmt.Println("./newsgo -command $command -newsdir $news_directory -statsfile $news_stats_file") - fmt.Println("") - fmt.Println("### Commands") - fmt.Println("") - fmt.Println(" - serve: Serve newsfeeds from a directory") - fmt.Println(" - build: Build newsfeeds from XML") - fmt.Println(" - sign: Sign newsfeeds with local keys") - fmt.Println("") - fmt.Println("### Options") - fmt.Println("") - fmt.Println("Use these options to configure the software") - fmt.Println("") - fmt.Println("#### Server Options(use with `serve`)") - fmt.Println("") - fmt.Println(" - `-newsdir`: directory to serve newsfeed from") - fmt.Println(" - `-statsfile`: file to store the stats in, in json format") - fmt.Println(" - `-host`: host to serve news files on") - fmt.Println(" - `-port`: port to serve news files on") - fmt.Println(" - `-http`: serve news on host:port using HTTP") - fmt.Println(" - `-i2p`: serve news files directly to I2P using SAMv3") - fmt.Println("") - fmt.Println("#### Builder Options(use with `build`)") - fmt.Println("") - fmt.Println(" - `-newsfile`: entries to pass to news generator. If passed a directory, all `entries.html` files in the directory will be processed") - fmt.Println(" - `-blockfile`: block list file to pass to news generator") - fmt.Println(" - `-releasejson`: json file describing an update to pass to news generator") - fmt.Println(" - `-feedtitle`: title to use for the RSS feed to pass to news generator") - fmt.Println(" - `-feedsubtitle`: subtitle to use for the RSS feed to pass to news generator") - fmt.Println(" - `-feedsite`: site for the RSS feed to pass to news generator") - fmt.Println(" - `-feedmain`: Primary newsfeed for updates to pass to news generator") - fmt.Println(" - `-feedbackup`: Backup newsfeed for updates to pass to news generator") - fmt.Println(" - `-feeduri`: UUID to use for the RSS feed to pass to news generator") - fmt.Println(" - `-builddir`: directory to output XML files in") - fmt.Println("") - fmt.Println("#### Signer Options(use with `sign`)") - fmt.Println("") - fmt.Println(" - `-signerid`: ID of the news signer") - fmt.Println(" - `-signingkey`: path to the signing key") -} - -func Serve(host, port string, s *server.NewsServer) error { - ln, err := net.Listen("tcp", net.JoinHostPort(host, port)) - if err != nil { - return err - } - return http.Serve(ln, s) -} - -func ServeI2P(s *server.NewsServer) error { - garlic := &onramp.Garlic{} - defer garlic.Close() - ln, err := garlic.Listen() - if err != nil { - return err - } - defer ln.Close() - return http.Serve(ln, s) -} - -func isSamAround() bool { - ln, err := net.Listen("tcp", "127.0.0.1:7656") - if err != nil { - return true - } - ln.Close() - return false -} - -func DefaultFeedURL() string { - if !isSamAround() { - return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" - } - garlic := &onramp.Garlic{} - defer garlic.Close() - ln, err := garlic.Listen() - if err != nil { - return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" - } - defer ln.Close() - return "http://" + ln.Addr().String() + "/news.atom.xml" -} - -func Build(newsFile string) { - news := builder.Builder(newsFile, *releasejson, *bloclist) - news.TITLE = *title - news.SITEURL = *site - news.MAINFEED = *mainurl - news.BACKUPFEED = *backupurl - news.SUBTITLE = *subtitle - news.URNID = *urn - base := filepath.Join(*newsfile, "entries.html") - if newsFile != base { - news.Feed.BaseEntriesHTMLPath = base - } - if feed, err := news.Build(); err != nil { - log.Printf("Build error: %s", err) - } else { - filename := strings.Replace(strings.Replace(strings.Replace(strings.Replace(newsFile, ".html", ".atom.xml", -1), "entries.", "news_", -1), "translations", "", -1), "news_atom", "news.atom", -1) - if err := os.MkdirAll(filepath.Join(*builddir, filepath.Dir(filename)), 0755); err != nil { - panic(err) - } - if err = ioutil.WriteFile(filepath.Join(*builddir, filename), []byte(feed), 0644); err != nil { - panic(err) - } - } -} +import "github.com/go-i2p/newsgo/cmd" func main() { - flag.Parse() - command := validateCommand(serve) - validatePort(port) - switch command { - case "serve": - s := server.Serve(*dir, *statsfile) - if *tcp { - go func() { - if err := Serve(*host, *port, s); err != nil { - panic(err) - } - }() - } - if *i2p { - go func() { - if err := ServeI2P(s); err != nil { - panic(err) - } - }() - } - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - go func() { - for sig := range c { - log.Println("captured: ", sig) - s.Stats.Save() - os.Exit(0) - } - }() - i := 0 - for { - time.Sleep(time.Minute) - log.Printf("Running for %d minutes.", i) - i++ - } - case "build": - f, e := os.Stat(*newsfile) - if e != nil { - panic(e) - } - if f.IsDir() { - err := filepath.Walk(*newsfile, - func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - ext := filepath.Ext(path) - if ext == ".html" { - Build(path) - } - return nil - }) - if err != nil { - log.Println(err) - } - } else { - Build(*newsfile) - } - case "sign": - f, e := os.Stat(*newsfile) - if e != nil { - panic(e) - } - if f.IsDir() { - err := filepath.Walk(*newsfile, - func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - ext := filepath.Ext(path) - if ext == ".html" { - Sign(path) - } - return nil - }) - if err != nil { - log.Println(err) - } - } else { - Sign(*newsfile) - } - case "help": - Help() - default: - Help() - } + cmd.Execute() } diff --git a/server/serve.go b/server/serve.go index 0fd5b5b..056ee0a 100644 --- a/server/serve.go +++ b/server/serve.go @@ -10,8 +10,8 @@ import ( "path/filepath" "strings" - "gitlab.com/golang-commonmark/markdown" stats "github.com/go-i2p/newsgo/server/stats" + "gitlab.com/golang-commonmark/markdown" ) type NewsServer struct { @@ -144,7 +144,7 @@ func (n *NewsServer) ServeFile(file string, rq *http.Request, rw http.ResponseWr return nil } -func Serve(newsDir, newsStats string) *NewsServer { +func Serve(newsDir string, newsStats string) *NewsServer { s := &NewsServer{ NewsDir: newsDir, Stats: stats.NewsStats{ From 10d4baefaa0e89f17df77ca53734de336def347c Mon Sep 17 00:00:00 2001 From: ungrentquest Date: Sun, 20 Apr 2025 21:53:37 +0000 Subject: [PATCH 2/3] remove accidentally commited debug code. fix ioutil deprecations --- cmd/build.go | 12 +----------- cmd/sign.go | 3 +-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index e03cf54..d48d738 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -1,9 +1,6 @@ package cmd import ( - "encoding/json" - "fmt" - "io/ioutil" "log" "os" "path/filepath" @@ -24,13 +21,6 @@ var buildCmd = &cobra.Command{ // For some reason this is the only way passing booleans from cobra to viper works viper.GetViper().Set("i2p", i2p) - viper.WriteConfigTo(os.Stdout) - viper.Unmarshal(c) - data, _ := json.MarshalIndent(&c, " ", "") - fmt.Print(string(data[:])) - - os.Exit(0) - f, e := os.Stat(c.NewsFile) if e != nil { panic(e) @@ -113,7 +103,7 @@ func build(newsFile string) { if err := os.MkdirAll(filepath.Join(c.BuildDir, filepath.Dir(filename)), 0755); err != nil { panic(err) } - if err = ioutil.WriteFile(filepath.Join(c.BuildDir, filename), []byte(feed), 0644); err != nil { + if err = os.WriteFile(filepath.Join(c.BuildDir, filename), []byte(feed), 0644); err != nil { panic(err) } } diff --git a/cmd/sign.go b/cmd/sign.go index c4e257a..f101576 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -4,7 +4,6 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "io/ioutil" "log" "os" "path/filepath" @@ -59,7 +58,7 @@ func init() { } func loadPrivateKey(path string) (*rsa.PrivateKey, error) { - privPem, err := ioutil.ReadFile(path) + privPem, err := os.ReadFile(path) if nil != err { return nil, err } From 5a3788ddbc08d432e884119a29621a3ae2548f53 Mon Sep 17 00:00:00 2001 From: ungrentquest Date: Thu, 24 Apr 2025 22:28:51 +0000 Subject: [PATCH 3/3] revise build cmd i2p arg handing, drop --i2p flag and follow serve pattern instead. Pass default args to NewGarlic func --- cmd/build.go | 8 +++----- cmd/root.go | 1 - cmd/serve.go | 2 +- config/config.go | 1 - 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index d48d738..f382ad7 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -18,8 +18,6 @@ var buildCmd = &cobra.Command{ Use: "build", Short: "Build newsfeeds from XML", Run: func(cmd *cobra.Command, args []string) { - // For some reason this is the only way passing booleans from cobra to viper works - viper.GetViper().Set("i2p", i2p) f, e := os.Stat(c.NewsFile) if e != nil { @@ -59,17 +57,17 @@ func init() { buildCmd.Flags().String("feedbackup", "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/news.atom.xml", "Backup newsfeed for updates to pass to news generator") buildCmd.Flags().String("feeduid", "", "UUID to use for the RSS feed to pass to news generator. Random if omitted") buildCmd.Flags().String("builddir", "build", "Build directory to output feeds to") - buildCmd.Flags().BoolVar(&i2p, "i2p", false, "Enable I2P support") + serveCmd.Flags().String("samaddr", onramp.SAM_ADDR, "SAMv3 gateway address. Empty string to disable") viper.BindPFlags(buildCmd.Flags()) } func defaultFeedURL() string { - if !c.I2P { + if c.SamAddr == "" { return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.atom.xml" } - garlic := &onramp.Garlic{} + garlic, _ := onramp.NewGarlic("newsgo", c.SamAddr, onramp.OPT_DEFAULTS) defer garlic.Close() ln, err := garlic.Listen() if err != nil { diff --git a/cmd/root.go b/cmd/root.go index a61e947..512f9c4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -11,7 +11,6 @@ import ( ) var cfgFile string -var i2p bool var c *config.Conf = &config.Conf{} // rootCmd represents the base command when called without any subcommands diff --git a/cmd/serve.go b/cmd/serve.go index 34b7976..defd4e2 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -68,7 +68,7 @@ func init() { } func serveI2P(s *server.NewsServer) error { - garlic, err := onramp.NewGarlic("newsgo", c.SamAddr, make([]string, 0)) + garlic, err := onramp.NewGarlic("newsgo", c.SamAddr, onramp.OPT_DEFAULTS) if err != nil { return err } diff --git a/config/config.go b/config/config.go index e960cf1..322771d 100644 --- a/config/config.go +++ b/config/config.go @@ -3,7 +3,6 @@ package config type Conf struct { NewsDir string StatsFile string - I2P bool Http string SamAddr string NewsFile string