1 // Package accesstoken provides storage and validation of Chain Core
13 "github.com/bytom/vapor/crypto/sha3pool"
14 dbm "github.com/bytom/vapor/database/leveldb"
15 "github.com/bytom/vapor/errors"
21 // ErrBadID is returned when Create is called on an invalid id string.
22 ErrBadID = errors.New("invalid id")
23 // ErrDuplicateID is returned when Create is called on an existing ID.
24 ErrDuplicateID = errors.New("duplicate access token ID")
25 // ErrBadType is returned when Create is called with a bad type.
26 ErrBadType = errors.New("type must be client or network")
27 // ErrNoMatchID is returned when Delete is called on nonexisting ID.
28 ErrNoMatchID = errors.New("nonexisting access token ID")
29 // ErrInvalidToken is returned when Check is called on invalid token
30 ErrInvalidToken = errors.New("invalid token")
32 // validIDRegexp checks that all characters are alphumeric, _ or -.
33 // It also must have a length of at least 1.
34 validIDRegexp = regexp.MustCompile(`^[\w-]+$`)
37 // Token describe the access token.
40 Token string `json:"token,omitempty"`
41 Type string `json:"type,omitempty"`
42 Created time.Time `json:"created_at"`
45 // CredentialStore store user access credential.
46 type CredentialStore struct {
50 // NewStore creates and returns a new Store object.
51 func NewStore(db dbm.DB) *CredentialStore {
52 return &CredentialStore{
57 // Create generates a new access token with the given ID.
58 func (cs *CredentialStore) Create(id, typ string) (*Token, error) {
59 if !validIDRegexp.MatchString(id) {
60 return nil, errors.WithDetailf(ErrBadID, "invalid id %q", id)
64 if cs.DB.Get(key) != nil {
65 return nil, errors.WithDetailf(ErrDuplicateID, "id %q already in use", id)
68 secret := make([]byte, tokenSize)
69 if _, err := rand.Read(secret); err != nil {
73 hashedSecret := make([]byte, tokenSize)
74 sha3pool.Sum256(hashedSecret, secret)
77 Token: fmt.Sprintf("%s:%x", id, hashedSecret),
82 value, err := json.Marshal(token)
91 // Check returns whether or not an id-secret pair is a valid access token.
92 func (cs *CredentialStore) Check(id string, secret string) error {
93 if !validIDRegexp.MatchString(id) {
94 return errors.WithDetailf(ErrBadID, "invalid id %q", id)
97 value := cs.DB.Get([]byte(id))
99 return errors.WithDetailf(ErrNoMatchID, "check id %q nonexisting", id)
103 if err := json.Unmarshal(value, token); err != nil {
107 if strings.Split(token.Token, ":")[1] == secret {
111 return ErrInvalidToken
114 // List lists all access tokens.
115 func (cs *CredentialStore) List() ([]*Token, error) {
116 tokens := make([]*Token, 0)
117 iter := cs.DB.Iterator()
122 if err := json.Unmarshal(iter.Value(), token); err != nil {
125 tokens = append(tokens, token)
130 // Delete deletes an access token by id.
131 func (cs *CredentialStore) Delete(id string) error {
132 if !validIDRegexp.MatchString(id) {
133 return errors.WithDetailf(ErrBadID, "invalid id %q", id)
136 if value := cs.DB.Get([]byte(id)); value == nil {
137 return errors.WithDetailf(ErrNoMatchID, "check id %q", id)
140 cs.DB.Delete([]byte(id))