package queries import ( "sync" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/security" "github.com/fiskerinc/cloud-services/pkg/validator" "github.com/go-pg/pg/v10" "github.com/go-pg/pg/v10/orm" "github.com/pkg/errors" berrors "errors" ) type FileKeysInterface interface { Delete(fileID string) (orm.Result, error) Insert(filekey common.FileKey) (orm.Result, error) Get(fileID string) (*common.FileKey, error) GetMulti(fileIDs []string) ([]common.FileKey, error) } type FileKeys struct { QueryBase encryptor security.IEncryptor once sync.Once } func (fk *FileKeys) getEncryptor() (security.IEncryptor, error) { var err error fk.once.Do(func() { encrypt := security.Encrypt{} fk.encryptor, err = encrypt.GetEncryptor() }) return fk.encryptor, err } // Delete deletes fileID of FileKey from database func (fk *FileKeys) Delete(fileID string) (orm.Result, error) { if fileID == "" { return nil, errors.WithStack(&validator.FieldError{ ErrorMsg: "FileID required", }) } conn := fk.GetDBConn() return fk.resultWithStack(conn.Model(&common.FileKey{ FileID: fileID, }).WherePK().Delete()) } // Insert makes a copy of FileKey, encrypts encryption parameters, and inserts into database func (fk *FileKeys) Insert(filekey common.FileKey) (orm.Result, error) { err := validator.ValidateStruct(filekey) if err != nil { return nil, errors.WithStack(err) } err = fk.encrypt(&filekey) if err != nil { return nil, err } return fk.resultWithStack(fk.GetDBConn().Model(&filekey).Insert()) } func (fk *FileKeys) Get(fileID string) (*common.FileKey, error) { if fileID == "" { return nil, errors.WithStack(&validator.FieldError{ ErrorMsg: "FileID required", }) } filekey := []common.FileKey{} err := fk.GetDBConn().Model(&filekey).Where("file_id = ?", fileID).Select() if err != nil { return nil, errors.WithStack(err) } if len(filekey) == 0 { return &common.FileKey{}, nil } err = fk.decrypt(&filekey[0]) if err != nil { return nil, err } return &filekey[0], nil } func (fk *FileKeys) GetMulti(fileIDs []string) ([]common.FileKey, error) { filekeys := []common.FileKey{} if len(fileIDs) == 0 { return filekeys, nil } err := fk.GetDBConn().Model(&filekeys).Where("file_id in (?)", pg.In(fileIDs)).Select() if err != nil { return nil, errors.WithStack(err) } var masterError error for i := range filekeys { err = fk.decrypt(&filekeys[i]) if err != nil { masterError = berrors.Join(masterError, err) filekeys[i].Error = err.Error() } } return filekeys, masterError } func (fk *FileKeys) encrypt(filekey *common.FileKey) error { encryptor, err := fk.getEncryptor() if err != nil { return err } filekey.Key = encryptor.EncryptChunk([]byte(filekey.Key)) filekey.Auth = encryptor.EncryptChunk([]byte(filekey.Auth)) filekey.Nonce = encryptor.EncryptChunk([]byte(filekey.Nonce)) return nil } func (fk *FileKeys) decrypt(filekey *common.FileKey) error { encryptor, err := fk.getEncryptor() if err != nil { return err } value, err := encryptor.DecryptChunk([]byte(filekey.Key)) if err != nil { return err } filekey.Key = value value, err = encryptor.DecryptChunk([]byte(filekey.Auth)) if err != nil { return err } filekey.Auth = value value, err = encryptor.DecryptChunk([]byte(filekey.Nonce)) if err != nil { return err } filekey.Nonce = value return nil }