Updated deps, go.19 migration, nginx template work

This commit is contained in:
Jamie Curnow
2022-11-08 10:03:45 +10:00
parent 8d37f5df8d
commit c00b690ed3
23 changed files with 375 additions and 376 deletions

View File

@ -117,6 +117,21 @@ func getQueryVarInt(r *http.Request, varName string, required bool, defaultValue
return varInt, nil
}
/*
func getQueryVarBool(r *http.Request, varName string, required bool, defaultValue bool) (bool, error) {
queryValues := r.URL.Query()
varValue := queryValues.Get(varName)
if varValue == "" && required {
return false, fmt.Errorf("%v was not supplied in the request", varName)
} else if varValue == "" {
return defaultValue, nil
}
return varValue == "true" || varValue == "1" || varValue == "on", nil
}
*/
func getURLParamInt(r *http.Request, varName string) (int, error) {
required := true
defaultValue := 0

View File

@ -88,6 +88,8 @@ func UpdateHostTemplate() func(http.ResponseWriter, *http.Request) {
return
}
// reconfigure, _ := getQueryVarBool(r, "reconfigure", false, false)
hostTemplate, err := hosttemplate.GetByID(templateID)
if err != nil {
h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil)

View File

@ -2,7 +2,7 @@ package middleware
import (
"context"
"io/ioutil"
"io"
"net/http"
c "npm/internal/api/context"
@ -15,7 +15,7 @@ func BodyContext() func(http.Handler) http.Handler {
// Grab the Body Data
var body []byte
if r.Body != nil {
body, _ = ioutil.ReadAll(r.Body)
body, _ = io.ReadAll(r.Body)
}
// Add it to the context
ctx := r.Context()

View File

@ -38,12 +38,6 @@ var headersAllowedByCORS = []string{
"User-Agent",
"Cache-Control",
"Accept-Encoding",
"X-Jumbo-AppKey",
"X-Jumbo-SKey",
"X-Jumbo-SV",
"X-Jumbo-Timestamp",
"X-Jumbo-Version",
"X-Jumbo-Customer-Id",
}
// Cors handles cors headers

View File

@ -3,6 +3,7 @@ package api
import (
"fmt"
"net/http"
"time"
"npm/internal/logger"
)
@ -12,7 +13,14 @@ const httpPort = 3000
// StartServer creates a http server
func StartServer() {
logger.Info("Server starting on port %v", httpPort)
err := http.ListenAndServe(fmt.Sprintf(":%v", httpPort), NewRouter())
server := &http.Server{
Addr: fmt.Sprintf(":%v", httpPort),
Handler: NewRouter(),
ReadHeaderTimeout: 3 * time.Second,
}
err := server.ListenAndServe()
if err != nil {
logger.Error("HttpListenError", err)
}

View File

@ -8,7 +8,6 @@ import (
"encoding/asn1"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"npm/internal/logger"
@ -41,9 +40,9 @@ func loadKeys() {
// Load keys from disk
// nolint:gosec
publicKeyBytes, publicKeyBytesErr := ioutil.ReadFile(publicKeyFile)
publicKeyBytes, publicKeyBytesErr := os.ReadFile(publicKeyFile)
// nolint:gosec
privateKeyBytes, privateKeyBytesErr := ioutil.ReadFile(privateKeyFile)
privateKeyBytes, privateKeyBytesErr := os.ReadFile(privateKeyFile)
PublicKey = string(publicKeyBytes)
PrivateKey = string(privateKeyBytes)
@ -96,14 +95,14 @@ func generateKeys() {
}
func saveKeys() {
err := ioutil.WriteFile(publicKeyFile, []byte(PublicKey), 0600)
err := os.WriteFile(publicKeyFile, []byte(PublicKey), 0600)
if err != nil {
logger.Error("PublicKeyWriteError", err)
} else {
logger.Info("Saved Public Key: %s", publicKeyFile)
}
err = ioutil.WriteFile(privateKeyFile, []byte(PrivateKey), 0600)
err = os.WriteFile(privateKeyFile, []byte(PrivateKey), 0600)
if err != nil {
logger.Error("PrivateKeyWriteError", err)
} else {

View File

@ -264,3 +264,38 @@ func (m *Model) Request() error {
logger.Info("Request for certificate for: #%d %v was completed", m.ID, m.Name)
return nil
}
// GetTemplate will convert the Model to a Template
func (m *Model) GetTemplate() Template {
domainNames, _ := m.DomainNames.AsStringArray()
t := Template{
ID: m.ID,
CreatedOn: m.CreatedOn.Time.String(),
ModifiedOn: m.ModifiedOn.Time.String(),
ExpiresOn: m.ExpiresOn.AsString(),
Type: m.Type,
UserID: m.UserID,
CertificateAuthorityID: m.CertificateAuthorityID,
DNSProviderID: m.DNSProviderID,
Name: m.Name,
DomainNames: domainNames,
Status: m.Status,
IsECC: m.IsECC,
// These are helpers for template generation
IsCustom: m.Type == TypeCustom,
IsAcme: m.Type != TypeCustom,
IsProvided: m.ID > 0 && m.Status == StatusProvided,
Folder: m.GetFolder(),
}
return t
}
// GetFolder returns the folder where these certs should exist
func (m *Model) GetFolder() string {
if m.Type == TypeCustom {
return fmt.Sprintf("%s/custom_ssl/npm-%d", config.Configuration.DataFolder, m.ID)
}
return fmt.Sprintf("%s/npm-%d", config.Configuration.Acmesh.CertHome, m.ID)
}

View File

@ -0,0 +1,22 @@
package certificate
// Template is the model given to the template parser, converted from the Model
type Template struct {
ID int
CreatedOn string
ModifiedOn string
ExpiresOn string
Type string
UserID int
CertificateAuthorityID int
DNSProviderID int
Name string
DomainNames []string
Status string
IsECC int
// These are helpers for template generation
IsCustom bool
IsAcme bool // non-custom
IsProvided bool
Folder string
}

View File

@ -139,3 +139,37 @@ func (m *Model) Expand(items []string) error {
return err
}
// GetTemplate will convert the Model to a Template
func (m *Model) GetTemplate() Template {
domainNames, _ := m.DomainNames.AsStringArray()
t := Template{
ID: m.ID,
CreatedOn: m.CreatedOn.Time.String(),
ModifiedOn: m.ModifiedOn.Time.String(),
UserID: m.UserID,
Type: m.Type,
HostTemplateID: m.HostTemplateID,
ListenInterface: m.ListenInterface,
DomainNames: domainNames,
UpstreamID: m.UpstreamID,
CertificateID: m.CertificateID,
AccessListID: m.AccessListID,
SSLForced: m.SSLForced,
CachingEnabled: m.CachingEnabled,
BlockExploits: m.BlockExploits,
AllowWebsocketUpgrade: m.AllowWebsocketUpgrade,
HTTP2Support: m.HTTP2Support,
HSTSEnabled: m.HSTSEnabled,
HSTSSubdomains: m.HSTSSubdomains,
Paths: m.Paths,
UpstreamOptions: m.UpstreamOptions,
AdvancedConfig: m.AdvancedConfig,
Status: m.Status,
ErrorMessage: m.ErrorMessage,
IsDisabled: m.IsDisabled,
}
return t
}

View File

@ -0,0 +1,29 @@
package host
// Template is the model given to the template parser, converted from the Model
type Template struct {
ID int
CreatedOn string
ModifiedOn string
UserID int
Type string
HostTemplateID int
ListenInterface string
DomainNames []string
UpstreamID int
CertificateID int
AccessListID int
SSLForced bool
CachingEnabled bool
BlockExploits bool
AllowWebsocketUpgrade bool
HTTP2Support bool
HSTSEnabled bool
HSTSSubdomains bool
IsDisabled bool
Paths string
UpstreamOptions string
AdvancedConfig string
Status string
ErrorMessage string
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"io"
"log"
"os"
"testing"
@ -144,7 +144,7 @@ func TestConfigure(t *testing.T) {
func BenchmarkLogLevelBelowThreshold(b *testing.B) {
l := NewLogger()
log.SetOutput(ioutil.Discard)
log.SetOutput(io.Discard)
defer func() {
log.SetOutput(os.Stderr)
}()
@ -157,7 +157,7 @@ func BenchmarkLogLevelBelowThreshold(b *testing.B) {
func BenchmarkLogLevelAboveThreshold(b *testing.B) {
l := NewLogger()
log.SetOutput(ioutil.Discard)
log.SetOutput(io.Discard)
defer func() {
log.SetOutput(os.Stderr)
}()

View File

@ -16,9 +16,8 @@ func ConfigureHost(h host.Model) error {
data := TemplateData{
ConfDir: fmt.Sprintf("%s/nginx/hosts", config.Configuration.DataFolder),
DataDir: config.Configuration.DataFolder,
CertsDir: config.Configuration.Acmesh.CertHome,
Host: &h,
Certificate: h.Certificate,
Host: h.GetTemplate(),
Certificate: h.Certificate.GetTemplate(),
}
filename := fmt.Sprintf("%s/host_%d.conf", data.ConfDir, h.ID)

View File

@ -15,22 +15,16 @@ func TestWriteTemplate(t *testing.T) {
# Host is disabled
{{else}}
server {
{{#if Certificate}}
{{#if Certificate.CertificateAuthorityID}}
# Acme SSL
include {{ConfDir}}/npm/conf.d/acme-challenge.conf;
include {{ConfDir}}/npm/conf.d/include/ssl-ciphers.conf;
ssl_certificate {{CertsDir}}/npm-{{Certificate.ID}}/fullchain.pem;
ssl_certificate_key {{CertsDir}}/npm-{{Certificate.ID}}/privkey.pem;
{{else}}
# Custom SSL
ssl_certificate {{DataDir}}/custom_ssl/npm-{{Certificate.ID}}/fullchain.pem;
ssl_certificate_key {{DataDir}}/custom_ssl/npm-{{Certificate.ID}}/privkey.pem;
{{#if Certificate.IsProvided}}
{{#if Certificate.IsAcme}}
include {{ConfDir}}/npm/conf.d/acme-challenge.conf;
include {{ConfDir}}/npm/conf.d/include/ssl-ciphers.conf;
{{/if}}
ssl_certificate {{Certificate.Folder}}/fullchain.pem;
ssl_certificate_key {{Certificate.Folder}}/privkey.pem;
{{/if}}
}
{{/if}}
`
type want struct {
@ -41,36 +35,49 @@ server {
tests := []struct {
name string
data TemplateData
host host.Model
cert certificate.Model
want want
}{
{
name: "Basic Template enabled",
data: TemplateData{
ConfDir: "/etc/nginx/conf.d",
Host: &host.Model{
IsDisabled: false,
},
Certificate: &certificate.Model{
CertificateAuthorityID: 0,
},
host: host.Model{
IsDisabled: false,
},
cert: certificate.Model{
ID: 77,
Status: certificate.StatusProvided,
Type: certificate.TypeHTTP,
CertificateAuthorityID: 99,
},
want: want{
output: "\nserver {\n # Custom SSL\n ssl_certificate /custom_ssl/npm-0/fullchain.pem;\n ssl_certificate_key /custom_ssl/npm-0/privkey.pem;\n \n}\n\n",
output: "\nserver {\n include /etc/nginx/conf.d/npm/conf.d/acme-challenge.conf;\n include /etc/nginx/conf.d/npm/conf.d/include/ssl-ciphers.conf;\n ssl_certificate /npm-77/fullchain.pem;\n ssl_certificate_key /npm-77/privkey.pem;\n}\n",
err: nil,
},
},
{
name: "Basic Template custom ssl",
host: host.Model{
IsDisabled: false,
},
cert: certificate.Model{
ID: 66,
Status: certificate.StatusProvided,
Type: certificate.TypeCustom,
},
want: want{
output: "\nserver {\n ssl_certificate /custom_ssl/npm-66/fullchain.pem;\n ssl_certificate_key /custom_ssl/npm-66/privkey.pem;\n}\n",
err: nil,
},
},
{
name: "Basic Template disabled",
data: TemplateData{
ConfDir: "/etc/nginx/conf.d",
DataDir: "/data",
CertsDir: "/acme.sh/certs",
Host: &host.Model{
IsDisabled: true,
},
host: host.Model{
IsDisabled: true,
},
cert: certificate.Model{},
want: want{
output: "\n # Host is disabled\n\n",
output: "\n # Host is disabled\n",
err: nil,
},
},
@ -78,7 +85,14 @@ server {
for _, test := range tests {
t.Run(test.name, func(st *testing.T) {
output, err := generateHostConfig(template, test.data)
templateData := TemplateData{
ConfDir: "/etc/nginx/conf.d",
DataDir: "/data",
Host: test.host.GetTemplate(),
Certificate: test.cert.GetTemplate(),
}
output, err := generateHostConfig(template, templateData)
assert.Equal(t, test.want.err, err)
assert.Equal(t, test.want.output, output)
})

View File

@ -2,7 +2,7 @@ package nginx
import (
"fmt"
"io/ioutil"
"os"
"npm/internal/entity/certificate"
"npm/internal/entity/host"
@ -11,13 +11,12 @@ import (
"github.com/aymerick/raymond"
)
// TemplateData ...
// TemplateData is a struct
type TemplateData struct {
ConfDir string
DataDir string
CertsDir string
Host *host.Model
Certificate *certificate.Model
Host host.Template
Certificate certificate.Template
}
func generateHostConfig(template string, data TemplateData) (string, error) {
@ -42,5 +41,5 @@ func writeTemplate(filename, template string, data TemplateData) error {
func writeConfigFile(filename, content string) error {
logger.Debug("Writing %s with:\n%s", filename, content)
// nolint: gosec
return ioutil.WriteFile(filename, []byte(content), 0644)
return os.WriteFile(filename, []byte(content), 0644)
}

View File

@ -52,3 +52,21 @@ func (d NullableDBDate) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Time.Unix())
}
// AsInt64 will attempt to return a unixtime
func (d NullableDBDate) AsInt64() int64 {
if d.Time == nil || d.Time.IsZero() {
return 0
}
return d.Time.Unix()
}
// AsString returns date as a string
func (d NullableDBDate) AsString() string {
if d.Time == nil || d.Time.IsZero() {
return ""
}
return d.Time.String()
}