10 Commits

Author SHA1 Message Date
eyedeekay
83cf8bdcde bump version 2025-03-09 13:45:17 -04:00
eyedeekay
2a23c5ea13 update Makefile 2025-03-09 13:44:19 -04:00
eyedeekay
a666afef7c update .gitignore 2025-03-08 20:28:36 -05:00
eyedeekay
ba79de0135 update some docs, clean up the Makefile 2025-03-08 20:27:00 -05:00
eyedeekay
0ede48bfc6 clean up makefile 2025-03-08 20:18:10 -05:00
eyedeekay
d0b5b3874e update service, initscripts 2025-03-08 19:59:25 -05:00
eyedeekay
59479597d5 update service initscripts 2025-03-08 19:54:48 -05:00
eyedeekay
e85229dc90 update gitignore 2025-03-08 19:40:50 -05:00
eyedeekay
504e7bddb9 disable docker 2025-03-08 19:36:31 -05:00
eyedeekay
2e7e2e1289 add I2P maintainers repository to CI build file 2025-03-08 19:26:18 -05:00
17 changed files with 109 additions and 150 deletions

View File

@@ -24,6 +24,7 @@ jobs:
- name: Install build dependencies
run: |
sudo add-apt-repository -y ppa:i2p-maintainers/i2p
sudo apt-get update
sudo apt-get install -y make git fakeroot checkinstall i2p i2p-router
@@ -78,11 +79,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
if: success()
run: |
docker login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ghcr.io
docker build -t ghcr.io/${{ github.repository }}:${{ github.ref_name }} .
docker push ghcr.io/${{ github.repository }}:${{ github.ref_name }}
docker tag ghcr.io/${{ github.repository }}:${{ github.ref_name }} ghcr.io/${{ github.repository }}:latest
docker push ghcr.io/${{ github.repository }}:latest
# - name: Build and push Docker image
# if: success()
# run: |
# docker login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ghcr.io
# docker build -t ghcr.io/${{ github.repository }}:${{ github.ref_name }} .
# docker push ghcr.io/${{ github.repository }}:${{ github.ref_name }}
# docker tag ghcr.io/${{ github.repository }}:${{ github.ref_name }} ghcr.io/${{ github.repository }}:latest
# docker push ghcr.io/${{ github.repository }}:latest

8
.gitignore vendored
View File

@@ -2,6 +2,10 @@
/cert.pem
/key.pem
/_netdb
/i2pkeys
/onionkeys
/tlskeys
/tmp
i2pseeds.su3
*.pem
onion.key
@@ -17,4 +21,6 @@ audit.json
*ed25519*
client.yaml
plugin.yaml
err
err
/plugin-linux-amd64.yaml
/client-linux-amd64.yaml

123
Makefile
View File

