mirror of
https://github.com/smallstep/certificates.git
synced 2024-11-17 15:29:21 +00:00
01169b2483
This is a non-standard property in the ACME challenge response, so we shouldn't return it if it's not set. Also made it an optional field in the DB.
110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package nosql
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/smallstep/nosql"
|
|
|
|
"github.com/smallstep/certificates/acme"
|
|
)
|
|
|
|
type dbChallenge struct {
|
|
ID string `json:"id"`
|
|
AccountID string `json:"accountID"`
|
|
Type acme.ChallengeType `json:"type"`
|
|
Status acme.Status `json:"status"`
|
|
Token string `json:"token"`
|
|
Value string `json:"value"`
|
|
Target string `json:"target,omitempty"`
|
|
ValidatedAt string `json:"validatedAt"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
Error *acme.Error `json:"error"` // TODO(hs): a bit dangerous; should become db-specific type
|
|
}
|
|
|
|
func (dbc *dbChallenge) clone() *dbChallenge {
|
|
u := *dbc
|
|
return &u
|
|
}
|
|
|
|
func (db *DB) getDBChallenge(_ context.Context, id string) (*dbChallenge, error) {
|
|
data, err := db.db.Get(challengeTable, []byte(id))
|
|
if nosql.IsErrNotFound(err) {
|
|
return nil, acme.NewError(acme.ErrorMalformedType, "challenge %s not found", id)
|
|
} else if err != nil {
|
|
return nil, errors.Wrapf(err, "error loading acme challenge %s", id)
|
|
}
|
|
|
|
dbch := new(dbChallenge)
|
|
if err := json.Unmarshal(data, dbch); err != nil {
|
|
return nil, errors.Wrap(err, "error unmarshaling dbChallenge")
|
|
}
|
|
return dbch, nil
|
|
}
|
|
|
|
// CreateChallenge creates a new ACME challenge data structure in the database.
|
|
// Implements acme.DB.CreateChallenge interface.
|
|
func (db *DB) CreateChallenge(ctx context.Context, ch *acme.Challenge) error {
|
|
var err error
|
|
ch.ID, err = randID()
|
|
if err != nil {
|
|
return errors.Wrap(err, "error generating random id for ACME challenge")
|
|
}
|
|
|
|
dbch := &dbChallenge{
|
|
ID: ch.ID,
|
|
AccountID: ch.AccountID,
|
|
Value: ch.Value,
|
|
Status: acme.StatusPending,
|
|
Token: ch.Token,
|
|
CreatedAt: clock.Now(),
|
|
Type: ch.Type,
|
|
Target: ch.Target,
|
|
}
|
|
|
|
return db.save(ctx, ch.ID, dbch, nil, "challenge", challengeTable)
|
|
}
|
|
|
|
// GetChallenge retrieves and unmarshals an ACME challenge type from the database.
|
|
// Implements the acme.DB GetChallenge interface.
|
|
func (db *DB) GetChallenge(ctx context.Context, id, authzID string) (*acme.Challenge, error) {
|
|
_ = authzID // unused input
|
|
dbch, err := db.getDBChallenge(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ch := &acme.Challenge{
|
|
ID: dbch.ID,
|
|
AccountID: dbch.AccountID,
|
|
Type: dbch.Type,
|
|
Value: dbch.Value,
|
|
Status: dbch.Status,
|
|
Token: dbch.Token,
|
|
Error: dbch.Error,
|
|
ValidatedAt: dbch.ValidatedAt,
|
|
Target: dbch.Target,
|
|
}
|
|
return ch, nil
|
|
}
|
|
|
|
// UpdateChallenge updates an ACME challenge type in the database.
|
|
func (db *DB) UpdateChallenge(ctx context.Context, ch *acme.Challenge) error {
|
|
old, err := db.getDBChallenge(ctx, ch.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
nu := old.clone()
|
|
|
|
// These should be the only values changing in an Update request.
|
|
nu.Status = ch.Status
|
|
nu.Error = ch.Error
|
|
nu.ValidatedAt = ch.ValidatedAt
|
|
|
|
return db.save(ctx, old.ID, nu, old, "challenge", challengeTable)
|
|
}
|