mirror of
https://github.com/outbackdingo/labca.git
synced 2026-01-27 10:19:34 +00:00
120
gui/acme.go
120
gui/acme.go
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
136
gui/main.go
136
gui/main.go
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user