Merge branch 'release/0.8.5'

* release/0.8.5:
  Bump boulder version to release-2018-12-10
  Limit docker-compose logfile sizes
  Update README.md
  Update README.md
  Add Go Report Card badge
  Make golint happy
This commit is contained in:
Arjan H
2018-12-21 13:14:51 +01:00
9 changed files with 259 additions and 188 deletions

View File

@@ -1,6 +1,8 @@
# LabCA
A private Certificate Authority for internal (lab) use, based on the open source ACME Automated Certificate Management Environment implementation from Let's Encrypt (tm).
[![Go Report Card](https://goreportcard.com/badge/github.com/hakwerk/labca)](https://goreportcard.com/report/github.com/hakwerk/labca)
**A private Certificate Authority for internal (lab) use, based on the open source ACME Automated Certificate Management Environment implementation from Let's Encrypt (tm).**
![08-dashboard](https://user-images.githubusercontent.com/44847421/48658726-ebd4c400-ea46-11e8-8cb1-43584dbc3719.jpg)

View File

@@ -1,5 +1,5 @@
diff --git a/docker-compose.yml b/docker-compose.yml
index b0e2c1f1..be6edbda 100644
index b0e2c1f1..30426452 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,9 +6,10 @@ services:
@@ -14,21 +14,31 @@ index b0e2c1f1..be6edbda 100644
- ./.gocache:/root/.cache/go-build
networks:
bluenet:
@@ -47,8 +48,9 @@ services:
@@ -47,8 +48,14 @@ services:
depends_on:
- bhsm
- bmysql
- entrypoint: test/entrypoint.sh
+ entrypoint: labca/entrypoint.sh
working_dir: /go/src/github.com/letsencrypt/boulder
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "500k"
+ max-file: "5"
+ restart: always
bhsm:
# To minimize fetching this should be the same version used above
image: letsencrypt/boulder-tools-go${TRAVIS_GO_VERSION:-1.11.1}:2018-10-18
@@ -61,8 +63,11 @@ services:
image: letsencrypt/boulder-tools-go${TRAVIS_GO_VERSION:-1.11.2}:2018-11-19
@@ -61,8 +68,16 @@ services:
bluenet:
aliases:
- boulder-hsm
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "500k"
+ max-file: "5"
+ restart: always
bmysql:
image: mariadb:10.3
@@ -37,14 +47,19 @@ index b0e2c1f1..be6edbda 100644
networks:
bluenet:
aliases:
@@ -72,16 +77,27 @@ services:
@@ -72,16 +87,37 @@ services:
command: mysqld --bind-address=0.0.0.0
logging:
driver: none
- netaccess:
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "500k"
+ max-file: "5"
+ restart: always
+ labca:
image: letsencrypt/boulder-tools-go${TRAVIS_GO_VERSION:-1.11.1}:2018-10-18
image: letsencrypt/boulder-tools-go${TRAVIS_GO_VERSION:-1.11.2}:2018-11-19
networks:
- bluenet
volumes:
@@ -62,6 +77,11 @@ index b0e2c1f1..be6edbda 100644
- bmysql
+ working_dir: /go/src/labca
+ command: ./setup.sh
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "500k"
+ max-file: "5"
+ restart: always
+
+volumes:

View File

@@ -8,26 +8,30 @@ import (
"strconv"
)
// BaseList is the generic base struct for showing lists of data
type BaseList struct {
Title string
TableClass string
Header []template.HTML
}
// Account contains the data representing an ACME account
type Account struct {
Id int
ID int
Status string
Contact string
Agreement string
InitialIp net.IP
InitialIP net.IP
CreatedAt string
}
// AccountList is a list of Account records
type AccountList struct {
BaseList
Rows []Account
}
// GetAccounts returns the list of accounts
func GetAccounts(w http.ResponseWriter, r *http.Request) (AccountList, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -54,7 +58,7 @@ func GetAccounts(w http.ResponseWriter, r *http.Request) (AccountList, error) {
for rows.Next() {
row := Account{}
err = rows.Scan(&row.Id, &row.Status, &row.Contact, &row.Agreement, &row.InitialIp, &row.CreatedAt)
err = rows.Scan(&row.ID, &row.Status, &row.Contact, &row.Agreement, &row.InitialIP, &row.CreatedAt)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AccountList{}, err
@@ -65,39 +69,45 @@ func GetAccounts(w http.ResponseWriter, r *http.Request) (AccountList, error) {
return Accounts, nil
}
// Order contains the data representing an ACME order
type Order struct {
Id int
RegistrationId int
ID int
RegistrationID int
Expires string
CertSerial string
BeganProc bool
Created string
}
// OrderList is a list of Order records
type OrderList struct {
BaseList
Rows []Order
}
// NameValue is a pair of a name and a value
type NameValue struct {
Name string
Value string
}
// BaseShow is the generic base struct for showing an individual data record
type BaseShow struct {
Title string
TableClass string
Rows []NameValue
Links []NameValHtml
Links []NameValHTML
Extra []template.HTML
}
// AccountShow contains the data of an ACME account and its related data lists
type AccountShow struct {
BaseShow
Related []CertificateList
Related2 []OrderList
}
// GetAccount returns an account
func GetAccount(w http.ResponseWriter, r *http.Request, id int) (AccountShow, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -124,7 +134,7 @@ func GetAccount(w http.ResponseWriter, r *http.Request, id int) (AccountShow, er
for rows.Next() {
row := Certificate{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Serial, &row.Status, &row.Issued, &row.Expires)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Serial, &row.Status, &row.Issued, &row.Expires)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AccountShow{}, err
@@ -149,7 +159,7 @@ func GetAccount(w http.ResponseWriter, r *http.Request, id int) (AccountShow, er
for rows.Next() {
row := Order{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AccountShow{}, err
@@ -175,22 +185,23 @@ func GetAccount(w http.ResponseWriter, r *http.Request, id int) (AccountShow, er
for rows.Next() {
row := Account{}
err = rows.Scan(&row.Id, &row.Status, &row.Contact, &row.Agreement, &row.InitialIp, &row.CreatedAt)
err = rows.Scan(&row.ID, &row.Status, &row.Contact, &row.Agreement, &row.InitialIP, &row.CreatedAt)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AccountShow{}, err
}
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"ID", strconv.Itoa(row.Id)})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"ID", strconv.Itoa(row.ID)})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Status", row.Status})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Contact", row.Contact})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Agreement", row.Agreement})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Initial IP", row.InitialIp.String()})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Initial IP", row.InitialIP.String()})
AccountDetails.Rows = append(AccountDetails.Rows, NameValue{"Created At", row.CreatedAt})
}
return AccountDetails, nil
}
// GetOrders returns the list of orders
func GetOrders(w http.ResponseWriter, r *http.Request) (OrderList, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -217,7 +228,7 @@ func GetOrders(w http.ResponseWriter, r *http.Request) (OrderList, error) {
for rows.Next() {
row := Order{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return OrderList{}, err
@@ -228,26 +239,30 @@ func GetOrders(w http.ResponseWriter, r *http.Request) (OrderList, error) {
return Orders, nil
}
// Auth contains the data representing an ACME auth
type Auth struct {
Id string
ID string
Identifier string
RegistrationId int
RegistrationID int
Status string
Expires string
Combinations string
}
// AuthList is a list of Auth records
type AuthList struct {
BaseList
Rows []Auth
}
// OrderShow contains the data of an ACME order and its related data lists
type OrderShow struct {
BaseShow
Related []AuthList
Related2 []BaseList
}
// GetOrder returns an order with the given id
func GetOrder(w http.ResponseWriter, r *http.Request, id int) (OrderShow, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -276,7 +291,7 @@ func GetOrder(w http.ResponseWriter, r *http.Request, id int) (OrderShow, error)
for rows.Next() {
row := Auth{}
err = rows.Scan(&row.Id, &row.Identifier, &row.RegistrationId, &row.Status, &row.Expires, &row.Combinations)
err = rows.Scan(&row.ID, &row.Identifier, &row.RegistrationID, &row.Status, &row.Expires, &row.Combinations)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return OrderShow{}, err
@@ -295,19 +310,19 @@ func GetOrder(w http.ResponseWriter, r *http.Request, id int) (OrderShow, error)
Title: "Order",
TableClass: "order_show",
Rows: []NameValue{},
Links: []NameValHtml{},
Links: []NameValHTML{},
},
Related: []AuthList{Authz},
}
for rows.Next() {
row := Order{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Expires, &row.CertSerial, &row.BeganProc, &row.Created)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return OrderShow{}, err
}
OrderDetails.Rows = append(OrderDetails.Rows, NameValue{"ID", strconv.Itoa(row.Id)})
OrderDetails.Rows = append(OrderDetails.Rows, NameValue{"ID", strconv.Itoa(row.ID)})
OrderDetails.Rows = append(OrderDetails.Rows, NameValue{"Expires", row.Expires})
v := "false"
if row.BeganProc {
@@ -316,13 +331,14 @@ func GetOrder(w http.ResponseWriter, r *http.Request, id int) (OrderShow, error)
OrderDetails.Rows = append(OrderDetails.Rows, NameValue{"Began Processing?", v})
OrderDetails.Rows = append(OrderDetails.Rows, NameValue{"Created", row.Created})
OrderDetails.Links = append(OrderDetails.Links, NameValHtml{"Certificate", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/certificates/" + row.CertSerial + "\">" + row.CertSerial + "</a>")})
OrderDetails.Links = append(OrderDetails.Links, NameValHtml{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationId) + "\">" + strconv.Itoa(row.RegistrationId) + "</a>")})
OrderDetails.Links = append(OrderDetails.Links, NameValHTML{"Certificate", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/certificates/" + row.CertSerial + "\">" + row.CertSerial + "</a>")})
OrderDetails.Links = append(OrderDetails.Links, NameValHTML{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationID) + "\">" + strconv.Itoa(row.RegistrationID) + "</a>")})
}
return OrderDetails, nil
}
// GetAuthz returns the list of authz
func GetAuthz(w http.ResponseWriter, r *http.Request) (AuthList, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -349,7 +365,7 @@ func GetAuthz(w http.ResponseWriter, r *http.Request) (AuthList, error) {
for rows.Next() {
row := Auth{}
err = rows.Scan(&row.Id, &row.Identifier, &row.RegistrationId, &row.Status, &row.Expires, &row.Combinations)
err = rows.Scan(&row.ID, &row.Identifier, &row.RegistrationID, &row.Status, &row.Expires, &row.Combinations)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AuthList{}, err
@@ -360,9 +376,10 @@ func GetAuthz(w http.ResponseWriter, r *http.Request) (AuthList, error) {
return Authz, nil
}
// Challenge contains the data representing an ACME challenge
type Challenge struct {
Id int
AuthId string
ID int
AuthID string
Type string
Status string
Validated string
@@ -370,22 +387,26 @@ type Challenge struct {
KeyAuth string
}
// ChallengeList is a list of Challenge records
type ChallengeList struct {
BaseList
Rows []Challenge
}
type NameValHtml struct {
// NameValHTML is a pair of a name and an HTML value
type NameValHTML struct {
Name string
Value template.HTML
}
// AuthShow contains the data of an ACME auth and its related data lists
type AuthShow struct {
BaseShow
Related []ChallengeList
Related2 []BaseList
}
// GetAuth returns an auth with the given id
func GetAuth(w http.ResponseWriter, r *http.Request, id string) (AuthShow, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -412,7 +433,7 @@ func GetAuth(w http.ResponseWriter, r *http.Request, id string) (AuthShow, error
for rows.Next() {
row := Challenge{}
err = rows.Scan(&row.Id, &row.AuthId, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
err = rows.Scan(&row.ID, &row.AuthID, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AuthShow{}, err
@@ -433,31 +454,32 @@ func GetAuth(w http.ResponseWriter, r *http.Request, id string) (AuthShow, error
Title: "Authorization",
TableClass: "auth_show",
Rows: []NameValue{},
Links: []NameValHtml{},
Links: []NameValHTML{},
},
Related: []ChallengeList{Challenges},
}
for rows.Next() {
row := Auth{}
err = rows.Scan(&row.Id, &row.Identifier, &row.RegistrationId, &row.Status, &row.Expires, &row.Combinations)
err = rows.Scan(&row.ID, &row.Identifier, &row.RegistrationID, &row.Status, &row.Expires, &row.Combinations)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return AuthShow{}, err
}
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"ID", row.Id})
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"ID", row.ID})
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"Identifier", row.Identifier})
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"Status", row.Status})
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"Expires", row.Expires})
AuthDetails.Rows = append(AuthDetails.Rows, NameValue{"Combinations", row.Combinations})
Link := NameValHtml{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationId) + "\">" + strconv.Itoa(row.RegistrationId) + "</a>")}
Link := NameValHTML{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationID) + "\">" + strconv.Itoa(row.RegistrationID) + "</a>")}
AuthDetails.Links = append(AuthDetails.Links, Link)
}
return AuthDetails, nil
}
// GetChallenges returns the list of challenges
func GetChallenges(w http.ResponseWriter, r *http.Request) (ChallengeList, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -484,7 +506,7 @@ func GetChallenges(w http.ResponseWriter, r *http.Request) (ChallengeList, error
for rows.Next() {
row := Challenge{}
err = rows.Scan(&row.Id, &row.AuthId, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
err = rows.Scan(&row.ID, &row.AuthID, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return ChallengeList{}, err
@@ -495,12 +517,14 @@ func GetChallenges(w http.ResponseWriter, r *http.Request) (ChallengeList, error
return Challenges, nil
}
// ChallengeShow contains the data of an ACME challenge and its related data lists
type ChallengeShow struct {
BaseShow
Related []ChallengeList
Related2 []BaseList
}
// GetChallenge returns a challenge with the given id
func GetChallenge(w http.ResponseWriter, r *http.Request, id int) (ChallengeShow, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -521,46 +545,49 @@ func GetChallenge(w http.ResponseWriter, r *http.Request, id int) (ChallengeShow
Title: "Challenge",
TableClass: "challenge_show",
Rows: []NameValue{},
Links: []NameValHtml{},
Links: []NameValHTML{},
},
Related: []ChallengeList{},
}
for rows.Next() {
row := Challenge{}
err = rows.Scan(&row.Id, &row.AuthId, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
err = rows.Scan(&row.ID, &row.AuthID, &row.Type, &row.Status, &row.Validated, &row.Token, &row.KeyAuth)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return ChallengeShow{}, err
}
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"ID", strconv.Itoa(row.Id)})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"ID", strconv.Itoa(row.ID)})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"Type", row.Type})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"Status", row.Status})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"Validated", row.Validated})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"Token", row.Token})
ChallengeDetails.Rows = append(ChallengeDetails.Rows, NameValue{"KeyAuth", row.KeyAuth})
Link := NameValHtml{"Authorization", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/authz/" + row.AuthId + "\">" + row.AuthId + "</a>")}
Link := NameValHTML{"Authorization", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/authz/" + row.AuthID + "\">" + row.AuthID + "</a>")}
ChallengeDetails.Links = append(ChallengeDetails.Links, Link)
}
return ChallengeDetails, nil
}
// Certificate contains the data representing an ACME certificate
type Certificate struct {
Id int
RegistrationId int
ID int
RegistrationID int
Serial string
Status string
Issued string
Expires string
}
// CertificateList is a list of Certificate records
type CertificateList struct {
BaseList
Rows []Certificate
}
// GetCertificates returns the list of certificates
func GetCertificates(w http.ResponseWriter, r *http.Request) (CertificateList, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -596,7 +623,7 @@ func GetCertificates(w http.ResponseWriter, r *http.Request) (CertificateList, e
for rows.Next() {
row := Certificate{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Serial, &row.Status, &row.Issued, &row.Expires)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Serial, &row.Status, &row.Issued, &row.Expires)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return CertificateList{}, err
@@ -607,15 +634,17 @@ func GetCertificates(w http.ResponseWriter, r *http.Request) (CertificateList, e
return Certificates, nil
}
// CertificateShow contains the data of an ACME certificate and its related data lists
type CertificateShow struct {
BaseShow
Related []BaseList
Related2 []BaseList
}
// CertificateExtra contains more detailed data of an ACME certificate
type CertificateExtra struct {
Id int
RegistrationId int
ID int
RegistrationID int
Serial string
Digest string
Issued string
@@ -660,6 +689,7 @@ func _getReasonText(RevokedReason int, Revoked string) string {
return reasonText
}
// GetCertificate returns a certificate with the given id or serial
func GetCertificate(w http.ResponseWriter, r *http.Request, id int, serial string) (CertificateShow, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {
@@ -687,18 +717,18 @@ func GetCertificate(w http.ResponseWriter, r *http.Request, id int, serial strin
Title: "Certificate",
TableClass: "certificate_show",
Rows: []NameValue{},
Links: []NameValHtml{},
Links: []NameValHTML{},
},
}
for rows.Next() {
row := CertificateExtra{}
err = rows.Scan(&row.Id, &row.RegistrationId, &row.Serial, &row.Digest, &row.Issued, &row.Expires, &row.SubscriberApproved, &row.Status, &row.OCSPLastUpdate, &row.Revoked, &row.RevokedReason, &row.LastNagSent, &row.NotAfter, &row.IsExpired)
err = rows.Scan(&row.ID, &row.RegistrationID, &row.Serial, &row.Digest, &row.Issued, &row.Expires, &row.SubscriberApproved, &row.Status, &row.OCSPLastUpdate, &row.Revoked, &row.RevokedReason, &row.LastNagSent, &row.NotAfter, &row.IsExpired)
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return CertificateShow{}, err
}
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"ID", strconv.Itoa(row.Id)})
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"ID", strconv.Itoa(row.ID)})
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"Serial", row.Serial})
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"Digest", row.Digest})
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"Issued", row.Issued})
@@ -721,16 +751,16 @@ func GetCertificate(w http.ResponseWriter, r *http.Request, id int, serial strin
}
CertificateDetails.Rows = append(CertificateDetails.Rows, NameValue{"Is Expired", v})
Link := NameValHtml{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationId) + "\">" + strconv.Itoa(row.RegistrationId) + "</a>")}
Link := NameValHTML{"Account", template.HTML("<a href=\"" + r.Header.Get("X-Request-Base") + "/accounts/" + strconv.Itoa(row.RegistrationID) + "\">" + strconv.Itoa(row.RegistrationID) + "</a>")}
CertificateDetails.Links = append(CertificateDetails.Links, Link)
if row.Revoked == "0000-00-00 00:00:00" {
revokeHtml, err := tmpls.RenderSingle("views/revoke-partial.tmpl", struct{ Serial string }{Serial: row.Serial})
revokeHTML, err := tmpls.RenderSingle("views/revoke-partial.tmpl", struct{ Serial string }{Serial: row.Serial})
if err != nil {
errorHandler(w, r, err, http.StatusInternalServerError)
return CertificateShow{}, err
}
CertificateDetails.Extra = append(CertificateDetails.Extra, template.HTML(revokeHtml))
CertificateDetails.Extra = append(CertificateDetails.Extra, template.HTML(revokeHTML))
}
}

