github.com/adecaro/fabric-ca@v2.0.0-alpha+incompatible/lib/server/idemix/creddbaccessor.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package idemix 8 9 import ( 10 "fmt" 11 "reflect" 12 "time" 13 14 "github.com/cloudflare/cfssl/log" 15 "github.com/hyperledger/fabric-ca/lib/server/db" 16 "github.com/kisielk/sqlstruct" 17 "github.com/pkg/errors" 18 ) 19 20 const ( 21 // InsertCredentialSQL is the SQL to add a credential to database 22 InsertCredentialSQL = ` 23 INSERT INTO credentials (id, revocation_handle, cred, ca_label, status, reason, expiry, revoked_at, level) 24 VALUES (:id, :revocation_handle, :cred, :ca_label, :status, :reason, :expiry, :revoked_at, :level);` 25 26 // SelectCredentialByIDSQL is the SQL for getting credentials of a user 27 SelectCredentialByIDSQL = ` 28 SELECT %s FROM credentials 29 WHERE (id = ?);` 30 31 // SelectCredentialSQL is the SQL for getting a credential given a revocation handle 32 SelectCredentialSQL = ` 33 SELECT %s FROM credentials 34 WHERE (revocation_handle = ?);` 35 36 // SelectRevokedCredentialSQL is the SQL for getting revoked credentials 37 SelectRevokedCredentialSQL = ` 38 SELECT %s FROM credentials 39 WHERE (status = 'revoked');` 40 41 // UpdateRevokeCredentialSQL is the SQL for updating status of a credential to revoked 42 UpdateRevokeCredentialSQL = ` 43 UPDATE credentials 44 SET status='revoked', revoked_at=CURRENT_TIMESTAMP, reason=:reason 45 WHERE (id = :id AND status != 'revoked');` 46 47 // DeleteCredentialbyID is the SQL for deleting credential of a user 48 DeleteCredentialbyID = ` 49 DELETE FROM credentials 50 WHERE (id = ?);` 51 ) 52 53 // CredRecord represents a credential database record 54 type CredRecord struct { 55 ID string `db:"id"` 56 RevocationHandle string `db:"revocation_handle"` 57 Cred string `db:"cred"` 58 CALabel string `db:"ca_label"` 59 Status string `db:"status"` 60 Reason int `db:"reason"` 61 Expiry time.Time `db:"expiry"` 62 RevokedAt time.Time `db:"revoked_at"` 63 Level int `db:"level"` 64 } 65 66 //go:generate mockery -name CredDBAccessor -case underscore 67 68 // CredDBAccessor is the accessor for credentials database table 69 type CredDBAccessor interface { 70 // Sets reference to datastore object 71 SetDB(db db.FabricCADB) 72 // InsertCredential inserts specified Idemix credential record into database 73 InsertCredential(cr CredRecord) error 74 // GetCredential returns Idemix credential associated with the specified revocation 75 // handle 76 GetCredential(revocationHandle string) (*CredRecord, error) 77 // GetCredentialsByID returns Idemix credentials associated with the specified 78 // enrollment ID 79 GetCredentialsByID(id string) ([]CredRecord, error) 80 // GetRevokedCredentials returns revoked credentials 81 GetRevokedCredentials() ([]CredRecord, error) 82 } 83 84 // CredentialAccessor implements IdemixCredDBAccessor interface 85 type CredentialAccessor struct { 86 level int 87 db db.FabricCADB 88 } 89 90 // NewCredentialAccessor returns a new CredentialAccessor. 91 func NewCredentialAccessor(db db.FabricCADB, level int) CredDBAccessor { 92 ac := new(CredentialAccessor) 93 ac.db = db 94 ac.level = level 95 return ac 96 } 97 98 // SetDB changes the underlying sql.DB object Accessor is manipulating. 99 func (ac *CredentialAccessor) SetDB(db db.FabricCADB) { 100 ac.db = db 101 } 102 103 // InsertCredential puts a CredentialRecord into db. 104 func (ac *CredentialAccessor) InsertCredential(cr CredRecord) error { 105 log.Debug("DB: Insert Credential") 106 err := ac.checkDB() 107 if err != nil { 108 return err 109 } 110 cr.Level = ac.level 111 res, err := ac.db.NamedExec("InsertCredential", InsertCredentialSQL, cr) 112 if err != nil { 113 return errors.Wrap(err, "Failed to insert credential into datastore") 114 } 115 116 numRowsAffected, err := res.RowsAffected() 117 118 if numRowsAffected == 0 { 119 return errors.New("Failed to insert the credential record; no rows affected") 120 } 121 122 if numRowsAffected != 1 { 123 return errors.Errorf("Expected to affect 1 entry in credentials table but affected %d", 124 numRowsAffected) 125 } 126 127 return err 128 } 129 130 // GetCredentialsByID gets a CredentialRecord indexed by id. 131 func (ac *CredentialAccessor) GetCredentialsByID(id string) ([]CredRecord, error) { 132 log.Debugf("DB: Get credentials by ID '%s'", id) 133 err := ac.checkDB() 134 if err != nil { 135 return nil, err 136 } 137 crs := []CredRecord{} 138 err = ac.db.Select("GetCredentialsByID", &crs, fmt.Sprintf(ac.db.Rebind(SelectCredentialByIDSQL), sqlstruct.Columns(CredRecord{})), id) 139 if err != nil { 140 return nil, errors.Wrapf(err, "Failed to get credentials for identity '%s' from datastore", id) 141 } 142 143 return crs, nil 144 } 145 146 // GetCredential gets a CredentialRecord indexed by revocationHandle. 147 func (ac *CredentialAccessor) GetCredential(revocationHandle string) (*CredRecord, error) { 148 log.Debugf("DB: Get credential by revocation handle '%s'", revocationHandle) 149 err := ac.checkDB() 150 if err != nil { 151 return nil, err 152 } 153 cr := &CredRecord{} 154 err = ac.db.Select("GetCredential", cr, fmt.Sprintf(ac.db.Rebind(SelectCredentialSQL), sqlstruct.Columns(CredRecord{})), revocationHandle) 155 if err != nil { 156 return nil, errors.Wrapf(err, "Failed to get credential associated with revocation handle '%s' from datastore", revocationHandle) 157 } 158 159 return cr, nil 160 } 161 162 // GetRevokedCredentials returns revoked certificates 163 func (ac *CredentialAccessor) GetRevokedCredentials() ([]CredRecord, error) { 164 err := ac.checkDB() 165 if err != nil { 166 return nil, err 167 } 168 crs := []CredRecord{} 169 err = ac.db.Select("GetRevokedCredentials", &crs, fmt.Sprintf(ac.db.Rebind(SelectRevokedCredentialSQL), sqlstruct.Columns(CredRecord{}))) 170 if err != nil { 171 return crs, errors.Wrap(err, "Failed to get revoked credentials from datastore") 172 } 173 return crs, nil 174 } 175 176 func (ac *CredentialAccessor) checkDB() error { 177 if ac.db == nil || reflect.ValueOf(ac.db).IsNil() { 178 return errors.New("Database is not set") 179 } 180 return nil 181 }