File: challenge.go

package info (click to toggle)
golang-github-smallstep-certificates 0.29.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,720 kB
  • sloc: sh: 385; makefile: 129
file content (109 lines) | stat: -rw-r--r-- 3,061 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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)
}