View File

@@ -13,6 +13,7 @@ import (
"strings"
)
// CertificateInfo contains all data related to a certificate (file)
type CertificateInfo struct {
IsRoot bool
KeyTypes map[string]string
@@ -36,6 +37,7 @@ type CertificateInfo struct {
Errors map[string]string
}
// Initialize the CertificateInfo and set the list of available key types
func (ci *CertificateInfo) Initialize() {
ci.Errors = make(map[string]string)
@@ -49,6 +51,7 @@ func (ci *CertificateInfo) Initialize() {
ci.KeyType = "rsa4096"
}
// ValidateGenerate that the CertificateInfo contains valid and all required data for generating a cert
func (ci *CertificateInfo) ValidateGenerate() {
if strings.TrimSpace(ci.KeyType) == "" || strings.TrimSpace(ci.KeyTypes[ci.KeyType]) == "" {
ci.Errors["KeyType"] = "Please select a key type/size"
@@ -64,6 +67,7 @@ func (ci *CertificateInfo) ValidateGenerate() {
}
}
// Validate that the CertificateInfo contains valid and all required data
func (ci *CertificateInfo) Validate() bool {
ci.Errors = make(map[string]string)
@@ -112,10 +116,10 @@ func reportError(err error) error {
}
func preCreateTasks(path string) error {
if _, err := exe_cmd("touch " + path + "index.txt"); err != nil {
if _, err := exeCmd("touch " + path + "index.txt"); err != nil {
return reportError(err)
}
if _, err := exe_cmd("touch " + path + "index.txt.attr"); err != nil {
if _, err := exeCmd("touch " + path + "index.txt.attr"); err != nil {
return reportError(err)
}
@@ -130,13 +134,14 @@ func preCreateTasks(path string) error {
}
}
if _, err := exe_cmd("mkdir -p " + path + "certs"); err != nil {
if _, err := exeCmd("mkdir -p " + path + "certs"); err != nil {
return reportError(err)
}
return nil
}
// Generate a key and certificate file for the data from this CertificateInfo
func (ci *CertificateInfo) Generate(path string, certBase string) error {
// 1. Generate key
createCmd := "genrsa -aes256 -passout pass:foobar"
@@ -159,17 +164,17 @@ func (ci *CertificateInfo) Generate(path string, certBase string) error {
}
}
if _, err := exe_cmd("openssl " + createCmd + " -out " + path + certBase + ".key" + keySize); err != nil {
if _, err := exeCmd("openssl " + createCmd + " -out " + path + certBase + ".key" + keySize); err != nil {
return reportError(err)
}
if _, err := exe_cmd("openssl pkey -in " + path + certBase + ".key -passin pass:foobar -out " + path + certBase + ".tmp"); err != nil {
if _, err := exeCmd("openssl pkey -in " + path + certBase + ".key -passin pass:foobar -out " + path + certBase + ".tmp"); err != nil {
return reportError(err)
}
if _, err := exe_cmd("mv " + path + certBase + ".tmp " + path + certBase + ".key"); err != nil {
if _, err := exeCmd("mv " + path + certBase + ".tmp " + path + certBase + ".key"); err != nil {
return reportError(err)
}
_, _ = exe_cmd("sleep 1")
_, _ = exeCmd("sleep 1")
// 2. Generate certificate
subject := "/C=" + ci.Country + "/O=" + ci.Organization
@@ -180,14 +185,14 @@ func (ci *CertificateInfo) Generate(path string, certBase string) error {
subject = strings.Replace(subject, " ", "\\\\", -1)
if ci.IsRoot {
if _, err := exe_cmd("openssl req -config " + path + "openssl.cnf -days 3650 -new -x509 -extensions v3_ca -subj " + subject + " -key " + path + certBase + ".key -out " + path + certBase + ".pem"); err != nil {
if _, err := exeCmd("openssl req -config " + path + "openssl.cnf -days 3650 -new -x509 -extensions v3_ca -subj " + subject + " -key " + path + certBase + ".key -out " + path + certBase + ".pem"); err != nil {
return reportError(err)
}
} else {
if _, err := exe_cmd("openssl req -config " + path + "openssl.cnf -new -subj " + subject + " -key " + path + certBase + ".key -out " + path + certBase + ".csr"); err != nil {
if _, err := exeCmd("openssl req -config " + path + "openssl.cnf -new -subj " + subject + " -key " + path + certBase + ".key -out " + path + certBase + ".csr"); err != nil {
return reportError(err)
}
if _, err := exe_cmd("openssl ca -config " + path + "../openssl.cnf -extensions v3_intermediate_ca -days 3600 -md sha384 -notext -batch -in " + path + certBase + ".csr -out " + path + certBase + ".pem"); err != nil {
if _, err := exeCmd("openssl ca -config " + path + "../openssl.cnf -extensions v3_intermediate_ca -days 3600 -md sha384 -notext -batch -in " + path + certBase + ".csr -out " + path + certBase + ".pem"); err != nil {
return reportError(err)
}
}
@@ -195,6 +200,7 @@ func (ci *CertificateInfo) Generate(path string, certBase string) error {
return nil
}
// ImportPkcs12 imports an uploaded PKCS#12 / PFX file
func (ci *CertificateInfo) ImportPkcs12(tmpFile string, tmpKey string, tmpCert string) error {
if ci.IsRoot {
if strings.Index(ci.ImportHandler.Filename, "labca_root") != 0 {
@@ -211,24 +217,25 @@ func (ci *CertificateInfo) ImportPkcs12(tmpFile string, tmpKey string, tmpCert s
pwd = "pass:" + strings.Replace(ci.ImportPwd, " ", "\\\\", -1)
}
if out, err := exe_cmd("openssl pkcs12 -in " + strings.Replace(tmpFile, " ", "\\\\", -1) + " -password " + pwd + " -nocerts -nodes -out " + tmpKey); err != nil {
if out, err := exeCmd("openssl pkcs12 -in " + strings.Replace(tmpFile, " ", "\\\\", -1) + " -password " + pwd + " -nocerts -nodes -out " + tmpKey); err != nil {
if strings.Index(string(out), "invalid password") >= 0 {
return errors.New("Incorrect password!")
} else {
return reportError(err)
}
return reportError(err)
}
if out, err := exe_cmd("openssl pkcs12 -in " + strings.Replace(tmpFile, " ", "\\\\", -1) + " -password " + pwd + " -nokeys -out " + tmpCert); err != nil {
if out, err := exeCmd("openssl pkcs12 -in " + strings.Replace(tmpFile, " ", "\\\\", -1) + " -password " + pwd + " -nokeys -out " + tmpCert); err != nil {
if strings.Index(string(out), "invalid password") >= 0 {
return errors.New("Incorrect password!")
} else {
return reportError(err)
}
return reportError(err)
}
return nil
}
// ImportZip imports an uploaded ZIP file
func (ci *CertificateInfo) ImportZip(tmpFile string, tmpDir string) error {
if ci.IsRoot {
if (strings.Index(ci.ImportHandler.Filename, "labca_root") != 0) && (strings.Index(ci.ImportHandler.Filename, "labca_certificates") != 0) {
@@ -248,17 +255,18 @@ func (ci *CertificateInfo) ImportZip(tmpFile string, tmpDir string) error {
}
cmd = cmd + " " + strings.Replace(tmpFile, " ", "\\\\", -1) + " -d " + tmpDir
if _, err := exe_cmd(cmd); err != nil {
if _, err := exeCmd(cmd); err != nil {
if err.Error() == "exit status 82" {
return errors.New("Incorrect password!")
} else {
return reportError(err)
}
return reportError(err)
}
return nil
}
// Import a certificate and key file
func (ci *CertificateInfo) Import(path string, certBase string, tmpDir string, tmpKey string, tmpCert string) error {
tmpFile := filepath.Join(tmpDir, ci.ImportHandler.Filename)
@@ -291,6 +299,7 @@ func (ci *CertificateInfo) Import(path string, certBase string, tmpDir string, t
return nil
}
// Upload a certificate and key file
func (ci *CertificateInfo) Upload(path string, certBase string, tmpKey string, tmpCert string) error {
if err := ioutil.WriteFile(tmpKey, []byte(ci.Key), 0644); err != nil {
return err
@@ -301,16 +310,16 @@ func (ci *CertificateInfo) Upload(path string, certBase string, tmpKey string, t
pwd = "pass:" + strings.Replace(ci.Passphrase, " ", "\\\\", -1)
}
if out, err := exe_cmd("openssl pkey -passin " + pwd + " -in " + tmpKey + " -out " + tmpKey + "-out"); err != nil {
if out, err := exeCmd("openssl pkey -passin " + pwd + " -in " + tmpKey + " -out " + tmpKey + "-out"); err != nil {
if strings.Index(string(out), ":bad decrypt:") >= 0 {
return errors.New("Incorrect password!")
} else {
return reportError(err)
}
} else {
if _, err = exe_cmd("mv " + tmpKey + "-out " + tmpKey); err != nil {
return reportError(err)
}
return reportError(err)
}
if _, err := exeCmd("mv " + tmpKey + "-out " + tmpKey); err != nil {
return reportError(err)
}
if err := ioutil.WriteFile(tmpCert, []byte(ci.Certificate), 0644); err != nil {
@@ -320,23 +329,24 @@ func (ci *CertificateInfo) Upload(path string, certBase string, tmpKey string, t
return nil
}
// ImportCerts imports both the root and the issuer certificates
func (ci *CertificateInfo) ImportCerts(path string, rootCert string, rootKey string, issuerCert string, issuerKey string) error {
var rootSubject string
if (rootCert != "") && (rootKey != "") {
r, err := exe_cmd("openssl x509 -noout -subject -in " + rootCert)
r, err := exeCmd("openssl x509 -noout -subject -in " + rootCert)
if err != nil {
return reportError(err)
} else {
rootSubject = string(r[0 : len(r)-1])
fmt.Printf("Import root with subject '%s'\n", rootSubject)
}
r, err = exe_cmd("openssl pkey -noout -in " + rootKey)
rootSubject = string(r[0 : len(r)-1])
fmt.Printf("Import root with subject '%s'\n", rootSubject)
r, err = exeCmd("openssl pkey -noout -in " + rootKey)
if err != nil {
return reportError(err)
} else {
fmt.Println("Import root key")
}
fmt.Println("Import root key")
}
if (issuerCert != "") && (issuerKey != "") {
@@ -346,65 +356,66 @@ func (ci *CertificateInfo) ImportCerts(path string, rootCert string, rootKey str
}
}
r, err := exe_cmd("openssl x509 -noout -subject -in " + issuerCert)
r, err := exeCmd("openssl x509 -noout -subject -in " + issuerCert)
if err != nil {
return reportError(err)
} else {
fmt.Printf("Import issuer with subject '%s'\n", string(r[0:len(r)-1]))
}
r, err = exe_cmd("openssl x509 -noout -issuer -in " + issuerCert)
fmt.Printf("Import issuer with subject '%s'\n", string(r[0:len(r)-1]))
r, err = exeCmd("openssl x509 -noout -issuer -in " + issuerCert)
if err != nil {
return reportError(err)
} else {
issuerIssuer := string(r[0 : len(r)-1])
fmt.Printf("Issuer certificate issued by CA '%s'\n", issuerIssuer)
}
if rootSubject == "" {
r, err := exe_cmd("openssl x509 -noout -subject -in data/root-ca.pem")
if err != nil {
return reportError(err)
} else {
rootSubject = string(r[0 : len(r)-1])
}
issuerIssuer := string(r[0 : len(r)-1])
fmt.Printf("Issuer certificate issued by CA '%s'\n", issuerIssuer)
if rootSubject == "" {
r, err := exeCmd("openssl x509 -noout -subject -in data/root-ca.pem")
if err != nil {
return reportError(err)
}
issuerIssuer = strings.Replace(issuerIssuer, "issuer=", "", -1)
rootSubject = strings.Replace(rootSubject, "subject=", "", -1)
if issuerIssuer != rootSubject {
return errors.New("Issuer not issued by our Root CA!")
}
rootSubject = string(r[0 : len(r)-1])
}
r, err = exe_cmd("openssl pkey -noout -in " + issuerKey)
issuerIssuer = strings.Replace(issuerIssuer, "issuer=", "", -1)
rootSubject = strings.Replace(rootSubject, "subject=", "", -1)
if issuerIssuer != rootSubject {
return errors.New("Issuer not issued by our Root CA!")
}
r, err = exeCmd("openssl pkey -noout -in " + issuerKey)
if err != nil {
return reportError(err)
} else {
fmt.Println("Import issuer key")
}
fmt.Println("Import issuer key")
}
return nil
}
// MoveFiles moves certificate / key files to their final location
func (ci *CertificateInfo) MoveFiles(path string, rootCert string, rootKey string, issuerCert string, issuerKey string) error {
if rootCert != "" {
if _, err := exe_cmd("mv " + rootCert + " " + path); err != nil {
if _, err := exeCmd("mv " + rootCert + " " + path); err != nil {
return reportError(err)
}
}
if rootKey != "" {
if _, err := exe_cmd("mv " + rootKey + " " + path); err != nil {
if _, err := exeCmd("mv " + rootKey + " " + path); err != nil {
return reportError(err)
}
}
if issuerCert != "" {
if _, err := exe_cmd("mv " + issuerCert + " data/issuer/"); err != nil {
if _, err := exeCmd("mv " + issuerCert + " data/issuer/"); err != nil {
return reportError(err)
}
}
if issuerKey != "" {
if _, err := exe_cmd("mv " + issuerKey + " data/issuer/"); err != nil {
if _, err := exeCmd("mv " + issuerKey + " data/issuer/"); err != nil {
return reportError(err)
}
}
@@ -418,6 +429,7 @@ func (ci *CertificateInfo) MoveFiles(path string, rootCert string, rootKey strin
return nil
}
// Extract key and certificate files from a container file
func (ci *CertificateInfo) Extract(path string, certBase string, tmpDir string) error {
var rootCert string
var rootKey string
@@ -468,6 +480,7 @@ func (ci *CertificateInfo) Extract(path string, certBase string, tmpDir string)
return nil
}
// Create a new pair of key + certificate files based on the info in CertificateInfo
func (ci *CertificateInfo) Create(path string, certBase string) error {
if err := preCreateTasks(path); err != nil {
return err
@@ -525,7 +538,7 @@ func (ci *CertificateInfo) Create(path string, certBase string) error {
}
if ci.IsRoot {
if _, err := exe_cmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil {
if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil {
return reportError(err)
}
}
@@ -534,18 +547,18 @@ func (ci *CertificateInfo) Create(path string, certBase string) error {
}
func postCreateTasks(path string, certBase string) error {
if _, err := exe_cmd("openssl pkey -in " + path + certBase + ".key -out " + path + certBase + ".key.der -outform der"); err != nil {
if _, err := exeCmd("openssl pkey -in " + path + certBase + ".key -out " + path + certBase + ".key.der -outform der"); err != nil {
return reportError(err)
}
if _, err := exe_cmd("openssl x509 -in " + path + certBase + ".pem -out " + path + certBase + ".der -outform DER"); err != nil {
if _, err := exeCmd("openssl x509 -in " + path + certBase + ".pem -out " + path + certBase + ".der -outform DER"); err != nil {
return reportError(err)
}
return nil
}
func exe_cmd(cmd string) ([]byte, error) {
func exeCmd(cmd string) ([]byte, error) {
parts := strings.Fields(cmd)
for i := 0; i < len(parts); i++ {
parts[i] = strings.Replace(parts[i], "\\\\", " ", -1)

View File

@@ -12,6 +12,7 @@ import (
"time"
)
// Activity is a message to be shown on the dashboard, with timestamp and css class
type Activity struct {
Title string
Message string
@@ -124,12 +125,13 @@ func _parseActivity(data string) []Activity {
return activity
}
// Component contains status info related to a LabCA component
type Component struct {
Name string
Timestamp string
TimestampRel string
Class string
LogUrl string
LogURL string
LogTitle string
Buttons []map[string]interface{}
}
@@ -197,6 +199,7 @@ func _parseComponents(data string) []Component {
return components
}
// Stat contains a statistic
type Stat struct {
Name string
Hint string
@@ -273,6 +276,7 @@ func _parseStats(data string) []Stat {
return stats
}
// CollectDashboardData collects all data relevant for building the dashboard page
func CollectDashboardData(w http.ResponseWriter, r *http.Request) (map[string]interface{}, error) {
db, err := sql.Open(dbType, dbConn)
if err != nil {

View File

@@ -60,6 +60,7 @@ var (
}
)
// User struct for storing the admin user account details.
type User struct {
Name string
Email string
@@ -70,6 +71,7 @@ type User struct {
Errors map[string]string
}
// ValidatePassword checks that the password of a User is non-empty, matches the confirmation, is not on the blacklist and is sufficiently complex.
func (reg *User) ValidatePassword(isNew bool, isChange bool) {
blacklist := []string{"labca", "acme", reg.Name}
if x := strings.Index(reg.Email, "@"); x > 0 {
@@ -119,6 +121,7 @@ func (reg *User) ValidatePassword(isNew bool, isChange bool) {
}
}
// Validate that User struct contains at least a Name, has a valid email address and password fields.
func (reg *User) Validate(isNew bool, isChange bool) bool {
reg.Errors = make(map[string]string)
@@ -139,10 +142,11 @@ func (reg *User) Validate(isNew bool, isChange bool) bool {
return len(reg.Errors) == 0
}
// SetupConfig stores the basic config settings.
type SetupConfig struct {
Fqdn string
Organization string
Dns string
DNS string
DomainMode string
LockdownDomains string
WhitelistDomains string
@@ -150,6 +154,7 @@ type SetupConfig struct {
Errors map[string]string
}
// Validate that SetupConfig contains all required data.
func (cfg *SetupConfig) Validate(orgRequired bool) bool {
cfg.Errors = make(map[string]string)
@@ -161,8 +166,8 @@ func (cfg *SetupConfig) Validate(orgRequired bool) bool {
cfg.Errors["Organization"] = "Please enter the organization name to show on the public pages"
}
if strings.TrimSpace(cfg.Dns) == "" {
cfg.Errors["Dns"] = "Please enter the DNS server to be used for validation"
if strings.TrimSpace(cfg.DNS) == "" {
cfg.Errors["DNS"] = "Please enter the DNS server to be used for validation"
}
if cfg.DomainMode != "lockdown" && cfg.DomainMode != "whitelist" && cfg.DomainMode != "standard" {
@@ -251,15 +256,15 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
}
session := getSession(w, r)
var bounceUrl string
var bounceURL string
if session.Values["bounce"] == nil {
bounceUrl = "/"
bounceURL = "/"
} else {
bounceUrl = session.Values["bounce"].(string)
bounceURL = session.Values["bounce"].(string)
}
if session.Values["user"] != nil {
http.Redirect(w, r, r.Header.Get("X-Request-Base")+bounceUrl, http.StatusFound)
http.Redirect(w, r, r.Header.Get("X-Request-Base")+bounceURL, http.StatusFound)
return
}
@@ -290,21 +295,21 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
reg.Errors["Name"] = "Incorrect username or password"
render(w, r, "login", map[string]interface{}{"User": reg, "IsLogin": true})
return
} else {
byteStored := []byte(viper.GetString("user.password"))
err := bcrypt.CompareHashAndPassword(byteStored, []byte(reg.Password))
if err != nil {
log.Println(err)
reg.Errors["Name"] = "Incorrect username or password"
render(w, r, "login", map[string]interface{}{"User": reg, "IsLogin": true})
return
}
}
byteStored := []byte(viper.GetString("user.password"))
err := bcrypt.CompareHashAndPassword(byteStored, []byte(reg.Password))
if err != nil {
log.Println(err)
reg.Errors["Name"] = "Incorrect username or password"
render(w, r, "login", map[string]interface{}{"User": reg, "IsLogin": true})
return
}
session.Values["user"] = reg.Name
session.Save(r, w)
http.Redirect(w, r, r.Header.Get("X-Request-Base")+bounceUrl, http.StatusFound)
http.Redirect(w, r, r.Header.Get("X-Request-Base")+bounceURL, http.StatusFound)
} else {
http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/login", http.StatusSeeOther)
return
@@ -419,7 +424,7 @@ func _configUpdateHandler(w http.ResponseWriter, r *http.Request) {
cfg := &SetupConfig{
Fqdn: r.Form.Get("fqdn"),
Organization: r.Form.Get("organization"),
Dns: r.Form.Get("dns"),
DNS: r.Form.Get("dns"),
DomainMode: r.Form.Get("domain_mode"),
LockdownDomains: r.Form.Get("lockdown_domains"),
WhitelistDomains: r.Form.Get("whitelist_domains"),
@@ -443,29 +448,29 @@ func _configUpdateHandler(w http.ResponseWriter, r *http.Request) {
viper.Set("labca.organization", cfg.Organization)
}
matched, err := regexp.MatchString(":\\d+$", cfg.Dns)
matched, err := regexp.MatchString(":\\d+$", cfg.DNS)
if err == nil && !matched {
cfg.Dns += ":53"
cfg.DNS += ":53"
}
if cfg.Dns != viper.GetString("labca.dns") {
if cfg.DNS != viper.GetString("labca.dns") {
delta = true
viper.Set("labca.dns", cfg.Dns)
viper.Set("labca.dns", cfg.DNS)
}
domain_mode := cfg.DomainMode
if domain_mode != viper.GetString("labca.domain_mode") {
domainMode := cfg.DomainMode
if domainMode != viper.GetString("labca.domain_mode") {
delta = true
viper.Set("labca.domain_mode", cfg.DomainMode)
}
if domain_mode == "lockdown" {
if domainMode == "lockdown" {
if cfg.LockdownDomains != viper.GetString("labca.lockdown") {
delta = true
viper.Set("labca.lockdown", cfg.LockdownDomains)
}
}
if domain_mode == "whitelist" {
if domainMode == "whitelist" {
if cfg.WhitelistDomains != viper.GetString("labca.whitelist") {
delta = true
viper.Set("labca.whitelist", cfg.WhitelistDomains)
@@ -496,6 +501,7 @@ func _configUpdateHandler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(res)
}
// EmailConfig stores configuration used for sending out emails
type EmailConfig struct {
DoEmail bool
Server string
@@ -506,6 +512,7 @@ type EmailConfig struct {
Errors map[string]string
}
// Validate that the email config is valid and complete
func (cfg *EmailConfig) Validate() bool {
cfg.Errors = make(map[string]string)
@@ -758,6 +765,7 @@ func _decrypt(ciphertext string) ([]byte, error) {
return gcm.Open(nil, ct[:gcm.NonceSize()], ct[gcm.NonceSize():], nil)
}
// Result contains data on managed processes
type Result struct {
Success bool
Message string
@@ -766,6 +774,7 @@ type Result struct {
Class string
}
// ManageComponents sets the additional data to be displayed on the page for the LabCA components
func (res *Result) ManageComponents(w http.ResponseWriter, r *http.Request, action string) {
components := _parseComponents(getLog(w, r, "components"))
for i := 0; i < len(components); i++ {
@@ -823,7 +832,7 @@ func _managePost(w http.ResponseWriter, r *http.Request) {
action := r.Form.Get("action")
actionKnown := false
for _, a := range []string {
for _, a := range []string{
"backup-restore",
"backup-delete",
"backup-now",
@@ -847,7 +856,7 @@ func _managePost(w http.ResponseWriter, r *http.Request) {
}
}
if !actionKnown {
errorHandler(w, r, errors.New(fmt.Sprintf("Unknown manage action '%s'", action)), http.StatusBadRequest)
errorHandler(w, r, fmt.Errorf("Unknown manage action '%s'", action), http.StatusBadRequest)
return
}
@@ -855,7 +864,7 @@ func _managePost(w http.ResponseWriter, r *http.Request) {
return
}
res := &Result{ Success: true }
res := &Result{Success: true}
if !_hostCommand(w, r, action) {
res.Success = false
res.Message = "Command failed - see LabCA log for any details"
@@ -876,7 +885,7 @@ func _manageGet(w http.ResponseWriter, r *http.Request) {
components := _parseComponents(getLog(w, r, "components"))
for i := 0; i < len(components); i++ {
if components[i].Name == "NGINX Webserver" {
components[i].LogUrl = r.Header.Get("X-Request-Base") + "/logs/weberr"
components[i].LogURL = r.Header.Get("X-Request-Base") + "/logs/weberr"
components[i].LogTitle = "Web Error Log"
btn := make(map[string]interface{})
@@ -895,7 +904,7 @@ func _manageGet(w http.ResponseWriter, r *http.Request) {
}
if components[i].Name == "Host Service" {
components[i].LogUrl = ""
components[i].LogURL = ""
components[i].LogTitle = ""
btn := make(map[string]interface{})
@@ -907,7 +916,7 @@ func _manageGet(w http.ResponseWriter, r *http.Request) {
}
if components[i].Name == "Boulder (ACME)" {
components[i].LogUrl = r.Header.Get("X-Request-Base") + "/logs/boulder"
components[i].LogURL = r.Header.Get("X-Request-Base") + "/logs/boulder"
components[i].LogTitle = "ACME Log"
btn := make(map[string]interface{})
@@ -945,7 +954,7 @@ func _manageGet(w http.ResponseWriter, r *http.Request) {
}
if components[i].Name == "LabCA Application" {
components[i].LogUrl = r.Header.Get("X-Request-Base") + "/logs/labca"
components[i].LogURL = r.Header.Get("X-Request-Base") + "/logs/labca"
components[i].LogTitle = "LabCA Log"
btn := make(map[string]interface{})
@@ -976,13 +985,13 @@ func _manageGet(w http.ResponseWriter, r *http.Request) {
manageData["Fqdn"] = viper.GetString("labca.fqdn")
manageData["Organization"] = viper.GetString("labca.organization")
manageData["Dns"] = viper.GetString("labca.dns")
domain_mode := viper.GetString("labca.domain_mode")
manageData["DomainMode"] = domain_mode
if domain_mode == "lockdown" {
manageData["DNS"] = viper.GetString("labca.dns")
domainMode := viper.GetString("labca.domain_mode")
manageData["DomainMode"] = domainMode
if domainMode == "lockdown" {
manageData["LockdownDomains"] = viper.GetString("labca.lockdown")
}
if domain_mode == "whitelist" {
if domainMode == "whitelist" {
manageData["WhitelistDomains"] = viper.GetString("labca.whitelist")
}
@@ -1015,9 +1024,9 @@ func manageHandler(w http.ResponseWriter, r *http.Request) {
}
if r.Method == "POST" {
_managePost(w,r)
_managePost(w, r)
} else {
_manageGet(w,r)
_manageGet(w, r)
}
}
@@ -1060,7 +1069,7 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
wsurl = ""
data = getLog(w, r, logType)
default:
errorHandler(w, r, errors.New(fmt.Sprintf("Unknown log type '%s'", logType)), http.StatusBadRequest)
errorHandler(w, r, fmt.Errorf("Unknown log type '%s'", logType), http.StatusBadRequest)
return
}
@@ -1196,7 +1205,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
case "labca":
case "web":
default:
errorHandler(w, r, errors.New(fmt.Sprintf("Unknown log type '%s'", logType)), http.StatusBadRequest)
errorHandler(w, r, fmt.Errorf("Unknown log type '%s'", logType), http.StatusBadRequest)
return
}
@@ -1446,7 +1455,7 @@ func _applyConfig() error {
os.Setenv("PKI_EMAIL_FROM", "Expiry bot <test@example.com>")
}
_, err := exe_cmd("./apply")
_, err := exeCmd("./apply")
if err != nil {
fmt.Println("")
}
@@ -1459,45 +1468,39 @@ func _progress(stage string) int {
if stage == "register" {
return int(math.Round(curr / max))
} else {
curr += 2.0
}
curr += 2.0
if stage == "setup" {
return int(math.Round(curr / max))
} else {
curr += 3.0
}
curr += 3.0
if stage == "root-ca" {
return int(math.Round(curr / max))
} else {
curr += 4.0
}
curr += 4.0
if stage == "ca-int" {
return int(math.Round(curr / max))
} else {
curr += 3.0
}
curr += 3.0
if stage == "polling" {
return int(math.Round(curr / max))
} else {
curr += 4.0
}
curr += 4.0
if stage == "wrapup" {
return int(math.Round(curr / max))
} else {
curr += 3.0
}
curr += 3.0
if stage == "final" {
return int(math.Round(curr / max))
} else {
return 0
}
return 0
}
func _helptext(stage string) template.HTML {
@@ -1612,7 +1615,7 @@ func _setupBaseConfig(w http.ResponseWriter, r *http.Request) bool {
cfg := &SetupConfig{
Fqdn: r.Form.Get("fqdn"),
Dns: r.Form.Get("dns"),
DNS: r.Form.Get("dns"),
DomainMode: r.Form.Get("domain_mode"),
LockdownDomains: r.Form.Get("lockdown_domains"),
WhitelistDomains: r.Form.Get("whitelist_domains"),
@@ -1624,13 +1627,13 @@ func _setupBaseConfig(w http.ResponseWriter, r *http.Request) bool {
return false
}
matched, err := regexp.MatchString(":\\d+$", cfg.Dns)
matched, err := regexp.MatchString(":\\d+$", cfg.DNS)
if err == nil && !matched {
cfg.Dns += ":53"
cfg.DNS += ":53"
}
viper.Set("labca.fqdn", cfg.Fqdn)
viper.Set("labca.dns", cfg.Dns)
viper.Set("labca.dns", cfg.DNS)
viper.Set("labca.domain_mode", cfg.DomainMode)
if cfg.DomainMode == "lockdown" {
viper.Set("labca.lockdown", cfg.LockdownDomains)
@@ -1702,10 +1705,9 @@ func setupHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, r.Header.Get("X-Request-Base")+"/wait?restart="+restartSecret, http.StatusFound)
}
return
} else {
render(w, r, "wrapup:manage", map[string]interface{}{"Progress": _progress("wrapup"), "HelpText": _helptext("wrapup")})
}
render(w, r, "wrapup:manage", map[string]interface{}{"Progress": _progress("wrapup"), "HelpText": _helptext("wrapup")})
}
func waitHandler(w http.ResponseWriter, r *http.Request) {
@@ -1989,12 +1991,12 @@ type navItem struct {
}
func _matchPrefix(uri string, prefix string) bool {
return (uri == prefix || strings.HasPrefix(uri, prefix + "/"))
return (uri == prefix || strings.HasPrefix(uri, prefix+"/"))
}
func _acmeNav(active string, uri string, requestBase string) navItem {
isAcmeActive := _matchPrefix(uri, "/accounts") || _matchPrefix(uri, "/orders") ||
_matchPrefix(uri, "/authz") || _matchPrefix(uri, "/challenges" ) ||
_matchPrefix(uri, "/authz") || _matchPrefix(uri, "/challenges") ||
_matchPrefix(uri, "/certificates") || false
accounts := navItem{
@@ -2132,7 +2134,7 @@ func activeNav(active string, uri string, requestBase string) []navItem {
"title": "Log Files",
},
IsActive: strings.HasPrefix(uri, "/logs/"),
SubMenu: []navItem{cert, boulder, audit, labca, web, weberr},
SubMenu: []navItem{cert, boulder, audit, labca, web, weberr},
}
manage := navItem{
Name: "Manage",

View File

@@ -38,7 +38,7 @@
{{ if ne $item.TimestampRel "stopped" }}Up {{ end }}{{ $item.TimestampRel }}
</span>
</td>
<td class="vmiddle">{{ if or $item.LogUrl $item.LogTitle}}<a href="{{ $item.LogUrl }}" title="{{ $item.LogTitle }}"><i class="fa fa-fw fa-file"></i></a>{{ end }}</td>
<td class="vmiddle">{{ if or $item.LogURL $item.LogTitle}}<a href="{{ $item.LogURL }}" title="{{ $item.LogTitle }}"><i class="fa fa-fw fa-file"></i></a>{{ end }}</td>
<td class="vmiddle">
{{ range $btn := $item.Buttons }}
<button class="btn btn-outline btn-reg {{ $btn.Class }}" type="button" id="{{ $btn.Id }}" title="{{ $btn.Title }}">{{ $btn.Label }}</button>
@@ -144,7 +144,7 @@
</div>
<div class="form-group">
<label for="dns">Internal DNS server to use:</label>
<input class="form-control non-fluid" type="text" id="dns" name="dns" value="{{ .Dns }}" required>
<input class="form-control non-fluid" type="text" id="dns" name="dns" value="{{ .DNS }}" required>
<span class="error config-error hidden" id="dns-error"></span>
</div>

View File

@@ -14,8 +14,8 @@
</div>
<div class="form-group">
<label for="dns">Internal DNS server to use:</label>
<input class="form-control non-fluid" type="text" id="dns" name="dns" value="{{ .Dns }}" required>
{{ with .Errors.Dns }}
<input class="form-control non-fluid" type="text" id="dns" name="dns" value="{{ .DNS }}" required>
{{ with .Errors.DNS }}
<span class="error">{{ . }}</span>
{{ end }}
</div>

View File

@@ -24,7 +24,7 @@ dockerComposeVersion="1.22.0"
labcaUrl="https://github.com/hakwerk/labca/"
boulderUrl="https://github.com/letsencrypt/boulder/"
boulderTag="release-2018-11-05"
boulderTag="release-2018-12-10"
#
# Color configuration