Files
cloud-services/pkg/db/queries/filekeys.go

154 lines
3.4 KiB
Go

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
}