@@ -1,5 +1,5 @@
VERSION=$(shell ./reseed-tools-linux-amd64 version 2>/dev/null)
VERSION=$(shell /usr/bin/go run . version 2>/dev/null)
APP=reseed-tools
USER_GH=eyedeekay
SIGNER=hankhill19580@gmail.com
@@ -12,7 +12,7 @@ prefix?=/
GOOS?=$(shell uname -s | tr A-Z a-z)
GOARCH?="amd64"
ARG=-v -tags netgo -ldflags '-w -extldflags "-static"'
ARG=-v -tags netgo,osusergo -ldflags '-w -extldflags "-static"'
#MIN_GO_VERSION=`ls /usr/lib/go-1.14 2>/dev/null >/dev/null && echo 1.14`
MIN_GO_VERSION?=1.16
@@ -23,10 +23,10 @@ I2P_GID=$(shell id -g i2psvc)
WHOAMI=$(shell whoami)
echo:
@echo "type make version to do release $(APP) $(VERSION) $(GOOS) $(GOARCH) $(MIN_GO_VERSION) $(I2P_UID) $(I2P_GID)"
@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
/usr/bin/go build -o reseed-tools-host 2>/dev/null 1>/dev/null
index:
edgar
@@ -101,70 +101,7 @@ unfork:
make gofmt build-unfork
gofmt:
gofmt -w main.go cmd/*.go reseed/*.go su3/*.go
try:
mkdir -p tmp && \
cd tmp && \
../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=fake@mail.i2p --netdb=${HOME}/.i2p/netDb --tlsHost=your-domain.tld --i2p
docker:
docker build -t eyedeekay/reseed .
docker-push: docker
docker push --disable-content-trust=false eyedeekay/reseed:$(VERSION)
users:
docker run --rm eyedeekay/reseed cat /etc/passwd
docker-ls:
docker run --rm \
--user $(I2P_UID) \
--group-add $(I2P_GID) \
--name reseed \
--publish 8443:8443 \
--volume /var/lib/i2p/i2p-config/netDb:/var/lib/i2p/i2p-config/netDb \
eyedeekay/reseed ls /var/lib/i2p/i2p-config -lah
docker-server:
docker run -itd \
--name reseed \
--user $(I2P_UID) \
--group-add $(I2P_GID) \
--publish 8443:8443 \
--restart=always \
--volume /var/lib/i2p/i2p-config/netDb:/var/lib/i2p/i2p-config/netDb:z \
--volume reseed-keys:/var/lib/i2p/i2p-config/reseed \
eyedeekay/reseed \
--signer=hankhill19580@gmail.com
docker logs -f reseed
docker-run:
docker run -itd \
--name reseed \
--user $(I2P_UID) \
--group-add $(I2P_GID) \
--publish 8443:8443 \
--volume /var/lib/i2p/i2p-config/netDb:/var/lib/i2p/i2p-config/netDb:z \
--volume reseed-keys:/var/lib/i2p/i2p-config/reseed \
eyedeekay/reseed \
--signer=hankhill19580@gmail.com
docker-homerun:
docker run -itd \
--name reseed \
--user 1000 \
--group-add 1000 \
--publish 8443:8443 \
--volume $(HOME)/i2p/netDb:/var/lib/i2p/i2p-config/netDb:z \
--volume reseed-keys:/var/lib/i2p/i2p-config/reseed:z \
eyedeekay/reseed \
--signer=hankhill19580@gmail.com
find . -name '*.go' -exec gofumpt -w -s -extra {} \;
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre/
export CGO_CFLAGS=-I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/
@@ -177,10 +114,15 @@ jar: gojava
echo $(JAVA_HOME)
./gojava -v -o reseed.jar -s . build ./reseed
release: version upload binary upload-bin plugins upload-su3s debs upload-debs
release: version plugins upload-su3s
tag:
git tag -a v$(VERSION) -m "Release $(VERSION)"
git push --tags
version:
head -n 5 README.md | github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -d -; true
#head -n 5 README.md | github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -d -; true
echo "make version is deprecated, use make tag instead"
delete-version:
github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION)
@@ -188,22 +130,6 @@ delete-version:
edit:
cat README.md | github-release edit -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -d -
upload: tar
github-release upload -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f reseed-tools.tar.gz -n "reseed-tools.tar.gz"; true
binary:
##export GOOS=darwin; export GOARCH=amd64; make build
###export GOOS=darwin; export GOARCH=arm64; make build
export GOOS=linux; export GOARCH=amd64; make build
export GOOS=linux; export GOARCH=386; make build
export GOOS=linux; export GOARCH=arm; make build
export GOOS=linux; export GOARCH=arm64; make build
export GOOS=openbsd; export GOARCH=amd64; make build
export GOOS=freebsd; export GOARCH=386; make build
export GOOS=freebsd; export GOARCH=amd64; make build
export GOOS=windows; export GOARCH=amd64; make build
export GOOS=windows; export GOARCH=386; make build
plugins:
#export GOOS=darwin; export GOARCH=amd64; make su3s
#export GOOS=darwin; export GOARCH=arm64; make su3s
@@ -223,25 +149,6 @@ debs:
export GOOS=linux; export GOARCH=arm; make build checkinstall
export GOOS=linux; export GOARCH=arm64; make build checkinstall
upload-debs:
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
#export GOOS=darwin; export GOARCH=arm64; make upload-single-bin
export GOOS=linux; export GOARCH=386; make upload-single-bin
export GOOS=linux; export GOARCH=amd64; make upload-single-bin
export GOOS=linux; export GOARCH=arm; make upload-single-bin
export GOOS=linux; export GOARCH=arm64; make upload-single-bin
export GOOS=openbsd; export GOARCH=amd64; make upload-single-bin
export GOOS=freebsd; export GOARCH=386; make upload-single-bin
export GOOS=freebsd; export GOARCH=amd64; make upload-single-bin
export GOOS=windows; export GOARCH=amd64; make upload-single-bin
export GOOS=windows; export GOARCH=386; make upload-single-bin
rm-su3s:
rm *.su3 -f
@@ -274,12 +181,6 @@ upload-su3s:
download-single-su3:
wget-ds "https://github.com/eyedeekay/reseed-tools/releases/download/v$(VERSION)/reseed-tools-$(GOOS)-$(GOARCH).su3"
upload-single-deb:
github-release upload -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f reseed-tools_$(VERSION)-1_"$(GOARCH)".deb -l "`sha256sum reseed-tools_$(VERSION)-1_$(GOARCH).deb`" -n "reseed-tools_$(VERSION)-1_$(GOARCH).deb"; true
upload-single-bin:
github-release upload -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f reseed-tools-"$(GOOS)"-"$(GOARCH)" -l "`sha256sum reseed-tools-$(GOOS)-$(GOARCH)`" -n "reseed-tools-$(GOOS)"-"$(GOARCH)"; true
upload-single-su3:
github-release upload -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(APP) -t v$(VERSION) -f reseed-tools-"$(GOOS)"-"$(GOARCH).su3" -l "`sha256sum reseed-tools-$(GOOS)-$(GOARCH).su3`" -n "reseed-tools-$(GOOS)"-"$(GOARCH).su3"; true

View File

@@ -6,6 +6,7 @@ import (
"github.com/urfave/cli/v3"
)
// NewKeygenCommand creates a new CLI command for generating keys.
func NewKeygenCommand() *cli.Command {
return &cli.Command{
Name: "keygen",

View File

@@ -56,6 +56,7 @@ func providedReseeds(c *cli.Context) []string {
return reseed.AllReseeds
}
// NewReseedCommand creates a new CLI command for starting a reseed server.
func NewReseedCommand() *cli.Command {
ndb, err := getmeanetdb.WhereIstheNetDB()
if err != nil {
@@ -394,7 +395,7 @@ func reseedAction(c *cli.Context) error {
if onionTlsHost == "" {
onionTlsHost = torutil.OnionServiceIDFromPrivateKey(ed25519.PrivateKey(ok)) + ".onion"
}
err = ioutil.WriteFile(c.String("onionKey"), ok, 0644)
err = ioutil.WriteFile(c.String("onionKey"), ok, 0o644)
if err != nil {
log.Fatalln(err.Error())
}
@@ -655,7 +656,6 @@ func reseedI2P(c *cli.Context, i2pTlsCert, i2pTlsKey string, i2pIdentKey i2pkeys
if err := server.ListenAndServeI2P(c.String("samaddr"), i2pIdentKey); err != nil {
log.Fatalln(err)
}
}
log.Printf("Onion server started on %s\n", server.Addr)
@@ -710,7 +710,7 @@ func downloadRemoteNetDB(remote, password, path, samaddr string) error {
if bodyBytes, err := ioutil.ReadAll(resp.Body); err != nil {
return err
} else {
if err := ioutil.WriteFile("netDb.tar.gz", bodyBytes, 0644); err != nil {
if err := ioutil.WriteFile("netDb.tar.gz", bodyBytes, 0o644); err != nil {
return err
} else {
dbPath := filepath.Join(path, "reseed-netDb")

View File

@@ -19,6 +19,8 @@ import (
"github.com/eyedeekay/onramp"
)
// NewShareCommand creates a new CLI Command for sharing the netDb over I2P with a password.
// Can be used to combine the local netDb with the netDb of a remote I2P router.
func NewShareCommand() *cli.Command {
ndb, err := getmeanetdb.WhereIstheNetDB()
if err != nil {

View File

@@ -55,9 +55,11 @@ type MyUser struct {
func (u *MyUser) GetEmail() string {
return u.Email
}
func (u MyUser) GetRegistration() *registration.Resource {
return u.Registration
}
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
return u.key
}
@@ -150,7 +152,7 @@ func checkUseAcmeCert(tlsHost, signer, cadirurl string, tlsCert, tlsKey *string,
return err
}
filename := tlsHost + signer + ".acme.key"
keypem, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
keypem, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return err
}
@@ -201,8 +203,8 @@ func renewAcmeIssuedCert(client *lego.Client, user MyUser, tlsHost string, tlsCe
return err
}
ioutil.WriteFile(tlsHost+".pem", certificates.PrivateKey, 0600)
ioutil.WriteFile(tlsHost+".crt", certificates.Certificate, 0600)
ioutil.WriteFile(tlsHost+".pem", certificates.PrivateKey, 0o600)
ioutil.WriteFile(tlsHost+".crt", certificates.Certificate, 0o600)
// ioutil.WriteFile(tlsHost+".crl", certificates.PrivateKey, 0600)
*tlsCert = tlsHost + ".crt"
*tlsKey = tlsHost + ".pem"
@@ -238,8 +240,8 @@ func newAcmeIssuedCert(client *lego.Client, user MyUser, tlsHost string, tlsCert
return err
}
ioutil.WriteFile(tlsHost+".pem", certificates.PrivateKey, 0600)
ioutil.WriteFile(tlsHost+".crt", certificates.Certificate, 0600)
ioutil.WriteFile(tlsHost+".pem", certificates.PrivateKey, 0o600)
ioutil.WriteFile(tlsHost+".crt", certificates.Certificate, 0o600)
// ioutil.WriteFile(tlsHost+".crl", certificates.PrivateKey, 0600)
*tlsCert = tlsHost + ".crt"
*tlsKey = tlsHost + ".pem"
@@ -303,7 +305,7 @@ func createSigningCertificate(signerID string) error {
// save signing private key
privFile := signerFile(signerID) + ".pem"
keyOut, err := os.OpenFile(privFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
keyOut, err := os.OpenFile(privFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %v", privFile, err)
}
@@ -314,7 +316,7 @@ func createSigningCertificate(signerID string) error {
// CRL
crlFile := signerFile(signerID) + ".crl"
crlOut, err := os.OpenFile(crlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
crlOut, err := os.OpenFile(crlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %s", crlFile, err)
}
@@ -373,7 +375,7 @@ func CreateTLSCertificate(host string) error {
// save the TLS private key
privFile := host + ".pem"
keyOut, err := os.OpenFile(privFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
keyOut, err := os.OpenFile(privFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %v", privFile, err)
}
@@ -388,7 +390,7 @@ func CreateTLSCertificate(host string) error {
// CRL
crlFile := host + ".crl"
crlOut, err := os.OpenFile(crlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
crlOut, err := os.OpenFile(crlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %s", crlFile, err)
}

View File

@@ -32,7 +32,6 @@ func I2PHome() string {
return usrCheck
}
return ""
}
func NewSu3VerifyCommand() *cli.Command {
@@ -101,7 +100,7 @@ func su3VerifyAction(c *cli.Context) error {
if c.Bool("extract") {
// @todo: don't assume zip
ioutil.WriteFile("extracted.zip", su3File.BodyBytes(), 0755)
ioutil.WriteFile("extracted.zip", su3File.BodyBytes(), 0o755)
}
return nil
}

View File

@@ -1,2 +1,3 @@
#Edit the contact/signing email used by your reseed server here
# Edit the contact/signing email used by your reseed server here
# Required: Set a valid email address
export RESEED_EMAIL=""

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
### BEGIN INIT INFO
# Provides: reseed
# Required-Start: $local_fs $network $named $time $syslog
@@ -13,21 +13,58 @@ RUNAS=i2psvc
NETDBDIR=/var/lib/i2p/i2p-config/netDb
RUNDIR=/var/lib/i2p/i2p-config/reseed
MORE_OPTIONS=""
PIDFILE="$RUNDIR/reseed.pid"
TIMEOUT=60
if [ -f /etc/default/reseed ]; then
. /etc/default/reseed
fi
RUNOPTS=" reseed --yes=true --netdb=$NETDBDIR $MORE_OPTIONS "
start() {
start-stop-daemon --background --user $RUNAS --chuid $RUNAS --exec $SCRIPT --chdir $RUNDIR --make-pidfile --pidfile $RUNDIR/reseed.pid --start -- $RUNOPTS
if [ ! -d "$RUNDIR" ]; then
mkdir -p "$RUNDIR"
chown $RUNAS:$RUNAS "$RUNDIR"
fi
if [ -z "$RESEED_EMAIL" ]; then
echo "Error: RESEED_EMAIL not configured" >&2
return 1
fi
start-stop-daemon --background \
--user $RUNAS \
--chuid $RUNAS \
--exec $SCRIPT \
--chdir $RUNDIR \
--make-pidfile \
--pidfile $PIDFILE \
--start \
--startas $SCRIPT -- $RUNOPTS
for i in $(seq 1 $TIMEOUT); do
if status >/dev/null; then
return 0
fi
sleep 1
done
return 1
}
stop() {
start-stop-daemon --background --user $RUNAS --exec $SCRIPT --chdir $RUNDIR --remove-pidfile --pidfile $RUNDIR/reseed.pid --stop
start-stop-daemon \
--user $RUNAS \
--exec $SCRIPT \
--chdir $RUNDIR \
--remove-pidfile \
--pidfile $RUNDIR/reseed.pid \
--stop
}
status() {
start-stop-daemon --background --user $RUNAS --exec $SCRIPT --chdir $RUNDIR --pidfile $RUNDIR/reseed.pid --status
start-stop-daemon \
--user $RUNAS \
--exec $SCRIPT \
--chdir $RUNDIR \
--pidfile $RUNDIR/reseed.pid \
--status
}
restart() {
@@ -42,7 +79,7 @@ uninstall() {
if [ "$SURE" = "yes" ]; then
stop
rm -f "$PIDFILE"
echo "Notice: log file is not be removed: '$LOGFILE'" >&2
echo "Notice: log file is not removed" >&2
update-rc.d -f reseed remove
rm -fv "$0"
fi
@@ -65,5 +102,5 @@ case "$1" in
restart
;;
*)
echo "Usage: $0 {start|stop|restart|uninstall}"
echo "Usage: $0 {start|stop|restart|uninstall|status}"
esac

View File

@@ -11,6 +11,10 @@ ExecStart=/usr/bin/reseed-tools reseed --yes=true --netdb=/var/lib/i2p/i2p-confi
Restart=always
RestartSec=10
RuntimeMaxSec=43200
StandardOutput=journal
StandardError=journal
#MemoryMax=512M
#CPUQuota=50%
[Install]
WantedBy=multi-user.target

View File

@@ -2,4 +2,5 @@
# without it the reseed will fail to start.
[Service]
# Required: Set a valid email address
Environment="RESEED_EMAIL="

View File

@@ -33,11 +33,14 @@ var SupportedLanguages = []language.Tag{
language.Korean,
language.Bengali,
}
var CachedLanguagePages = map[string]string{}
var CachedDataPages = map[string][]byte{}
var (
CachedLanguagePages = map[string]string{}
CachedDataPages = map[string][]byte{}
)
func StableContentPath() (string, error) {
var BaseContentPath, ContentPathError = ContentPath()
BaseContentPath, ContentPathError := ContentPath()
if _, err := os.Stat(BaseContentPath); os.IsNotExist(err) {
if err := unembed.Unembed(f, BaseContentPath); err != nil {
return "", err
@@ -59,6 +62,7 @@ var header = []byte(`<!DOCTYPE html>
<script src="script.js"></script>
</head>
<body>`)
var footer = []byte(` </body>
</html>`)
@@ -69,7 +73,7 @@ func ContentPath() (string, error) {
if err != nil {
return "", err
}
//exPath := filepath.Dir(ex)
// exPath := filepath.Dir(ex)
if _, err := os.Stat(filepath.Join(exPath, "content")); err != nil {
return "", err
}

View File

@@ -60,11 +60,11 @@ func PingWriteContent(urlInput string) error {
result, err := Ping(urlInput)
if result {
log.Printf("Ping: %s OK", urlInput)
err := ioutil.WriteFile(path, []byte("Alive: Status OK"), 0644)
err := ioutil.WriteFile(path, []byte("Alive: Status OK"), 0o644)
return err
} else {
log.Printf("Ping: %s %s", urlInput, err)
err := ioutil.WriteFile(path, []byte("Dead: "+err.Error()), 0644)
err := ioutil.WriteFile(path, []byte("Dead: "+err.Error()), 0o644)
return err
}
}

View File

@@ -114,7 +114,7 @@ func SecureRandomAlphaString() string {
// SecureRandomBytes returns the requested number of bytes using crypto/rand
func SecureRandomBytes(length int) []byte {
var randomBytes = make([]byte, length)
randomBytes := make([]byte, length)
_, err := rand.Read(randomBytes)
if err != nil {
log.Fatal("Unable to generate random bytes")

View File

@@ -1,3 +1,3 @@
package reseed
const Version = "0.3.3"
const Version = "0.3.4"

View File

@@ -105,7 +105,7 @@ func NewSigningCertificate(signerID string, privateKey *rsa.PrivateKey) ([]byte,
publicKey := &privateKey.PublicKey
// create a self-signed certificate. template = parent
var parent = template
parent := template
cert, err := x509.CreateCertificate(rand.Reader, template, parent, publicKey, privateKey)
if err != nil {
return nil, err