All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sss.openstar.attachments.LocalAttachmentsService.scala Maven / Gradle / Ivy

package sss.openstar.attachments

import java.io.InputStream
import java.sql.SQLIntegrityConstraintViolationException
import sss.ancillary.Guid
import sss.db._
import sss.openstar.attachments.AttachmentsService.EncryptedAttachment
import sss.openstar.crypto.AESDetails.AESEncodedKey
import sss.openstar.crypto.{CBCEncryption, CBCStreamEncryption}

import scala.util.Try
import sss.openstar.schemamigration.SqlSchemaNames.ColumnNames._
import sss.db.ops.DbOps.{DbRunOps, FutureTxOps}
import sss.openstar.schemamigration.SqlSchemaNames

class LocalAttachmentsService(
                   streamPersister: StreamPersister
                   )(implicit db: Db) {

  private[attachments] val table = db.table(SqlSchemaNames.TableNames.attachmentsTableName)

  def forUser(who: String): LocalAttachments = new LocalAttachments(who, streamPersister, this)

  def find(
            guid: Guid,
            name: String): Option[EncryptedAttachment] = {
    table.find(
      where(
        nameCol -> name,
        guidCol -> guid.value
        //ownerCol -> who
      )
    ).dbRunSyncGet.map(row => {
      val inputStream = streamPersister
        .getStream(
          UniqueLocator(row.string(locationUrlCol)))
        .get

      EncryptedAttachment(
        inputStream,
        Guid(row.arrayByte(guidCol)),
        row.string(nameCol),
        row.string(mimeCol),
        row.long(lenCol),
        CBCEncryption.initVector(row.arrayByte(ivKeyCol)))
    })
  }
}

class LocalAttachments(
                   who:String,
                   streamPersister: StreamPersister,
                   service:LocalAttachmentsService)(implicit db: Db) {

  require(Option(who).isDefined && who.length > 0, "User must not be null or empty")

  val table = service.table

  def delete(guid: Guid, name: String): Try[Int] = {
    table.delete(
      where(
        guidCol -> guid.value,
        nameCol -> name
      )
    )
  }.dbRunSync

  def delete(guid: Guid): Try[Int] = {
    table.delete(
      where(
        guidCol -> guid.value,
      )
    )
  }.dbRunSync

  def filter(
              guid: Guid,
              lenLessThan: Long = Long.MaxValue): Seq[EncryptedAttachment] = {

    table.filter(
      where(
        guidCol -> guid.value,
        ownerCol -> who
      ) and where(s"$lenCol < $lenLessThan")
    ).dbRunSyncGet.map(row => {
      val is = streamPersister.getStream(
        UniqueLocator(
          row.string(locationUrlCol)))
        .get

      EncryptedAttachment(
        is,
        Guid(row.arrayByte(guidCol)),
        row.string(nameCol),
        row.string(mimeCol),
        row.long(lenCol),
        CBCEncryption.initVector(row.arrayByte(ivKeyCol)))
    })
  }

  def find(
            guid: Guid,
            name: String): Option[EncryptedAttachment] = service.find(guid, name)

  def saveEncrypted(guid: Guid,
                    name: String,
                    mimeType: String,
                    key: AESEncodedKey,
                    clearInputStream: InputStream
                   ): Try[Long] = Try {

    val encryptedStream = CBCStreamEncryption.encrypt(clearInputStream, key)
    val locator = streamPersister.saveStream(encryptedStream.encrypted, who, guid.toString, name).get
    (locator, encryptedStream)
  }.flatMap {
    case (locator, encryptedStream) =>
      table.insert(Map(
        guidCol -> guid.value,
        nameCol -> name,
        ownerCol -> who,
        mimeCol -> mimeType,
        ivKeyCol -> encryptedStream.iv.bytes,
        lenCol -> locator.size.getOrElse(0),
        locationUrlCol -> locator.location
      )).recoverWithDb {
        case _: SQLIntegrityConstraintViolationException =>
          table.update(Map(
            ivKeyCol -> encryptedStream.iv.bytes,
            lenCol -> locator.size.getOrElse(0),
            locationUrlCol -> locator.location
          ), where(
            guidCol -> guid.value,
            nameCol -> name,
            ownerCol -> who
          ))
      }.dbRunSync.map[Long](_ => locator.size.getOrElse(0))
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy