forked from TrueCloudLab/certificates
[acme] Use lock for ordersByAccID and type to house methods
This commit is contained in:
parent
6049d42b5f
commit
f34fb80eb6
3 changed files with 80 additions and 53 deletions
|
@ -195,49 +195,3 @@ func getAccountByKeyID(db nosql.DB, kid string) (*account, error) {
|
|||
}
|
||||
return getAccountByID(db, string(id))
|
||||
}
|
||||
|
||||
// getOrderIDsByAccount retrieves a list of Order IDs that were created by the
|
||||
// account.
|
||||
func getOrderIDsByAccount(db nosql.DB, accID string) ([]string, error) {
|
||||
b, err := db.Get(ordersByAccountIDTable, []byte(accID))
|
||||
if err != nil {
|
||||
if nosql.IsErrNotFound(err) {
|
||||
return []string{}, nil
|
||||
}
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error loading orderIDs for account %s", accID))
|
||||
}
|
||||
var oids []string
|
||||
if err := json.Unmarshal(b, &oids); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error unmarshaling orderIDs for account %s", accID))
|
||||
}
|
||||
|
||||
// Remove any order that is not in PENDING state and update the stored list
|
||||
// before returning.
|
||||
//
|
||||
// According to RFC 8555:
|
||||
// The server SHOULD include pending orders and SHOULD NOT include orders
|
||||
// that are invalid in the array of URLs.
|
||||
pendOids := []string{}
|
||||
for _, oid := range oids {
|
||||
o, err := getOrder(db, oid)
|
||||
if err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error loading order %s for account %s", oid, accID))
|
||||
}
|
||||
if o, err = o.updateStatus(db); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error updating order %s for account %s", oid, accID))
|
||||
}
|
||||
if o.Status == StatusPending {
|
||||
pendOids = append(pendOids, oid)
|
||||
}
|
||||
}
|
||||
// If the number of pending orders is less than the number of orders in the
|
||||
// list, then update the pending order list.
|
||||
if len(pendOids) != len(oids) {
|
||||
if err = orderIDs(pendOids).save(db, oids, accID); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error storing orderIDs as part of getOrderIDsByAccount logic: "+
|
||||
"len(orderIDs) = %d", len(pendOids)))
|
||||
}
|
||||
}
|
||||
|
||||
return pendOids, nil
|
||||
}
|
||||
|
|
|
@ -233,7 +233,8 @@ func (a *Authority) GetOrder(ctx context.Context, accID, orderID string) (*Order
|
|||
|
||||
// GetOrdersByAccount returns the list of order urls owned by the account.
|
||||
func (a *Authority) GetOrdersByAccount(ctx context.Context, id string) ([]string, error) {
|
||||
oids, err := getOrderIDsByAccount(a.db, id)
|
||||
var oiba = orderIDsByAccount{}
|
||||
oids, err := oiba.getOrderIDsByAccount(a.db, id, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -16,6 +17,9 @@ import (
|
|||
|
||||
var defaultOrderExpiry = time.Hour * 24
|
||||
|
||||
// Mutex for locking ordersByAccount index operations.
|
||||
var ordersByAccountMux = &sync.Mutex{}
|
||||
|
||||
// Order contains order metadata for the ACME protocol order type.
|
||||
type Order struct {
|
||||
Status string `json:"status"`
|
||||
|
@ -111,17 +115,84 @@ func newOrder(db nosql.DB, ops OrderOptions) (*order, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Update the "order IDs by account ID" index //
|
||||
oids, err := getOrderIDsByAccount(db, ops.AccountID)
|
||||
var oidHelper = orderIDsByAccount{}
|
||||
_, err = oidHelper.addOrderID(db, ops.AccountID, o.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newOids := append(oids, o.ID)
|
||||
if err = orderIDs(newOids).save(db, oids, o.AccountID); err != nil {
|
||||
db.Del(orderTable, []byte(o.ID))
|
||||
return o, nil
|
||||
}
|
||||
|
||||
type orderIDsByAccount struct{}
|
||||
|
||||
func (oiba orderIDsByAccount) addOrderID(db nosql.DB, accID string, oid string) ([]string, error) {
|
||||
ordersByAccountMux.Lock()
|
||||
defer ordersByAccountMux.Unlock()
|
||||
|
||||
// Update the "order IDs by account ID" index
|
||||
oids, err := oiba.getOrderIDsByAccount(db, accID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, nil
|
||||
newOids := append(oids, oid)
|
||||
if err = orderIDs(newOids).save(db, oids, accID); err != nil {
|
||||
// Delete the entire order if storing the index fails.
|
||||
db.Del(orderTable, []byte(oid))
|
||||
return nil, err
|
||||
}
|
||||
return newOids, nil
|
||||
}
|
||||
|
||||
// getOrderIDsByAccount retrieves a list of Order IDs that were created by the
|
||||
// account.
|
||||
func (oiba orderIDsByAccount) getOrderIDsByAccount(db nosql.DB, accID string, alreadyLocked bool) ([]string, error) {
|
||||
if !alreadyLocked {
|
||||
ordersByAccountMux.Lock()
|
||||
|
||||
defer ordersByAccountMux.Unlock()
|
||||
}
|
||||
|
||||
b, err := db.Get(ordersByAccountIDTable, []byte(accID))
|
||||
if err != nil {
|
||||
if nosql.IsErrNotFound(err) {
|
||||
return []string{}, nil
|
||||
}
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error loading orderIDs for account %s", accID))
|
||||
}
|
||||
var oids []string
|
||||
if err := json.Unmarshal(b, &oids); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error unmarshaling orderIDs for account %s", accID))
|
||||
}
|
||||
|
||||
// Remove any order that is not in PENDING state and update the stored list
|
||||
// before returning.
|
||||
//
|
||||
// According to RFC 8555:
|
||||
// The server SHOULD include pending orders and SHOULD NOT include orders
|
||||
// that are invalid in the array of URLs.
|
||||
pendOids := []string{}
|
||||
for _, oid := range oids {
|
||||
o, err := getOrder(db, oid)
|
||||
if err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error loading order %s for account %s", oid, accID))
|
||||
}
|
||||
if o, err = o.updateStatus(db); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error updating order %s for account %s", oid, accID))
|
||||
}
|
||||
if o.Status == StatusPending {
|
||||
pendOids = append(pendOids, oid)
|
||||
}
|
||||
}
|
||||
// If the number of pending orders is less than the number of orders in the
|
||||
// list, then update the pending order list.
|
||||
if len(pendOids) != len(oids) {
|
||||
if err = orderIDs(pendOids).save(db, oids, accID); err != nil {
|
||||
return nil, ServerInternalErr(errors.Wrapf(err, "error storing orderIDs as part of getOrderIDsByAccount logic: "+
|
||||
"len(orderIDs) = %d", len(pendOids)))
|
||||
}
|
||||
}
|
||||
|
||||
return pendOids, nil
|
||||
}
|
||||
|
||||
type orderIDs []string
|
||||
|
@ -271,6 +342,7 @@ func (o *order) finalize(db nosql.DB, csr *x509.CertificateRequest, auth SignAut
|
|||
if o, err = o.updateStatus(db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch o.Status {
|
||||
case StatusInvalid:
|
||||
return nil, OrderNotReadyErr(errors.Errorf("order %s has been abandoned", o.ID))
|
||||
|
|
Loading…
Reference in a new issue