lots o progress
This commit is contained in:
37
config.go
Normal file
37
config.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeDirs() {
|
||||||
|
err := os.MkdirAll("/etc/certman", 0775)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
fmt.Println("Unable to create config directory")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Mkdir("/etc/certman/conf", 0775)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
fmt.Println("Unable to create config directory")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO make domain level configs override global config
|
||||||
|
func createConfig() {
|
||||||
|
confPath := "/etc/certman/certman.conf"
|
||||||
|
configBytes := []byte("[Git]\nhost = github\nserver = https://gitea.instance.com\nusername = user\napi_token = xxxxxxxxxxxxxxxx\norg_name = org\ntemplate_name = template\n\n[Crypto]\ncert_path = /etc/certman/crypto/cert.pem\nkey_path = /etc/certman/crypto/key.pem")
|
||||||
|
|
||||||
|
createFile(confPath, configBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNewDomainConfig(domain string) {
|
||||||
|
data := []byte("[Cloudflare]\ncf_email = email@example.com\ncf_api_token = xxxxxxxxxxxxxxxx\n\n[Certificates]\ncerts_path = ./certs/" + domain + "\nsubdomains =")
|
||||||
|
createFile("/etc/certman/"+domain+".conf", data)
|
||||||
|
}
|
||||||
58
crypto.go
Normal file
58
crypto.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cert *x509.Certificate
|
||||||
|
var key *rsa.PrivateKey
|
||||||
|
|
||||||
|
func encryptBytes(data []byte) []byte {
|
||||||
|
if cert == nil || key == nil {
|
||||||
|
loadCerts()
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, cert.PublicKey.(*rsa.PublicKey), data)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error encrypting data,", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptBytes(data []byte) []byte {
|
||||||
|
if cert == nil || key == nil {
|
||||||
|
loadCerts()
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, key, data)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error decrypting data,", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCerts() {
|
||||||
|
var err error
|
||||||
|
certBytes, err := os.ReadFile(config.GetAsString("Crypto.cert_path"))
|
||||||
|
keyBytes, err := os.ReadFile(config.GetAsString("Crypto.key_path"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error reading cert or key,", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err = x509.ParseCertificate(certBytes)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error parsing certificate,", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
key, err = x509.ParsePKCS1PrivateKey(keyBytes)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error parsing private key,", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
[Git]
|
[Git]
|
||||||
|
host = github
|
||||||
server = https://gitea.instance.com
|
server = https://gitea.instance.com
|
||||||
username = user
|
username = user
|
||||||
api_token = xxxxxxxxxxxxxxxx
|
api_token = xxxxxxxxxxxxxxxx
|
||||||
|
|||||||
139
git.go
Normal file
139
git.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
"github.com/google/go-github/v55/github"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createGithubClient() *github.Client {
|
||||||
|
return github.NewClient(nil).WithAuthToken(config.GetAsString("Git.api_token"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGiteaClient() *gitea.Client {
|
||||||
|
client, err := gitea.NewClient(config.GetAsString("Git.server"), gitea.SetToken(config.GetAsString("Git.api_token")))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error connecting to gitea instance: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGithubRepo(domain *Domain, client *github.Client) string {
|
||||||
|
name := domain.name
|
||||||
|
owner := domain.config.GetAsString("Repo.owner")
|
||||||
|
description := domain.description
|
||||||
|
private := true
|
||||||
|
includeAllBranches := false
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
template := &github.TemplateRepoRequest{
|
||||||
|
Name: name,
|
||||||
|
Owner: &owner,
|
||||||
|
Description: description,
|
||||||
|
Private: &private,
|
||||||
|
IncludeAllBranches: &includeAllBranches,
|
||||||
|
}
|
||||||
|
repo, _, err := client.Repositories.CreateFromTemplate(ctx, config.GetAsString("Git.org_name"), config.GetAsString("Git.template_name"), template)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating repository from template,", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return *repo.CloneURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGiteaRepo() string {
|
||||||
|
options := gitea.CreateRepoFromTemplateOption{
|
||||||
|
Avatar: true,
|
||||||
|
Description: "Certificates storage for " + domain,
|
||||||
|
GitContent: true,
|
||||||
|
GitHooks: true,
|
||||||
|
Labels: true,
|
||||||
|
Name: domain + "-certificates",
|
||||||
|
Owner: config.GetAsString("Git.org_name"),
|
||||||
|
Private: true,
|
||||||
|
Topics: true,
|
||||||
|
Webhooks: true,
|
||||||
|
}
|
||||||
|
giteaRepo, _, err := giteaClient.CreateRepoFromTemplate(config.GetAsString("Git.org_name"), config.GetAsString("Git.template_name"), options)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error creating repo: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return giteaRepo.CloneURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneRepo(url string) (*git.Repository, *git.Worktree) {
|
||||||
|
repository, err := git.Clone(storage, fs, &git.CloneOptions{URL: url, Auth: creds})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error clone git repo: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
workingTree, err := repo.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting worktree from repo: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return repository, workingTree
|
||||||
|
}
|
||||||
|
|
||||||
|
func addAndPushCerts() {
|
||||||
|
certs, err := os.ReadDir(config.GetAsString("Certificates.certs_path") + "/certificates")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading from directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
for _, cert := range certs {
|
||||||
|
if strings.HasPrefix(cert.Name(), domain) {
|
||||||
|
file, err := fs.Create(cert.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error copying cert to memfs: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
certFile, err := os.ReadFile(config.GetAsString("Certificates.certs_path") + "/certificates/" + cert.Name())
|
||||||
|
certFile = encryptBytes(certFile)
|
||||||
|
_, err = file.Write(certFile)
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error writing to memfs: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
_, err = workTree.Add(cert.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error adding certificate %v: %v", cert.Name(), err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := workTree.Status()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting repo status: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("Work Tree Status:\n" + status.String())
|
||||||
|
signature := &object.Signature{
|
||||||
|
Name: "Cert Manager",
|
||||||
|
Email: config.GetAsString("Git.email"),
|
||||||
|
When: time.Now(),
|
||||||
|
}
|
||||||
|
_, err = workTree.Commit("Update "+domain+" @ "+time.Now().Format("Mon Jan _2 2006 15:04:05 MST"), &git.CommitOptions{Author: signature, Committer: signature})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error committing certs: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = repo.Push(&git.PushOptions{Auth: creds, Force: true, RemoteName: "origin"})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error pushing to origin: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Successfully uploaded to " + config.GetAsString("Git.server") + "/" + config.GetAsString("Git.org_name") + "/" + domain + "-certificates.git")
|
||||||
|
}
|
||||||
6
go.mod
6
go.mod
@@ -19,6 +19,8 @@ require (
|
|||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/google/go-github/v55 v55.0.0 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.2.1 // indirect
|
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||||
github.com/imdario/mergo v0.3.15 // indirect
|
github.com/imdario/mergo v0.3.15 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
@@ -28,9 +30,9 @@ require (
|
|||||||
github.com/skeema/knownhosts v1.1.1 // indirect
|
github.com/skeema/knownhosts v1.1.1 // indirect
|
||||||
github.com/src-d/gcfg v1.4.0 // indirect
|
github.com/src-d/gcfg v1.4.0 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.12.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
|
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
|||||||
11
go.sum
11
go.sum
@@ -43,7 +43,12 @@ github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhc
|
|||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
|
||||||
|
github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
||||||
@@ -102,6 +107,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
|||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||||
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.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.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/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
@@ -138,11 +145,14 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||||
|
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -151,6 +161,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.7.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.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
|||||||
132
main.go
132
main.go
@@ -5,21 +5,20 @@ import (
|
|||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.nevets.tech/Steven/ezconf"
|
"git.nevets.tech/Steven/ezconf"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
"github.com/go-git/go-git/v5/storage/memory"
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
"github.com/google/go-github/v55/github"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var config *ezconf.Configuration
|
var config *ezconf.Configuration
|
||||||
|
var githubClient *github.Client
|
||||||
var giteaClient *gitea.Client
|
var giteaClient *gitea.Client
|
||||||
var domain string
|
var domain string
|
||||||
var legoBaseArgs []string
|
var legoBaseArgs []string
|
||||||
@@ -31,19 +30,20 @@ var creds *http.BasicAuth
|
|||||||
|
|
||||||
var repo *git.Repository
|
var repo *git.Repository
|
||||||
|
|
||||||
|
//TODO create logic for domain based configs
|
||||||
|
//TODO create logic for gh vs gt repos
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
makeDirs()
|
||||||
|
createConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func maindis() {
|
||||||
|
config = ezconf.NewConfiguration("/etc/certman/certman.conf")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
args := os.Args
|
args := os.Args
|
||||||
|
|
||||||
// -c
|
|
||||||
hasConfig, configIndex := contains(args, "-c")
|
|
||||||
if hasConfig {
|
|
||||||
config = ezconf.NewConfiguration(args[configIndex+1])
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Error, no config passed. Please add '-c /path/to/config.ini' to the command\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -d
|
// -d
|
||||||
hasDomain, domainIndex := contains(args, "-d")
|
hasDomain, domainIndex := contains(args, "-d")
|
||||||
if hasDomain {
|
if hasDomain {
|
||||||
@@ -82,11 +82,7 @@ func main() {
|
|||||||
Username: config.GetAsString("Git.username"),
|
Username: config.GetAsString("Git.username"),
|
||||||
Password: config.GetAsString("Git.api_token"),
|
Password: config.GetAsString("Git.api_token"),
|
||||||
}
|
}
|
||||||
giteaClient, err = gitea.NewClient(config.GetAsString("Git.server"), gitea.SetToken(config.GetAsString("Git.api_token")))
|
giteaClient = createGiteaClient()
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error connecting to gitea instance: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
storage = memory.NewStorage()
|
storage = memory.NewStorage()
|
||||||
fs = memfs.New()
|
fs = memfs.New()
|
||||||
@@ -96,13 +92,13 @@ func main() {
|
|||||||
case "gen":
|
case "gen":
|
||||||
{
|
{
|
||||||
url := createGiteaRepo()
|
url := createGiteaRepo()
|
||||||
cloneRepo(url)
|
repo, workTree = cloneRepo(url)
|
||||||
fixUpdateSh()
|
fixUpdateSh()
|
||||||
cmd = exec.Command("lego", legoNewSiteArgs...)
|
cmd = exec.Command("lego", legoNewSiteArgs...)
|
||||||
}
|
}
|
||||||
case "renew":
|
case "renew":
|
||||||
{
|
{
|
||||||
cloneRepo(config.GetAsString("Git.server") + "/" + config.GetAsString("Git.org_name") + "/" + domain + "-certificates.git")
|
repo, workTree = cloneRepo(config.GetAsString("Git.server") + "/" + config.GetAsString("Git.org_name") + "/" + domain + "-certificates.git")
|
||||||
cmd = exec.Command("lego", legoRenewSiteArgs...)
|
cmd = exec.Command("lego", legoRenewSiteArgs...)
|
||||||
}
|
}
|
||||||
case "gen-cert-only":
|
case "gen-cert-only":
|
||||||
@@ -116,7 +112,7 @@ func main() {
|
|||||||
case "git":
|
case "git":
|
||||||
{
|
{
|
||||||
url := createGiteaRepo()
|
url := createGiteaRepo()
|
||||||
cloneRepo(url)
|
repo, workTree = cloneRepo(url)
|
||||||
fixUpdateSh()
|
fixUpdateSh()
|
||||||
addAndPushCerts()
|
addAndPushCerts()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
@@ -159,42 +155,6 @@ func main() {
|
|||||||
addAndPushCerts()
|
addAndPushCerts()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createGiteaRepo() string {
|
|
||||||
options := gitea.CreateRepoFromTemplateOption{
|
|
||||||
Avatar: true,
|
|
||||||
Description: "Certificates storage for " + domain,
|
|
||||||
GitContent: true,
|
|
||||||
GitHooks: true,
|
|
||||||
Labels: true,
|
|
||||||
Name: domain + "-certificates",
|
|
||||||
Owner: config.GetAsString("Git.org_name"),
|
|
||||||
Private: true,
|
|
||||||
Topics: true,
|
|
||||||
Webhooks: true,
|
|
||||||
}
|
|
||||||
giteaRepo, _, err := giteaClient.CreateRepoFromTemplate(config.GetAsString("Git.org_name"), config.GetAsString("Git.template_name"), options)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error creating repo: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return giteaRepo.CloneURL
|
|
||||||
}
|
|
||||||
|
|
||||||
func cloneRepo(url string) {
|
|
||||||
var err error
|
|
||||||
repo, err = git.Clone(storage, fs, &git.CloneOptions{URL: url, Auth: creds})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error clone git repo: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
workTree, err = repo.Worktree()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error getting worktree from repo: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixUpdateSh() {
|
func fixUpdateSh() {
|
||||||
oldUpdateSh, err := fs.Open("update.sh")
|
oldUpdateSh, err := fs.Open("update.sh")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -222,60 +182,6 @@ func fixUpdateSh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addAndPushCerts() {
|
|
||||||
//TODO integrate SOPS api when stable release
|
|
||||||
certs, err := os.ReadDir(config.GetAsString("Certificates.certs_path") + "/certificates")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error reading from directory: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
for _, cert := range certs {
|
|
||||||
if strings.HasPrefix(cert.Name(), domain) {
|
|
||||||
file, err := fs.Create(cert.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error copying cert to memfs: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
certFile, err := os.ReadFile(config.GetAsString("Certificates.certs_path") + "/certificates/" + cert.Name())
|
|
||||||
_, err = file.Write(certFile)
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error writing to memfs: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
_, err = workTree.Add(cert.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error adding certificate %v: %v", cert.Name(), err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
status, err := workTree.Status()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error getting repo status: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Println("Work Tree Status:\n" + status.String())
|
|
||||||
signature := &object.Signature{
|
|
||||||
Name: "Cert Manager",
|
|
||||||
Email: "certs@nevets.tech",
|
|
||||||
When: time.Now(),
|
|
||||||
}
|
|
||||||
_, err = workTree.Commit("Update "+domain+" @ "+time.Now().Format("Mon Jan _2 2006 15:04:05 MST"), &git.CommitOptions{Author: signature, Committer: signature})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error committing certs: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
err = repo.Push(&git.PushOptions{Auth: creds, Force: true, RemoteName: "origin"})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error pushing to origin: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Successfully uploaded to " + config.GetAsString("Git.server") + "/" + config.GetAsString("Git.org_name") + "/" + domain + "-certificates.git")
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(slice []string, value string) (sliceHas bool, index int) {
|
func contains(slice []string, value string) (sliceHas bool, index int) {
|
||||||
for i, entry := range slice {
|
for i, entry := range slice {
|
||||||
if entry == value {
|
if entry == value {
|
||||||
|
|||||||
53
util.go
Normal file
53
util.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
"fmt"
|
||||||
|
"git.nevets.tech/Steven/ezconf"
|
||||||
|
"github.com/google/go-github/v55/github"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Domain struct {
|
||||||
|
name *string
|
||||||
|
config *ezconf.Configuration
|
||||||
|
description *string
|
||||||
|
ghClient *github.Client
|
||||||
|
gtClient *gitea.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFile(fileName string, data []byte) {
|
||||||
|
fileInfo, err := os.Stat(fileName)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
file, err := os.Create(fileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating configuration file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = file.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error writing to file;", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Error opening configuration file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if fileInfo.Size() == 0 {
|
||||||
|
file, err := os.Create(fileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error creating configuration file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = file.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error writing to file:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user