Fix gosec, govet, and errorlint linter errors

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-03-15 10:04:12 -07:00
parent dd31e440e6
commit fbaf79a8a0
35 changed files with 236 additions and 232 deletions

View File

@@ -19,12 +19,12 @@ import (
// directoryResponse is the ACME directory object (RFC 8555 §7.1.1).
type directoryResponse struct {
NewNonce string `json:"newNonce"`
NewAccount string `json:"newAccount"`
NewOrder string `json:"newOrder"`
RevokeCert string `json:"revokeCert"`
KeyChange string `json:"keyChange"`
Meta *directoryMeta `json:"meta,omitempty"`
NewNonce string `json:"newNonce"`
NewAccount string `json:"newAccount"`
NewOrder string `json:"newOrder"`
RevokeCert string `json:"revokeCert"`
KeyChange string `json:"keyChange"`
}
type directoryMeta struct {
@@ -49,7 +49,7 @@ func (h *Handler) handleDirectory(w http.ResponseWriter, r *http.Request) {
},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(dir)
_ = json.NewEncoder(w).Encode(dir)
}
// handleNewNonce serves HEAD and GET /acme/{mount}/new-nonce.
@@ -65,10 +65,10 @@ func (h *Handler) handleNewNonce(w http.ResponseWriter, r *http.Request) {
// newAccountPayload is the payload for the new-account request.
type newAccountPayload struct {
TermsOfServiceAgreed bool `json:"termsOfServiceAgreed"`
Contact []string `json:"contact,omitempty"`
Contact []string `json:"contact,omitempty"`
ExternalAccountBinding json.RawMessage `json:"externalAccountBinding,omitempty"`
OnlyReturnExisting bool `json:"onlyReturnExisting"`
TermsOfServiceAgreed bool `json:"termsOfServiceAgreed"`
OnlyReturnExisting bool `json:"onlyReturnExisting"`
}
// handleNewAccount handles POST /acme/{mount}/new-account.
@@ -172,9 +172,9 @@ func (h *Handler) handleNewAccount(w http.ResponseWriter, r *http.Request) {
// newOrderPayload is the payload for the new-order request.
type newOrderPayload struct {
Identifiers []Identifier `json:"identifiers"`
NotBefore string `json:"notBefore,omitempty"`
NotAfter string `json:"notAfter,omitempty"`
Identifiers []Identifier `json:"identifiers"`
}
// handleNewOrder handles POST /acme/{mount}/new-order.
@@ -350,7 +350,7 @@ func (h *Handler) handleChallenge(w http.ResponseWriter, r *http.Request) {
h.writeJSON(w, http.StatusOK, h.challengeToWire(chall))
// Launch validation goroutine.
go h.validateChallenge(context.Background(), chall, acc.JWK)
go h.validateChallenge(context.Background(), chall, acc.JWK) //nolint:gosec
}
// handleFinalize handles POST /acme/{mount}/finalize/{id}.
@@ -468,7 +468,7 @@ func (h *Handler) handleFinalize(w http.ResponseWriter, r *http.Request) {
order.Status = StatusValid
order.CertID = certID
orderData, _ := json.Marshal(order)
h.barrier.Put(ctx, h.barrierPrefix()+"orders/"+orderID+".json", orderData)
_ = h.barrier.Put(ctx, h.barrierPrefix()+"orders/"+orderID+".json", orderData)
h.writeJSON(w, http.StatusOK, h.orderToWire(order))
}
@@ -502,7 +502,7 @@ func (h *Handler) handleGetCert(w http.ResponseWriter, r *http.Request) {
h.addNonceHeader(w)
w.Header().Set("Content-Type", "application/pem-certificate-chain")
w.WriteHeader(http.StatusOK)
w.Write([]byte(cert.CertPEM))
_, _ = w.Write([]byte(cert.CertPEM))
}
// handleRevokeCert handles POST /acme/{mount}/revoke-cert.
@@ -564,7 +564,7 @@ func (h *Handler) handleRevokeCert(w http.ResponseWriter, r *http.Request) {
if issuedCert.SerialNumber.Cmp(targetCert.SerialNumber) == 0 {
cert.Revoked = true
updated, _ := json.Marshal(cert)
h.barrier.Put(ctx, h.barrierPrefix()+"certs/"+p, updated)
_ = h.barrier.Put(ctx, h.barrierPrefix()+"certs/"+p, updated)
h.addNonceHeader(w)
w.WriteHeader(http.StatusOK)
return
@@ -726,11 +726,11 @@ func (h *Handler) orderToWire(order *Order) map[string]interface{} {
authzURLs[i] = h.authzURL(id)
}
m := map[string]interface{}{
"status": order.Status,
"expires": order.ExpiresAt.Format(time.RFC3339),
"identifiers": order.Identifiers,
"status": order.Status,
"expires": order.ExpiresAt.Format(time.RFC3339),
"identifiers": order.Identifiers,
"authorizations": authzURLs,
"finalize": h.finalizeURL(order.ID),
"finalize": h.finalizeURL(order.ID),
}
if order.CertID != "" {
m["certificate"] = h.certURL(order.CertID)
@@ -859,7 +859,7 @@ func readBody(r *http.Request) ([]byte, error) {
if r.Body == nil {
return nil, errors.New("empty body")
}
defer r.Body.Close()
defer func() { _ = r.Body.Close() }()
buf := make([]byte, 0, 4096)
tmp := make([]byte, 512)
for {

View File

@@ -27,18 +27,18 @@ type JWSHeader struct {
Alg string `json:"alg"`
Nonce string `json:"nonce"`
URL string `json:"url"`
JWK json.RawMessage `json:"jwk,omitempty"` // present for new-account / new-order with new key
KID string `json:"kid,omitempty"` // present for subsequent requests
KID string `json:"kid,omitempty"`
JWK json.RawMessage `json:"jwk,omitempty"`
}
// ParsedJWS is the result of parsing a JWS request body.
// Signature verification is NOT performed here; call VerifyJWS separately.
type ParsedJWS struct {
Header JWSHeader
Payload []byte // decoded payload bytes; empty-string payload decodes to nil
SigningInput []byte // protected + "." + payload (ASCII; used for signature verification)
RawSignature []byte // decoded signature bytes
RawBody JWSFlat
Header JWSHeader
RawBody JWSFlat
Payload []byte
SigningInput []byte
RawSignature []byte
}
// ParseJWS decodes the flattened JWS from body without verifying the signature.
@@ -77,7 +77,7 @@ func ParseJWS(body []byte) (*ParsedJWS, error) {
return &ParsedJWS{
Header: header,
Payload: payload,
SigningInput: signingInput,
SigningInput: signingInput,
RawSignature: sig,
RawBody: flat,
}, nil

View File

@@ -13,9 +13,9 @@ const nonceLifetime = 10 * time.Minute
// NonceStore is a thread-safe single-use nonce store with expiry.
// Nonces are short-lived per RFC 8555 §7.2.
type NonceStore struct {
mu sync.Mutex
nonces map[string]time.Time
issued int
mu sync.Mutex
}
// NewNonceStore creates a new nonce store.

View File

@@ -15,12 +15,12 @@ import (
// Handler implements the ACME protocol for a single CA mount.
type Handler struct {
mount string
barrier barrier.Barrier
engines *engine.Registry
nonces *NonceStore
baseURL string
logger *slog.Logger
mount string
baseURL string
}
// NewHandler creates an ACME handler for the given CA mount.

View File

@@ -4,63 +4,63 @@ import "time"
// Account represents an ACME account (RFC 8555 §7.1.2).
type Account struct {
ID string `json:"id"`
Status string `json:"status"` // "valid", "deactivated", "revoked"
Contact []string `json:"contact,omitempty"`
JWK []byte `json:"jwk"` // canonical JSON of account public key
CreatedAt time.Time `json:"created_at"`
MCIASUsername string `json:"mcias_username"` // MCIAS user who created via EAB
ID string `json:"id"`
Status string `json:"status"`
MCIASUsername string `json:"mcias_username"`
Contact []string `json:"contact,omitempty"`
JWK []byte `json:"jwk"`
}
// EABCredential is an External Account Binding credential (RFC 8555 §7.3.4).
type EABCredential struct {
KID string `json:"kid"`
HMACKey []byte `json:"hmac_key"` // raw 32-byte secret
Used bool `json:"used"`
CreatedBy string `json:"created_by"` // MCIAS username
CreatedAt time.Time `json:"created_at"`
KID string `json:"kid"`
CreatedBy string `json:"created_by"`
HMACKey []byte `json:"hmac_key"`
Used bool `json:"used"`
}
// Order represents an ACME certificate order (RFC 8555 §7.1.3).
type Order struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
Status string `json:"status"` // "pending","ready","processing","valid","invalid"
Identifiers []Identifier `json:"identifiers"`
AuthzIDs []string `json:"authz_ids"`
CertID string `json:"cert_id,omitempty"`
NotBefore *time.Time `json:"not_before,omitempty"`
NotAfter *time.Time `json:"not_after,omitempty"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
IssuerName string `json:"issuer_name"` // which CA issuer to sign with
NotBefore *time.Time `json:"not_before,omitempty"`
NotAfter *time.Time `json:"not_after,omitempty"`
ID string `json:"id"`
AccountID string `json:"account_id"`
Status string `json:"status"`
CertID string `json:"cert_id,omitempty"`
IssuerName string `json:"issuer_name"`
Identifiers []Identifier `json:"identifiers"`
AuthzIDs []string `json:"authz_ids"`
}
// Identifier is a domain name or IP address in an order.
type Identifier struct {
Type string `json:"type"` // "dns" or "ip"
Type string `json:"type"` // "dns" or "ip"
Value string `json:"value"`
}
// Authorization represents an ACME authorization (RFC 8555 §7.1.4).
type Authorization struct {
ExpiresAt time.Time `json:"expires_at"`
Identifier Identifier `json:"identifier"`
ID string `json:"id"`
AccountID string `json:"account_id"`
Status string `json:"status"` // "pending","valid","invalid","expired","deactivated","revoked"
Identifier Identifier `json:"identifier"`
Status string `json:"status"`
ChallengeIDs []string `json:"challenge_ids"`
ExpiresAt time.Time `json:"expires_at"`
}
// Challenge represents an ACME challenge (RFC 8555 §8).
type Challenge struct {
ID string `json:"id"`
AuthzID string `json:"authz_id"`
Type string `json:"type"` // "http-01" or "dns-01"
Status string `json:"status"` // "pending","processing","valid","invalid"
Token string `json:"token"` // base64url, 43 chars (32 random bytes)
Error *ProblemDetail `json:"error,omitempty"`
ValidatedAt *time.Time `json:"validated_at,omitempty"`
ID string `json:"id"`
AuthzID string `json:"authz_id"`
Type string `json:"type"`
Status string `json:"status"`
Token string `json:"token"`
}
// ProblemDetail is an RFC 7807 problem detail for ACME errors.
@@ -71,12 +71,12 @@ type ProblemDetail struct {
// IssuedCert stores the PEM and metadata for a certificate issued via ACME.
type IssuedCert struct {
IssuedAt time.Time `json:"issued_at"`
ExpiresAt time.Time `json:"expires_at"`
ID string `json:"id"`
OrderID string `json:"order_id"`
AccountID string `json:"account_id"`
CertPEM string `json:"cert_pem"` // full chain PEM
IssuedAt time.Time `json:"issued_at"`
ExpiresAt time.Time `json:"expires_at"`
CertPEM string `json:"cert_pem"`
Revoked bool `json:"revoked"`
}
@@ -104,27 +104,27 @@ const (
// ACME problem type URIs (RFC 8555 §6.7).
const (
ProblemAccountDoesNotExist = "urn:ietf:params:acme:error:accountDoesNotExist"
ProblemAlreadyRevoked = "urn:ietf:params:acme:error:alreadyRevoked"
ProblemBadCSR = "urn:ietf:params:acme:error:badCSR"
ProblemBadNonce = "urn:ietf:params:acme:error:badNonce"
ProblemBadPublicKey = "urn:ietf:params:acme:error:badPublicKey"
ProblemBadRevocationReason = "urn:ietf:params:acme:error:badRevocationReason"
ProblemBadSignatureAlg = "urn:ietf:params:acme:error:badSignatureAlgorithm"
ProblemCAA = "urn:ietf:params:acme:error:caa"
ProblemConnection = "urn:ietf:params:acme:error:connection"
ProblemDNS = "urn:ietf:params:acme:error:dns"
ProblemAccountDoesNotExist = "urn:ietf:params:acme:error:accountDoesNotExist"
ProblemAlreadyRevoked = "urn:ietf:params:acme:error:alreadyRevoked"
ProblemBadCSR = "urn:ietf:params:acme:error:badCSR"
ProblemBadNonce = "urn:ietf:params:acme:error:badNonce"
ProblemBadPublicKey = "urn:ietf:params:acme:error:badPublicKey"
ProblemBadRevocationReason = "urn:ietf:params:acme:error:badRevocationReason"
ProblemBadSignatureAlg = "urn:ietf:params:acme:error:badSignatureAlgorithm"
ProblemCAA = "urn:ietf:params:acme:error:caa"
ProblemConnection = "urn:ietf:params:acme:error:connection"
ProblemDNS = "urn:ietf:params:acme:error:dns"
ProblemExternalAccountRequired = "urn:ietf:params:acme:error:externalAccountRequired"
ProblemIncorrectResponse = "urn:ietf:params:acme:error:incorrectResponse"
ProblemInvalidContact = "urn:ietf:params:acme:error:invalidContact"
ProblemMalformed = "urn:ietf:params:acme:error:malformed"
ProblemOrderNotReady = "urn:ietf:params:acme:error:orderNotReady"
ProblemRateLimited = "urn:ietf:params:acme:error:rateLimited"
ProblemRejectedIdentifier = "urn:ietf:params:acme:error:rejectedIdentifier"
ProblemServerInternal = "urn:ietf:params:acme:error:serverInternal"
ProblemTLS = "urn:ietf:params:acme:error:tls"
ProblemUnauthorized = "urn:ietf:params:acme:error:unauthorized"
ProblemUnsupportedContact = "urn:ietf:params:acme:error:unsupportedContact"
ProblemUnsupportedIdentifier = "urn:ietf:params:acme:error:unsupportedIdentifier"
ProblemUserActionRequired = "urn:ietf:params:acme:error:userActionRequired"
ProblemIncorrectResponse = "urn:ietf:params:acme:error:incorrectResponse"
ProblemInvalidContact = "urn:ietf:params:acme:error:invalidContact"
ProblemMalformed = "urn:ietf:params:acme:error:malformed"
ProblemOrderNotReady = "urn:ietf:params:acme:error:orderNotReady"
ProblemRateLimited = "urn:ietf:params:acme:error:rateLimited"
ProblemRejectedIdentifier = "urn:ietf:params:acme:error:rejectedIdentifier"
ProblemServerInternal = "urn:ietf:params:acme:error:serverInternal"
ProblemTLS = "urn:ietf:params:acme:error:tls"
ProblemUnauthorized = "urn:ietf:params:acme:error:unauthorized"
ProblemUnsupportedContact = "urn:ietf:params:acme:error:unsupportedContact"
ProblemUnsupportedIdentifier = "urn:ietf:params:acme:error:unsupportedIdentifier"
ProblemUserActionRequired = "urn:ietf:params:acme:error:userActionRequired"
)