mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 19:21:29 +00:00
21aeed4f4e
Phase 0 closure (Path B2, post-rewrite):
addlicense sweep — adds the canonical certctl LLC copyright + BUSL-1.1
SPDX header to every production Go file. Template:
// Copyright 2026 certctl LLC. All rights reserved.
// SPDX-License-Identifier: BUSL-1.1
Coverage: 338 / 338 production Go files (cmd/ + internal/, excluding
*_test.go and **/testdata/**). Pre-sweep coverage was 22 / 338 (6.5%);
post-sweep is 338 / 338 (100%).
Normalized 22 pre-existing legacy headers (`// Copyright (c) certctl`
+ `// SPDX-License-Identifier: BSL-1.1`) and 1 file using a
`Certctl Contributors` attribution. The legacy SPDX ID `BSL-1.1`
is non-standard; the official SPDX identifier for Business Source
License 1.1 is `BUSL-1.1` (capital U). All 338 files now share the
canonical form.
Generated via:
addlicense -c "certctl LLC" -y 2026 \
-f cowork/legal/copyright-header.tpl \
-ignore '**/testdata/**' -ignore '**/*_test.go' \
cmd/ internal/
Verification:
find cmd internal -name '*.go' -not -name '*_test.go' \
-not -path '*/testdata/*' \
-exec grep -L '^// Copyright 2026 certctl LLC' {} \; | wc -l
Returns: 0
gofmt clean. Header additions are comments only, no compile impact.
Closes: cowork/certctl-architecture-diligence-audit.html#fix-RED-4
83 lines
3.6 KiB
Go
83 lines
3.6 KiB
Go
// Copyright 2026 certctl LLC. All rights reserved.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package acme
|
|
|
|
import (
|
|
"github.com/certctl-io/certctl/internal/domain"
|
|
)
|
|
|
|
// AccountResponseJSON is the wire shape RFC 8555 §7.1.2 mandates for
|
|
// account-resource responses (new-account success, account update,
|
|
// per-account GET POST-as-GET).
|
|
//
|
|
// The orders URL is mandatory per RFC 8555 §7.1.2.1; it points at the
|
|
// per-account orders list endpoint that Phase 2 implements. Phase 1b
|
|
// emits it as an empty placeholder ("orders not yet implemented") so
|
|
// the directory + new-account flow round-trips against ACME clients
|
|
// that expect the field present.
|
|
type AccountResponseJSON struct {
|
|
Status string `json:"status"`
|
|
Contact []string `json:"contact,omitempty"`
|
|
Orders string `json:"orders"`
|
|
}
|
|
|
|
// MarshalAccount renders an ACMEAccount in RFC 8555 §7.1.2 wire shape.
|
|
// `ordersURL` is the per-account orders list URL the handler computes
|
|
// from the inbound request (scheme + host + profile path + account
|
|
// id); Phase 1b's handler passes it but Phase 2 wires the actual
|
|
// /acme/profile/<id>/account/<acc-id>/orders endpoint.
|
|
func MarshalAccount(acct *domain.ACMEAccount, ordersURL string) AccountResponseJSON {
|
|
contact := acct.Contact
|
|
if contact == nil {
|
|
// RFC 8555 doesn't require contact be present, but cert-manager
|
|
// + lego both expect a stable shape. Emit [] rather than null.
|
|
contact = []string{}
|
|
}
|
|
return AccountResponseJSON{
|
|
Status: string(acct.Status),
|
|
Contact: contact,
|
|
Orders: ordersURL,
|
|
}
|
|
}
|
|
|
|
// NewAccountRequest is the payload shape RFC 8555 §7.3 mandates for
|
|
// new-account requests. The handler json.Unmarshals VerifiedRequest.Payload
|
|
// into this struct after JWS verify succeeds.
|
|
type NewAccountRequest struct {
|
|
// Contact is a list of mailto: / tel: URIs. Optional per RFC 8555
|
|
// but operators typically supply at least one mailto:.
|
|
Contact []string `json:"contact,omitempty"`
|
|
// TermsOfServiceAgreed signals client consent to the operator's
|
|
// ToS document (advertised via meta.termsOfService). Phase 1b
|
|
// records the value but does NOT enforce — the meta field is
|
|
// informational only at this stage.
|
|
TermsOfServiceAgreed bool `json:"termsOfServiceAgreed,omitempty"`
|
|
// OnlyReturnExisting, when true, asks the server to return the
|
|
// existing account row for this JWK (RFC 8555 §7.3.1). When
|
|
// true and no account exists, the server MUST return 400 +
|
|
// urn:ietf:params:acme:error:accountDoesNotExist.
|
|
OnlyReturnExisting bool `json:"onlyReturnExisting,omitempty"`
|
|
// ExternalAccountBinding (EAB) is RFC 8555 §7.3.4. Phase 1b
|
|
// accepts the field but does NOT validate — EAB enforcement is
|
|
// a deliberate out-of-scope per the master prompt and lands as a
|
|
// follow-up if there's demand. Storing the raw envelope means a
|
|
// future phase can backfill validation against historical accounts.
|
|
ExternalAccountBinding map[string]interface{} `json:"externalAccountBinding,omitempty"`
|
|
}
|
|
|
|
// AccountUpdateRequest is the payload shape for the account-update
|
|
// endpoint POST /acme/profile/<id>/account/<acc-id> (RFC 8555 §7.3.2 +
|
|
// §7.3.6). Only `contact` and `status` are mutable per the spec.
|
|
type AccountUpdateRequest struct {
|
|
// Contact, when non-nil, replaces the account's contact list.
|
|
// nil means "leave unchanged" (distinct from empty []string{}
|
|
// which means "clear contacts" — cert-manager doesn't issue
|
|
// either, but the spec permits both).
|
|
Contact []string `json:"contact,omitempty"`
|
|
// Status, when set to "deactivated", retires the account per
|
|
// RFC 8555 §7.3.6. Other values are rejected — the operator
|
|
// path for revoked is via certctl's API, not via ACME.
|
|
Status string `json:"status,omitempty"`
|
|
}
|