Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e7b711a65 | ||
|
|
03a40a7905 | ||
|
|
468184528a | ||
|
|
caa8356f96 | ||
|
|
55cecee87c | ||
|
|
9452295b69 | ||
|
|
3eaa3e545c | ||
|
|
d94e6db309 | ||
|
|
03c7ee8301 | ||
|
|
bb1c2263ab | ||
|
|
d5c3013861 | ||
|
|
82cead1e3e | ||
|
|
7f6c6a4cb3 | ||
|
|
fb9985e65c | ||
|
|
e5f50aa62e | ||
|
|
0b4bdaa68b | ||
|
|
e2b228042b | ||
|
|
cd6a54b994 | ||
|
|
7dd13b15a4 | ||
|
|
c9da9a9dcb | ||
|
|
b324b057bc | ||
|
|
c0495df940 |
@@ -1,3 +1,7 @@
|
||||
2024-06-29
|
||||
* app.Version = 2.5
|
||||
* Add password-protected netDb sync capability
|
||||
|
||||
2024-06-25
|
||||
* app.Version = 2.4
|
||||
* Remove dependency on libp2p
|
||||
|
||||
61
Makefile
61
Makefile
@@ -1,11 +1,13 @@
|
||||
|
||||
VERSION=0.2.34
|
||||
VERSION=0.3.2
|
||||
APP=reseed-tools
|
||||
USER_GH=eyedeekay
|
||||
SIGNER=hankhill19580@gmail.com
|
||||
CGO_ENABLED=0
|
||||
export CGO_ENABLED=0
|
||||
PLUGIN_PORT=7671
|
||||
export PLUGIN_PORT=7671
|
||||
prefix?=/
|
||||
|
||||
GOOS?=$(shell uname -s | tr A-Z a-z)
|
||||
GOARCH?="amd64"
|
||||
@@ -23,11 +25,14 @@ WHOAMI=$(shell whoami)
|
||||
echo:
|
||||
@echo "type make version to do release $(APP) $(VERSION) $(GOOS) $(GOARCH) $(MIN_GO_VERSION) $(I2P_UID) $(I2P_GID)"
|
||||
|
||||
host:
|
||||
/usr/bin/go build -o reseed-tools-host
|
||||
|
||||
index:
|
||||
edgar
|
||||
|
||||
build:
|
||||
go build $(ARG) -o reseed-tools-$(GOOS)-$(GOARCH)
|
||||
/usr/bin/go build $(ARG) -o reseed-tools-$(GOOS)-$(GOARCH)
|
||||
|
||||
1.15-build: gofmt
|
||||
/usr/lib/go-$(MIN_GO_VERSION)/bin/go build $(ARG) -o reseed-tools-$(GOOS)-$(GOARCH)
|
||||
@@ -36,31 +41,27 @@ clean:
|
||||
rm reseed-tools-* tmp -rfv *.deb plugin reseed-tools
|
||||
|
||||
tar:
|
||||
tar --exclude="./.git" --exclude="./tmp" --exclude=".vscode" --exclude="./*.pem" --exclude="./*.crl" --exclude="./*.crt" -cvf ../reseed-tools.tar.xz .
|
||||
git archive --format=tar.gz --output=reseed-tools.tar.gz v$(VERSION)
|
||||
|
||||
install:
|
||||
install -m755 reseed-tools-$(GOOS)-$(GOARCH) /usr/bin/reseed-tools
|
||||
install -m644 etc/default/reseed /etc/default/reseed
|
||||
install -m755 etc/init.d/reseed /etc/init.d/reseed
|
||||
mkdir -p /etc/systemd/system/reseed.service.d/
|
||||
mkdir -p /var/lib/i2p/
|
||||
mkdir -p /var/lib/i2p/i2p-config/reseed/
|
||||
install -g i2psvc -o i2psvc -d /var/lib/i2p/i2p-config/reseed/
|
||||
cp -r reseed/content /var/lib/i2p/i2p-config/reseed/content
|
||||
chown -R i2psvc:i2psvc /var/lib/i2p/i2p-config/reseed/
|
||||
install -m644 etc/systemd/system/reseed.service.d/override.conf /etc/systemd/system/reseed.service.d/override.conf
|
||||
install -m644 etc/systemd/system/reseed.service /etc/systemd/system/reseed.service
|
||||
install -m755 reseed-tools-$(GOOS)-$(GOARCH) ${prefix}usr/bin/reseed-tools
|
||||
install -m644 etc/default/reseed ${prefix}etc/default/reseed
|
||||
install -m755 etc/init.d/reseed ${prefix}etc/init.d/reseed
|
||||
install -g i2psvc -o i2psvc -D -d ${prefix}var/lib/i2p/i2p-config/reseed/
|
||||
install -g i2psvc -o i2psvc -D -d ${prefix}etc/systemd/system/reseed.service.d/
|
||||
install -m644 etc/systemd/system/reseed.service.d/override.conf ${prefix}etc/systemd/system/reseed.service.d/override.conf
|
||||
install -m644 etc/systemd/system/reseed.service ${prefix}etc/systemd/system/reseed.service
|
||||
|
||||
uninstall:
|
||||
rm /usr/bin/reseed-tools
|
||||
rm /etc/default/reseed
|
||||
rm /etc/init.d/reseed
|
||||
rm /etc/systemd/system/reseed.service.d/reseed.conf
|
||||
rm /etc/systemd/system/reseed.service
|
||||
rm -rf /var/lib/i2p/i2p-config/reseed/
|
||||
rm -rf ${prefix}bin/reseed-tools
|
||||
rm -rf ${prefix}etc/default/reseed
|
||||
rm -rf ${prefix}etc/init.d/reseed
|
||||
rm -rf ${prefix}etc/systemd/system/reseed.service.d/reseed.conf
|
||||
rm -rf ${prefix}etc/systemd/system/reseed.service
|
||||
rm -rf ${prefix}var/lib/i2p/i2p-config/reseed/
|
||||
|
||||
checkinstall: build
|
||||
fakeroot checkinstall \
|
||||
checkinstall:
|
||||
checkinstall -D \
|
||||
--arch=$(GOARCH) \
|
||||
--default \
|
||||
--install=no \
|
||||
@@ -103,12 +104,12 @@ gofmt:
|
||||
try:
|
||||
mkdir -p tmp && \
|
||||
cd tmp && \
|
||||
../reseed-tools-$(GOOS)-$(GOARCH) reseed --signer=you@mail.i2p --netdb=/home/idk/.i2p/netDb --tlsHost=your-domain.tld --onion --p2p --i2p
|
||||
../reseed-tools-$(GOOS)-$(GOARCH) reseed --signer=fake@mail.i2p --netdb=${HOME}/.i2p/netDb --tlsHost=your-domain.tld --i2p
|
||||
|
||||
stop:
|
||||
mkdir -p tmp && \
|
||||
cd tmp && \
|
||||
../reseed-tools-$(GOOS)-$(GOARCH) reseed --signer=you@mail.i2p --netdb=/home/idk/.i2p/netDb --tlsHost=your-domain.tld --onion --p2p --i2p
|
||||
../reseed-tools-$(GOOS)-$(GOARCH) reseed --signer=fake@mail.i2p --netdb=${HOME}/.i2p/netDb --tlsHost=your-domain.tld --i2p
|
||||
|
||||
docker:
|
||||
docker build -t eyedeekay/reseed .
|
||||
@@ -174,7 +175,7 @@ jar: gojava
|
||||
echo $(JAVA_HOME)
|
||||
./gojava -v -o reseed.jar -s . build ./reseed
|
||||
|
||||
release: version upload debs upload-deps plugins upload-bin
|
||||
release: version upload binary upload-bin plugins upload-plugins debs upload-debs
|
||||
|
||||
version:
|
||||
head -n 5 README.md | github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -d -; true
|
||||
@@ -186,7 +187,7 @@ edit:
|
||||
cat README.md | github-release edit -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -d -
|
||||
|
||||
upload: tar
|
||||
github-release upload -R -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f ../reseed-tools.tar.xz -n "reseed-tools.tar.xz"
|
||||
github-release upload -R -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f ../reseed-tools.tar.gz -n "reseed-tools.tar.gz"
|
||||
|
||||
binary:
|
||||
##export GOOS=darwin; export GOARCH=amd64; make build
|
||||
@@ -221,10 +222,10 @@ debs:
|
||||
export GOOS=linux; export GOARCH=arm64; make build checkinstall
|
||||
|
||||
upload-debs:
|
||||
export GOOS=linux; export GOARCH=386; make upload-single-su3
|
||||
export GOOS=linux; export GOARCH=amd64; make upload-single-su3
|
||||
export GOOS=linux; export GOARCH=arm; make upload-single-su3
|
||||
export GOOS=linux; export GOARCH=arm64; make upload-single-su3
|
||||
export GOOS=linux; export GOARCH=386; make upload-single-deb
|
||||
export GOOS=linux; export GOARCH=amd64; make upload-single-deb
|
||||
export GOOS=linux; export GOARCH=arm; make upload-single-deb
|
||||
export GOOS=linux; export GOARCH=arm64; make upload-single-deb
|
||||
|
||||
upload-bin:
|
||||
#export GOOS=darwin; export GOARCH=amd64; make upload-single-bin
|
||||
|
||||
118
cmd/reseed.go
118
cmd/reseed.go
@@ -1,6 +1,9 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
//"flag"
|
||||
@@ -17,7 +20,10 @@ import (
|
||||
"github.com/cretz/bine/torutil"
|
||||
"github.com/cretz/bine/torutil/ed25519"
|
||||
"github.com/eyedeekay/i2pkeys"
|
||||
"github.com/eyedeekay/onramp"
|
||||
"github.com/eyedeekay/sam3"
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/rglonek/untar"
|
||||
"github.com/urfave/cli/v3"
|
||||
"i2pgit.org/idk/reseed-tools/reseed"
|
||||
|
||||
@@ -162,6 +168,16 @@ func NewReseedCommand() *cli.Command {
|
||||
Value: cli.NewStringSlice(reseed.AllReseeds...),
|
||||
Usage: "Ping other reseed servers and display the result on the homepage to provide information about reseed uptime.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "share-peer",
|
||||
Value: "",
|
||||
Usage: "Download the shared netDb content of another I2P router, over I2P",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "share-password",
|
||||
Value: "",
|
||||
Usage: "Password for downloading netDb content from another router. Required for share-peer to work.",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "acme",
|
||||
Usage: "Automatically generate a TLS certificate with the ACME protocol, defaults to Let's Encrypt",
|
||||
@@ -265,6 +281,19 @@ func reseedAction(c *cli.Context) error {
|
||||
}
|
||||
signerID = string(bytes)
|
||||
}
|
||||
if c.String("share-peer") != "" {
|
||||
count := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
for i := range count {
|
||||
err := downloadRemoteNetDB(c.String("share-peer"), c.String("share-password"), c.String("netdb"), c.String("samaddr"))
|
||||
if err != nil {
|
||||
log.Println("Error downloading remote netDb,", err, "retrying in 10 seconds", i, "attempts remaining")
|
||||
time.Sleep(time.Second * 10)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
go getSupplementalNetDb(c.String("share-peer"), c.String("share-password"), c.String("netdb"), c.String("samaddr"))
|
||||
}
|
||||
|
||||
var tlsCert, tlsKey string
|
||||
tlsHost := c.String("tlsHost")
|
||||
@@ -631,3 +660,92 @@ func reseedI2P(c *cli.Context, i2pTlsCert, i2pTlsKey string, i2pIdentKey i2pkeys
|
||||
|
||||
log.Printf("Onion server started on %s\n", server.Addr)
|
||||
}
|
||||
|
||||
func getSupplementalNetDb(remote, password, path, samaddr string) {
|
||||
log.Println("Remote NetDB Update Loop")
|
||||
for {
|
||||
if err := downloadRemoteNetDB(remote, password, path, samaddr); err != nil {
|
||||
log.Println("Error downloading remote netDb", err)
|
||||
time.Sleep(time.Second * 30)
|
||||
} else {
|
||||
log.Println("Success downloading remote netDb", err)
|
||||
time.Sleep(time.Minute * 30)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func downloadRemoteNetDB(remote, password, path, samaddr string) error {
|
||||
var hremote string
|
||||
if !strings.HasPrefix("http://", remote) && !strings.HasPrefix("https://", remote) {
|
||||
hremote = "http://" + remote
|
||||
}
|
||||
if !strings.HasSuffix(hremote, ".tar.gz") {
|
||||
hremote += "/netDb.tar.gz"
|
||||
}
|
||||
url, err := url.Parse(hremote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpRequest := http.Request{
|
||||
URL: url,
|
||||
Header: http.Header{},
|
||||
}
|
||||
garlic, err := onramp.NewGarlic("reseed-client", samaddr, onramp.OPT_WIDE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer garlic.Close()
|
||||
httpRequest.Header.Add(http.CanonicalHeaderKey("reseed-password"), password)
|
||||
httpRequest.Header.Add(http.CanonicalHeaderKey("x-user-agent"), reseed.I2pUserAgent)
|
||||
transport := http.Transport{
|
||||
Dial: garlic.Dial,
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: &transport,
|
||||
}
|
||||
if resp, err := client.Do(&httpRequest); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if bodyBytes, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := ioutil.WriteFile("netDb.tar.gz", bodyBytes, 0644); err != nil {
|
||||
return err
|
||||
} else {
|
||||
dbPath := filepath.Join(path, "reseed-netDb")
|
||||
if err := untar.UntarFile("netDb.tar.gz", dbPath); err != nil {
|
||||
return err
|
||||
} else {
|
||||
// For example...
|
||||
opt := copy.Options{
|
||||
Skip: func(info os.FileInfo, src, dest string) (bool, error) {
|
||||
srcBase := filepath.Base(src)
|
||||
dstBase := filepath.Base(dest)
|
||||
if info.IsDir() {
|
||||
return false, nil
|
||||
}
|
||||
if srcBase == dstBase {
|
||||
log.Println("Ignoring existing RI", srcBase, dstBase)
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
},
|
||||
}
|
||||
if err := copy.Copy(dbPath, path, opt); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := os.RemoveAll(dbPath); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := os.RemoveAll("netDb.tar.gz"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
151
cmd/share.go
Normal file
151
cmd/share.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
|
||||
//"flag"
|
||||
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"github.com/eyedeekay/checki2cp/getmeanetdb"
|
||||
"github.com/eyedeekay/onramp"
|
||||
)
|
||||
|
||||
func NewShareCommand() *cli.Command {
|
||||
ndb, err := getmeanetdb.WhereIstheNetDB()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return &cli.Command{
|
||||
Name: "share",
|
||||
Usage: "Start a netDb sharing server",
|
||||
Action: shareAction,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "signer",
|
||||
Value: getDefaultSigner(),
|
||||
Usage: "Your su3 signing ID (ex. something@mail.i2p)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "key",
|
||||
Usage: "Path to your su3 signing private key",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netdb",
|
||||
Value: ndb,
|
||||
Usage: "Path to NetDB directory containing routerInfos",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "samaddr",
|
||||
Value: "127.0.0.1:7656",
|
||||
Usage: "Use this SAM address to set up I2P connections for in-network sharing",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "share-password",
|
||||
Value: "",
|
||||
Usage: "Share the contents of your netDb directory privately over I2P as a tar.gz archive. Will fail is password is blank.",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type sharer struct {
|
||||
http.FileSystem
|
||||
http.Handler
|
||||
Path string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *sharer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
p, ok := r.Header[http.CanonicalHeaderKey("reseed-password")]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if p[0] != s.Password {
|
||||
return
|
||||
}
|
||||
log.Println("Path", r.URL.Path)
|
||||
if strings.HasSuffix(r.URL.Path, "tar.gz") {
|
||||
log.Println("Serving netdb")
|
||||
archive, err := walker(s.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w.Write(archive.Bytes())
|
||||
return
|
||||
}
|
||||
s.Handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func Sharer(netDbDir, password string) *sharer {
|
||||
fileSystem := &sharer{
|
||||
FileSystem: http.Dir(netDbDir),
|
||||
Path: netDbDir,
|
||||
Password: password,
|
||||
}
|
||||
fileSystem.Handler = http.FileServer(fileSystem.FileSystem)
|
||||
return fileSystem
|
||||
}
|
||||
|
||||
func shareAction(c *cli.Context) error {
|
||||
netDbDir, err := filepath.Abs(c.String("netdb"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpFs := Sharer(netDbDir, c.String("share-password"))
|
||||
garlic, err := onramp.NewGarlic("reseed", c.String("samaddr"), onramp.OPT_WIDE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
garlicListener, err := garlic.Listen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return http.Serve(garlicListener, httpFs)
|
||||
}
|
||||
|
||||
func walker(netDbDir string) (*bytes.Buffer, error) {
|
||||
var buf bytes.Buffer
|
||||
tw := tar.NewWriter(&buf)
|
||||
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode().IsDir() {
|
||||
return nil
|
||||
}
|
||||
new_path := path[len(netDbDir):]
|
||||
if len(new_path) == 0 {
|
||||
return nil
|
||||
}
|
||||
fr, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fr.Close()
|
||||
if h, err := tar.FileInfoHeader(info, new_path); err != nil {
|
||||
log.Fatalln(err)
|
||||
} else {
|
||||
h.Name = new_path
|
||||
if err = tw.WriteHeader(h); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
if _, err := io.Copy(tw, fr); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := filepath.Walk(netDbDir, walkFn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &buf, nil
|
||||
}
|
||||
94
docs/REMOTE-SSH.md
Normal file
94
docs/REMOTE-SSH.md
Normal file
@@ -0,0 +1,94 @@
|
||||
Using a remote Network Database with SSH
|
||||
========================================
|
||||
|
||||
Beginning in `reseed-tools 2.5.0` it is possible to use reseed-tools to "share" a netDb directory on one host with a reseed server on another host.
|
||||
This feature is built into the reseed-tools software.
|
||||
It is also possible to do this manually using `sshfs`, `ssh` combined with `cron`, and most available backup utilities like `borg` and `syncthing`.
|
||||
This guide only covers `rsync+ssh` and `cron` where I2P is running as a user(not as `i2psvc`).
|
||||
It requires 2 hosts with exposed SSH ports that can reach eachother.
|
||||
It also pretty much assumes you're using something based on Debian.
|
||||
|
||||
Why?
|
||||
----
|
||||
|
||||
In most setups, a reseed service is using a network database which is kept on the same server as the I2P router where it finds it's netDb.
|
||||
This is convenient, however if reseed servers are targeted for a RouterInfo spam attack, then the reseed server could potentially be overwhelmed with spammy routerInfos.
|
||||
That impairs a new user's ability to join the network and slows down network integration.
|
||||
|
||||
SSH-Protected Retrieval of NetDB content over I2P
|
||||
-----------------------------------------------
|
||||
|
||||
In this guide, the NetDB is retrieved from a remote router by the reseed server.
|
||||
|
||||
### On the Remote Router
|
||||
|
||||
Install openssh-server and rsync and enable the service:
|
||||
|
||||
```sh
|
||||
sudo apt install openssh-server rsync
|
||||
sudo systemctl enable ssh
|
||||
```
|
||||
|
||||
### On the Reseed Server
|
||||
|
||||
Set up SSH and generate new keys, without passwords:
|
||||
|
||||
```sh
|
||||
ssh-keygen -f ~/.ssh/netdb_sync_ed25519 -N ""
|
||||
```
|
||||
|
||||
Then, copy the keys to the remote router:
|
||||
|
||||
```sh
|
||||
ssh-copy-id -f ~/.ssh/netdb_sync_ed25519 $(UserRunningI2P)@$(RemoteRouter)
|
||||
```
|
||||
|
||||
After, set up the `cron` job to copy the netDB.
|
||||
|
||||
```sh
|
||||
crontab -e
|
||||
>>
|
||||
* 30 * * * rsync --update -raz $(UserRunningI2P)@$(RemoteRouter):$(/Path/To/Remote/NetDB) $(Path/To/My/NetDB)
|
||||
```
|
||||
|
||||
SSH-Protected Sharing of NetDB content over I2P
|
||||
-----------------------------------------------
|
||||
|
||||
In this guide, the NetDB is pushed to a reseed server by a remote router.
|
||||
|
||||
### On the Reseed Server
|
||||
|
||||
Install openssh-server and rsync and enable the service:
|
||||
|
||||
```sh
|
||||
sudo apt install openssh-server rsync
|
||||
sudo systemctl enable ssh
|
||||
```
|
||||
|
||||
Next, stop your reseed server.
|
||||
|
||||
```sh
|
||||
killall reseed-tools
|
||||
```
|
||||
|
||||
### On the Remote Router
|
||||
|
||||
Start by setting up SSH and generating new keys, without passwords:
|
||||
|
||||
```sh
|
||||
ssh-keygen -f ~/.ssh/netdb_sync_ed25519 -N ""
|
||||
```
|
||||
|
||||
Then, copy the keys to the Reseed Server:
|
||||
|
||||
```sh
|
||||
ssh-copy-id -f ~/.ssh/netdb_sync_ed25519 $(UserRunningReseed)@$(ReseedServer)
|
||||
```
|
||||
|
||||
After, set up the `cron` job to copy the netDB.
|
||||
|
||||
```sh
|
||||
crontab -e
|
||||
>>
|
||||
* 30 * * * rsync --update -raz $(/Path/To/My/NetDB) $(UserRunningReseed)@$(ReseedServer):/$(Path/To/Reseed/NetDB)
|
||||
```
|
||||
47
docs/REMOTE.md
Normal file
47
docs/REMOTE.md
Normal file
@@ -0,0 +1,47 @@
|
||||
Using a remote Network Database
|
||||
===============================
|
||||
|
||||
Beginning in `reseed-tools 2.5.0` it is possible to use reseed-tools to "share" a netDb directory on one host with a reseed server on another host.
|
||||
This feature is built into the reseed-tools software.
|
||||
It is also possible to do this manually using `sshfs`, `ssh` combined with `cron`, and most available backup utilities like `borg` and `syncthing`.
|
||||
This guide only covers `reseed-tools`.
|
||||
It requires only `reseed-tools` and an I2P router.
|
||||
Presumably, if you are reading this document, you are already comfortable running both of these pieces of software.
|
||||
|
||||
Why?
|
||||
----
|
||||
|
||||
In most setups, a reseed service is using a network database which is kept on the same server as the I2P router where it finds it's netDb.
|
||||
This is convenient, however if reseed servers are targeted for a RouterInfo spam attack, then the reseed server could potentially be overwhelmed with spammy RouterInfos.
|
||||
That impairs a new user's ability to join the network and slows down network integration.
|
||||
|
||||
Password-Protected Sharing of NetDB content over I2P
|
||||
----------------------------------------------------
|
||||
|
||||
This method uses SAMv3 via the `onramp` library with `wide` tunnel options(1 hop, 2 tunnels) on both sides.
|
||||
By using I2P, this method trades some performance for ofuscation.
|
||||
However, the data is tiny so in-practice it works very well.
|
||||
|
||||
Run this command on a well-integrated I2P router which is **not** hosting a reseed server on the same IP address.
|
||||
To share the whole contents of your netDb directory over I2P, run reseed-tools with the following arguments:
|
||||
|
||||
```sh
|
||||
reseed-tools share --share-password $(use_a_strong_password) --netdb $(path_to_your_netdb)
|
||||
```
|
||||
|
||||
In a few seconds, you will have a new I2P site which will provide your netDb as a `.tar.gz` file to anyone with the password.
|
||||
Make a note of the base32 address of the new site for the next step.
|
||||
|
||||
Password-Protected Retrieval of Shared NetDB content over I2P
|
||||
-------------------------------------------------------------
|
||||
|
||||
Run this command on a router hosting which **is** hosting a reseed server on the same IP address, or add the arguments to your existing command.
|
||||
To retrieve a remote NetDB bundle from a hidden service, run reseed tools with the following arguments:
|
||||
|
||||
```sh
|
||||
reseed-tools reseed --share-peer $(thebase32addressyoumadeanoteofaboveintheotherstepnow.b32.i2p) --share-password $(use_a_strong_password) --netdb $(path_to_your_netdb)
|
||||
```
|
||||
|
||||
Periodically, the remote `netdb.tar.gz` bundle will be fetched from the remote server and extracted to the `--netdb` directory.
|
||||
If the `--netdb` directory is not empty, local RI's are left intact and never overwritten, essentially combining the local and remote netDb.
|
||||
If the directory is empty, the remote netDb will be the only netDb used by the reseed server.
|
||||
40
docs/UPGRADE.md
Normal file
40
docs/UPGRADE.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Upgrading from an older version of reseed-tools
|
||||
===============================================
|
||||
|
||||
This reseed server sometimes gains helpful features that reseed operators may wish to use.
|
||||
Additionally, it is possible that at some point we'll need to release a security update.
|
||||
This document provides a path to upgrade the various binary distributions of reseed-tools.
|
||||
|
||||
Debian and Ubuntu Users
|
||||
-----------------------
|
||||
|
||||
1. Shut down the existing `reseed-tools` service.
|
||||
If you are using `sysvinit` or something like it, you should be able to run: `sudo service reseed stop`.
|
||||
If you are using `systemd` you should be able to run `sudo systemctl stop reseed`.
|
||||
If those commands don't work, use `killall reseed-tools`
|
||||
2. Download the `.deb` package from the Github Releases page.
|
||||
Make sure you get the right package for your ARCH/OS pair.
|
||||
Most will need the `_amd64.deb` package.
|
||||
3. Install the package using: `sudo dpkg -i ./reseed-tools*.deb`
|
||||
|
||||
Docker Users
|
||||
------------
|
||||
|
||||
1. Build the container locally: `docker build -t eyedeekay/reseed .`
|
||||
2. Stop the container: `docker stop reseed`
|
||||
3. Start the container: `docker start reseed`
|
||||
|
||||
Freestanding `tar.gz` Users, People who built from source
|
||||
---------------------------------------------------------
|
||||
|
||||
1. Shut down the existing `reseed-tools` service.
|
||||
If you are using `sysvinit` or something like it, you should be able to run: `sudo service reseed stop`.
|
||||
If you are using `systemd` you should be able to run `sudo systemctl stop reseed`.
|
||||
If those commands don't work, use `killall reseed-tools`
|
||||
2. Extract the tar file: `tar xzf reseed-tools.tgz`
|
||||
3. Copy the `reseed-tools` binary to the correct location if you're on `amd64` or compile it if you are not.
|
||||
`cp reseed-tools reseed-tools-linux-amd64`
|
||||
OR
|
||||
`make build`
|
||||
4. Install the new software and service management files:
|
||||
`sudo make install`
|
||||
25
go.mod
25
go.mod
@@ -3,18 +3,37 @@ module i2pgit.org/idk/reseed-tools
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.0 // indirect
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/eyedeekay/checki2cp v0.0.21
|
||||
github.com/eyedeekay/checki2cp v0.33.8
|
||||
github.com/eyedeekay/go-fpw v0.0.0-20200512022837-c8b4dcdc74d4 // indirect
|
||||
github.com/eyedeekay/go-i2pd v0.0.0-20220213070306-9807541b2dfc
|
||||
github.com/eyedeekay/i2pkeys v0.33.0
|
||||
github.com/eyedeekay/sam3 v0.33.5
|
||||
github.com/eyedeekay/i2pkeys v0.33.8
|
||||
github.com/eyedeekay/onramp v0.33.7
|
||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab // indirect
|
||||
github.com/eyedeekay/sam3 v0.33.8
|
||||
github.com/eyedeekay/unembed v0.0.0-20230123014222-9916b121855b
|
||||
github.com/go-acme/lego/v4 v4.3.1
|
||||
github.com/go-i2p/go-i2p v0.0.0-20240625160418-ac705dee767b
|
||||
github.com/golang/gddo v0.0.0-20200324184333-3c2cc9a6329d // indirect
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/jpillora/go-tcp-proxy v1.0.0 // indirect
|
||||
github.com/justinas/alice v1.2.0
|
||||
github.com/klauspost/compress v1.10.5 // indirect
|
||||
github.com/klauspost/pgzip v1.2.3 // indirect
|
||||
github.com/majestrate/i2p-tools v0.0.0-20170507194519-afc8e46afa95 // indirect
|
||||
github.com/mholt/archiver v3.1.1+incompatible // indirect
|
||||
github.com/mholt/archiver/v3 v3.3.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
|
||||
github.com/rglonek/untar v0.0.1
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/throttled/throttled/v2 v2.7.1
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha
|
||||
github.com/ybbus/jsonrpc v2.1.2+incompatible // indirect
|
||||
github.com/zserge/lorca v0.1.9 // indirect
|
||||
gitlab.com/golang-commonmark/markdown v0.0.0-20191127184510-91b5b3c99c19
|
||||
golang.org/x/text v0.15.0
|
||||
)
|
||||
|
||||
55
go.sum
55
go.sum
@@ -107,22 +107,32 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc=
|
||||
github.com/eyedeekay/checki2cp v0.0.21 h1:DVer7H6RffCWS8Bo3+J6EyppUc1y8lvApKdQnAiVj5g=
|
||||
github.com/eyedeekay/checki2cp v0.0.21/go.mod h1:75sGwBgnacHmxxx8RQ7BIeS0gu5Pw916gFb2c80OUTc=
|
||||
github.com/eyedeekay/checki2cp v0.0.22 h1:GrgBzQBWGRa2rBLK/9fdRlgRqs2BLt8kqMoo/x5Srvs=
|
||||
github.com/eyedeekay/checki2cp v0.0.22/go.mod h1:n40YU2DtJI4iW6H8Wdqma062PI6L2ruVpG8QtsOjYRQ=
|
||||
github.com/eyedeekay/checki2cp v0.33.8 h1:h31UDIuTP7Pv0T332RlRUieTwaNT+LoLPPLOhkwecsk=
|
||||
github.com/eyedeekay/checki2cp v0.33.8/go.mod h1:n40YU2DtJI4iW6H8Wdqma062PI6L2ruVpG8QtsOjYRQ=
|
||||
github.com/eyedeekay/go-fpw v0.0.0-20200512022837-c8b4dcdc74d4/go.mod h1:RyCx7KuH+5ryvIpUF7SpxiChLtjeuPbVFCIzf8shIFc=
|
||||
github.com/eyedeekay/go-i2cp v0.0.0-20190716135428-6d41bed718b0 h1:rnn9OlD/3+tATEZNuiMR1C84O5CX8bZL2qqgttprKrw=
|
||||
github.com/eyedeekay/go-i2cp v0.0.0-20190716135428-6d41bed718b0/go.mod h1:+P0fIhkqIYjo7exMJRTlSteRMbRyHbiBiKw+YlPWk+c=
|
||||
github.com/eyedeekay/go-i2pcontrol v0.0.0-20200110011336-510cca77e350/go.mod h1:bhIQsVpbNNXMtcoZ9UF4hLQleOjaCgKGXiRRhNc8TOA=
|
||||
github.com/eyedeekay/go-i2pcontrol v0.1.6/go.mod h1:976YyzS3THPwlBelkp3t1pMzzsjyn96eLaVdhaaSI78=
|
||||
github.com/eyedeekay/go-i2pd v0.0.0-20220213070306-9807541b2dfc h1:ozp8Cxn9nsFF+p4tMcE63G0Kx+2lEywlCW0EvtISEZg=
|
||||
github.com/eyedeekay/go-i2pd v0.0.0-20220213070306-9807541b2dfc/go.mod h1:Yg8xCWRLyq0mezPV+xJygBhJCf7wYsIdXbYGQk5tnW8=
|
||||
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
|
||||
github.com/eyedeekay/i2pd v0.3.0-1stbinrelease.0.20210702172028-5d01ee95810a/go.mod h1:4qJhWn+yNrWRbqFHhU8kl7JgbcW1hm3PMgvlPlxO3gg=
|
||||
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/i2pkeys v0.33.0 h1:5SzUyWxNjV6AvYv/WaI8J4dSgAfv7/WEps6pDLe2YSs=
|
||||
github.com/eyedeekay/i2pkeys v0.33.0/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/i2pkeys v0.33.7 h1:cxqHSkl6b2lHyPJUtIQZBiipYf7NQVYqM1d3ub0MI4k=
|
||||
github.com/eyedeekay/i2pkeys v0.33.7/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/i2pkeys v0.33.8 h1:f3llyruchFqs1QwCacBYbShArKPpMSSOqo/DVZXcfVs=
|
||||
github.com/eyedeekay/i2pkeys v0.33.8/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
|
||||
github.com/eyedeekay/onramp v0.33.7 h1:LkPklut7Apa6CPGdIoOJpyIpzP9H/Jw7RKvrVxEEYEM=
|
||||
github.com/eyedeekay/onramp v0.33.7/go.mod h1:+Dutoc91mCHLJlYNE3Ir6kSfmpEcQA6/RNHnmVVznWg=
|
||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
|
||||
github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
|
||||
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
||||
github.com/eyedeekay/sam3 v0.33.5 h1:mY2MmEG4W35AOpG/G7DOdAhFZWRwFxlm+NmIoub1Xnw=
|
||||
github.com/eyedeekay/sam3 v0.33.5/go.mod h1:sPtlI4cRm7wD0UywOzLPvvdY1G++vBSK3n+jiIGqWlU=
|
||||
github.com/eyedeekay/sam3 v0.33.7 h1:GPYHG4NHxvhqPbGNJ3wKvUQyZSTCmX17f5L5QvyefGs=
|
||||
github.com/eyedeekay/sam3 v0.33.7/go.mod h1:25cRGEFawSkbiPNSh7vTUIpRtEYLVLg/4J4He6LndAY=
|
||||
github.com/eyedeekay/sam3 v0.33.8 h1:emuSZ4qSyoqc1EDjIBFbJ3GXNHOXw6hjbNp2OqdOpgI=
|
||||
github.com/eyedeekay/sam3 v0.33.8/go.mod h1:ytbwLYLJlW6UA92Ffyc6oioWTKnGeeUMr9CLuJbtqSA=
|
||||
github.com/eyedeekay/unembed v0.0.0-20230123014222-9916b121855b h1:QyCSwbHpkJtKGvIvHsvvlbDkf7/3a8qUlaa4rEr8myQ=
|
||||
github.com/eyedeekay/unembed v0.0.0-20230123014222-9916b121855b/go.mod h1:A6dZU88muI132XMrmdM0+cc2yIuwmhwgRfyrU54DjPc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
@@ -133,6 +143,8 @@ github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwU
|
||||
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
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/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
|
||||
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
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=
|
||||
@@ -371,9 +383,14 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
||||
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
@@ -414,6 +431,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rglonek/untar v0.0.1 h1:fI1QmP07eQvOgudrUP/NDUCob56JuAYlLDknxX8485A=
|
||||
github.com/rglonek/untar v0.0.1/go.mod h1:yq/FZcge2BBdmPQEShskttgtHZG+LOtiHZyXknL54a0=
|
||||
github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxzAnkLeoEbqHEerI4eSw6ua+RaIB0S4jMV21RAs=
|
||||
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=
|
||||
@@ -458,13 +477,18 @@ github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
|
||||
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=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/throttled/throttled/v2 v2.7.1 h1:FnBysDX4Sok55bvfDMI0l2Y71V1vM2wi7O79OW7fNtw=
|
||||
github.com/throttled/throttled/v2 v2.7.1/go.mod h1:fuOeyK9fmnA+LQnsBbfT/mmPHjmkdogRBQxaD8YsgZ8=
|
||||
@@ -490,8 +514,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
|
||||
github.com/ybbus/jsonrpc/v2 v2.1.7/go.mod h1:rIuG1+ORoiqocf9xs/v+ecaAVeo3zcZHQgInyKFMeg0=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zserge/lorca v0.1.9/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A=
|
||||
gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181 h1:K+bMSIx9A7mLES1rtG+qKduLIXq40DAzYHtb0XuCukA=
|
||||
@@ -535,6 +559,7 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
@@ -567,7 +592,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -597,14 +621,16 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -620,10 +646,10 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -673,16 +699,20 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -693,8 +723,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
@@ -740,7 +772,6 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
44
history.txt
44
history.txt
@@ -1,44 +0,0 @@
|
||||
2019-11-16
|
||||
* allow multiple reseed transports from the same application
|
||||
* incorporate libp2p(ipfs) listener from RTradeLtd/i2p-tools-1 master
|
||||
* in-network(I2P) reseeds in case there's a point to that.
|
||||
* self-supervising reseed service, if it crashes it will restart itself
|
||||
* add an initscript
|
||||
|
||||
2019-06-27
|
||||
* automatically configuring Tor Onionv3 Server
|
||||
|
||||
2019-04-21
|
||||
* app.Version = "0.1.7"
|
||||
* enabling TLS 1.3 *only*
|
||||
|
||||
2016-12-21
|
||||
* deactivating previous random time delta, makes only sense when patching ri too
|
||||
* app.Version = "0.1.6"
|
||||
|
||||
2016-10-09
|
||||
* seed the math random generator with time.Now().UnixNano()
|
||||
* added 6h+6h random time delta at su3-age to increase anonymity
|
||||
* app.Version = "0.1.5"
|
||||
|
||||
|
||||
2016-05-15
|
||||
* README.md updated
|
||||
* allowed routerInfos age increased from 96 to 192 hours
|
||||
* app.Version = "0.1.4"
|
||||
|
||||
2016-03-05
|
||||
* app.Version = "0.1.3"
|
||||
* CRL creation added
|
||||
|
||||
2016-01-31
|
||||
* allowed TLS ciphers updated (hardened)
|
||||
* TLS certificate generation: RSA 4096 --> ECDSAWithSHA512 384bit secp384r1
|
||||
* ECDHE handshake: only CurveP384 + CurveP521, default CurveP256 removed
|
||||
* TLS certificate valid: 2y --> 5y
|
||||
* throttled.PerDay(4) --> PerHour(4), to enable limited testing
|
||||
* su3 RebuildInterval: 24h --> 90h, higher anonymity for the running i2p-router
|
||||
* numRi per su3 file: 75 --> 77
|
||||
|
||||
2016-01
|
||||
* fork from https://i2pgit.org/idk/reseed-tools
|
||||
3
main.go
3
main.go
@@ -19,7 +19,7 @@ func main() {
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "reseed-tools"
|
||||
app.Version = "0.2.4"
|
||||
app.Version = "0.3.1"
|
||||
app.Usage = "I2P tools and reseed server"
|
||||
auth := &cli.Author{
|
||||
Name: "eyedeekay",
|
||||
@@ -31,6 +31,7 @@ func main() {
|
||||
cmd.NewReseedCommand(),
|
||||
cmd.NewSu3VerifyCommand(),
|
||||
cmd.NewKeygenCommand(),
|
||||
cmd.NewShareCommand(),
|
||||
// cmd.NewSu3VerifyPublicCommand(),
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ func Ping(urlInput string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
req.Header.Set("User-Agent", i2pUserAgent)
|
||||
req.Header.Set("User-Agent", I2pUserAgent)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
i2pUserAgent = "Wget/1.11.4"
|
||||
I2pUserAgent = "Wget/1.11.4"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -361,7 +361,7 @@ func (srv *Server) browsingMiddleware(next http.Handler) http.Handler {
|
||||
if srv.CheckAcceptable(r.FormValue("onetime")) {
|
||||
srv.reseedHandler(w, r)
|
||||
}
|
||||
if i2pUserAgent != r.UserAgent() {
|
||||
if I2pUserAgent != r.UserAgent() {
|
||||
srv.HandleARealBrowser(w, r)
|
||||
return
|
||||
}
|
||||
@@ -372,7 +372,7 @@ func (srv *Server) browsingMiddleware(next http.Handler) http.Handler {
|
||||
|
||||
func verifyMiddleware(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if i2pUserAgent != r.UserAgent() {
|
||||
if I2pUserAgent != r.UserAgent() {
|
||||
http.Error(w, "403 Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -273,6 +273,7 @@ func (db *LocalNetDbImpl) RouterInfos() (routerInfos []routerInfo, err error) {
|
||||
riStruct = nil
|
||||
continue
|
||||
}
|
||||
|
||||
// skip crappy routerInfos
|
||||
if riStruct.Reachable() && riStruct.UnCongested() && riStruct.GoodVersion() {
|
||||
routerInfos = append(routerInfos, routerInfo{
|
||||
|
||||
Reference in New Issue
Block a user