0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-23 22:27:38 -05:00
caddy/caddytls/storage.go
Chad Retz 88a2811e2a Pluggable TLS Storage (#913)
* Initial concept for pluggable storage (sans tests and docs)

* Add TLS storage docs, test harness, and minor clean up from code review

* Fix issue with caddymain's temporary moveStorage

* Formatting improvement on struct array literal by removing struct name

* Pluggable storage changes:

* Change storage interface to persist all site or user data in one call
* Add lock/unlock calls for renewal and cert obtaining

* Key fields on composite literals
2016-07-08 07:32:31 -06:00

105 lines
4.4 KiB
Go

package caddytls
import (
"errors"
"net/url"
)
// ErrStorageNotFound is returned by Storage implementations when data is
// expected to be present but is not.
var ErrStorageNotFound = errors.New("data not found")
// StorageCreator is a function type that is used in the Config to instantiate
// a new Storage instance. This function can return a nil Storage even without
// an error.
type StorageCreator func(caURL *url.URL) (Storage, error)
// SiteData contains persisted items pertaining to an individual site.
type SiteData struct {
// Cert is the public cert byte array.
Cert []byte
// Key is the private key byte array.
Key []byte
// Meta is metadata about the site used by Caddy.
Meta []byte
}
// UserData contains persisted items pertaining to a user.
type UserData struct {
// Reg is the user registration byte array.
Reg []byte
// Key is the user key byte array.
Key []byte
}
// Storage is an interface abstracting all storage used by the Caddy's TLS
// subsystem. Implementations of this interface store site data along with
// user data.
type Storage interface {
// SiteDataExists returns true if this site info exists in storage.
// Site data is considered present when StoreSite has been called
// successfully (without DeleteSite having been called of course).
SiteExists(domain string) bool
// LoadSite obtains the site data from storage for the given domain and
// returns. If data for the domain does not exist, the
// ErrStorageNotFound error instance is returned. For multi-server
// storage, care should be taken to make this load atomic to prevent
// race conditions that happen with multiple data loads.
LoadSite(domain string) (*SiteData, error)
// StoreSite persists the given site data for the given domain in
// storage. For multi-server storage, care should be taken to make this
// call atomic to prevent half-written data on failure of an internal
// intermediate storage step. Implementers can trust that at runtime
// this function will only be invoked after LockRegister and before
// UnlockRegister of the same domain.
StoreSite(domain string, data *SiteData) error
// DeleteSite deletes the site for the given domain from storage.
// Multi-server implementations should attempt to make this atomic. If
// the site does not exist, the ErrStorageNotFound error instance is
// returned.
DeleteSite(domain string) error
// LockRegister is called before Caddy attempts to obtain or renew a
// certificate. This function is used as a mutex/semaphore for making
// sure something else isn't already attempting obtain/renew. It should
// return true (without error) if the lock is successfully obtained
// meaning nothing else is attempting renewal. It should return false
// (without error) if this domain is already locked by something else
// attempting renewal. As a general rule, if this isn't multi-server
// shared storage, this should always return true. To prevent deadlocks
// for multi-server storage, all internal implementations should put a
// reasonable expiration on this lock in case UnlockRegister is unable to
// be called due to system crash. Errors should only be returned in
// exceptional cases. Any error will prevent renewal.
LockRegister(domain string) (bool, error)
// UnlockRegister is called after Caddy has attempted to obtain or renew
// a certificate, regardless of whether it was successful. If
// LockRegister essentially just returns true because this is not
// multi-server storage, this can be a no-op. Otherwise this should
// attempt to unlock the lock obtained in this process by LockRegister.
// If no lock exists, the implementation should not return an error. An
// error is only for exceptional cases.
UnlockRegister(domain string) error
// LoadUser obtains user data from storage for the given email and
// returns it. If data for the email does not exist, the
// ErrStorageNotFound error instance is returned. Multi-server
// implementations should take care to make this operation atomic for
// all loaded data items.
LoadUser(email string) (*UserData, error)
// StoreUser persists the given user data for the given email in
// storage. Multi-server implementations should take care to make this
// operation atomic for all stored data items.
StoreUser(email string, data *UserData) error
// MostRecentUserEmail provides the most recently used email parameter
// in StoreUser. The result is an empty string if there are no
// persisted users in storage.
MostRecentUserEmail() string
}