Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

metaVolumes for #496 #631

Merged
merged 13 commits into from
Oct 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions box/src/main/java/de/qabel/box/storage/BoxVolume.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ package de.qabel.box.storage
import de.qabel.box.storage.exceptions.QblStorageException

interface BoxVolume {
/**
* Calculate the filename of the index metadata file
*/
@Deprecated("gets removed soon")
val rootRef: String

val config: BoxVolumeConfig

fun getReadBackend(): StorageReadBackend
Expand All @@ -25,7 +19,9 @@ interface BoxVolume {

/**
* Create a new index metadata file
* @Deprecated use BoxVolume#createIndex(root: String) instead
*/
@Deprecated("insert root, you shouldn't know the bucket", ReplaceWith("createIndex(root: String)"))
@Throws(QblStorageException::class)
fun createIndex(bucket: String, prefix: String)

Expand Down
4 changes: 2 additions & 2 deletions box/src/main/java/de/qabel/box/storage/BoxVolumeConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import java.io.File

class BoxVolumeConfig(
val prefix: String,
val rootRef: String,
val deviceId: ByteArray,
val readBackend: StorageReadBackend,
val writeBackend: StorageWriteBackend,
var defaultHashAlgorithm: String,
val tempDir: File,
val directoryMetadataFactoryFactory: (File, ByteArray) -> DirectoryMetadataFactory =
{ tempDir, deviceId -> JdbcDirectoryMetadataFactory(tempDir, deviceId) },
val fileMetadataFactoryFactory: (File) -> FileMetadataFactory =
{ JdbcFileMetadataFactory(it) }
val fileMetadataFactoryFactory: (File) -> FileMetadataFactory = { JdbcFileMetadataFactory(it) }
) {
val directoryFactory: DirectoryMetadataFactory by lazy { directoryMetadataFactoryFactory(tempDir, deviceId) }
val fileFactory: FileMetadataFactory by lazy { fileMetadataFactoryFactory(tempDir) }
Expand Down
55 changes: 17 additions & 38 deletions box/src/main/java/de/qabel/box/storage/BoxVolumeImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@ package de.qabel.box.storage

import de.qabel.box.storage.exceptions.QblStorageException
import de.qabel.box.storage.exceptions.QblStorageIOFailure
import de.qabel.box.storage.exceptions.QblStorageInvalidKey
import de.qabel.box.storage.hash.QabelBoxDigestProvider
import de.qabel.core.config.Prefix
import de.qabel.core.crypto.CryptoUtils
import de.qabel.core.crypto.QblECKeyPair
import org.apache.commons.io.IOUtils
import org.slf4j.LoggerFactory
import org.spongycastle.jce.provider.BouncyCastleProvider
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.ByteBuffer
import java.security.InvalidKeyException
import java.security.MessageDigest
import java.security.Security
import java.util.*

open class BoxVolumeImpl(override val config: BoxVolumeConfig, private val keyPair: QblECKeyPair) : BoxVolume {
open class BoxVolumeImpl(final override val config: BoxVolumeConfig, private val keyPair: QblECKeyPair) : BoxVolume {
private val logger by lazy { LoggerFactory.getLogger(BoxVolumeImpl::class.java) }
private val cryptoUtils = CryptoUtils()
private val indexDmDownloader by lazy {
Expand Down Expand Up @@ -51,15 +44,22 @@ open class BoxVolumeImpl(override val config: BoxVolumeConfig, private val keyPa
Security.addProvider(BouncyCastleProvider())
}

@JvmOverloads
constructor (
readBackend: StorageReadBackend,
writeBackend: StorageWriteBackend,
keyPair: QblECKeyPair,
deviceId: ByteArray,
tempDir: File,
prefix: String
prefix: String,
type: Prefix.TYPE = Prefix.TYPE.USER
) : this(
BoxVolumeConfig(prefix, deviceId, readBackend, writeBackend, "Blake2b", tempDir),
BoxVolumeConfig(prefix,
RootRefCalculator().rootFor(
keyPair.privateKey,
type,
prefix
), deviceId, readBackend, writeBackend, "Blake2b", tempDir),
keyPair
)

Expand All @@ -80,44 +80,23 @@ open class BoxVolumeImpl(override val config: BoxVolumeConfig, private val keyPa
override fun navigate(): IndexNavigation = indexNavigation

/**
* Calculate the filename of the index metadata file
* filename of the index metadata file
*/
override val rootRef by lazy {
val digest = MessageDigest.getInstance("SHA-256").apply {
update(config.prefix.toByteArray())
update(keyPair.privateKey)
}.digest()
val firstBytes = Arrays.copyOfRange(digest, 0, 16)
val bb = ByteBuffer.wrap(firstBytes)
val firstLong = bb.getLong()
val secondLong = bb.getLong()
UUID(firstLong, secondLong).toString()
}
internal val rootRef = config.rootRef

/**
* Create a new index metadata file
*/
@Throws(QblStorageException::class)
override fun createIndex(bucket: String, prefix: String) {
createIndex("https://$bucket.s3.amazonaws.com/$prefix")
}
override fun createIndex(bucket: String, prefix: String)
= createIndex("https://$bucket.s3.amazonaws.com/$prefix")

/**
* Create a new index metadata file
*/
@Throws(QblStorageException::class)
override fun createIndex(root: String) {
val dm = config.directoryFactory.create(root)
try {
val plaintext = IOUtils.toByteArray(FileInputStream(dm.path))
val encrypted = cryptoUtils.createBox(keyPair, keyPair.pub, plaintext, 0)
config.writeBackend.upload(rootRef, ByteArrayInputStream(encrypted))
} catch (e: IOException) {
throw QblStorageIOFailure(e)
} catch (e: InvalidKeyException) {
throw QblStorageInvalidKey(e)
}
}
override fun createIndex(root: String)
= createIndex(config.directoryFactory, config.writeBackend, cryptoUtils, rootRef, keyPair)
}

fun ByteArray.toLong() = ByteBuffer.wrap(this).long
64 changes: 0 additions & 64 deletions box/src/main/java/de/qabel/box/storage/LocalReadBackend.java

This file was deleted.

57 changes: 57 additions & 0 deletions box/src/main/java/de/qabel/box/storage/LocalReadBackend.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package de.qabel.box.storage

import de.qabel.box.storage.exceptions.QblStorageException
import de.qabel.box.storage.exceptions.QblStorageNotFound
import org.apache.commons.codec.digest.DigestUtils
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
import java.io.IOException

class LocalReadBackend(private val root: File) : StorageReadBackend {

@Throws(QblStorageException::class)
override fun download(name: String): StorageDownload {
try {
return download(name, null)
} catch (e: UnmodifiedException) {
throw IllegalStateException(e)
}

}

@Throws(QblStorageException::class, UnmodifiedException::class)
override fun download(name: String, ifModifiedVersion: String?): StorageDownload {
val file = root.resolve(name)

try {
if (ifModifiedVersion != null && getMHash(file) == ifModifiedVersion) {
throw UnmodifiedException()
}
} catch (e: IOException) {
// best effort
}

logger.info("Downloading file path " + file)
try {
return StorageDownload(
FileInputStream(file),
getMHash(file),
file.length())
} catch (e: IOException) {
throw QblStorageNotFound(e)
}

}

@Throws(IOException::class)
private fun getMHash(file: File): String {
FileInputStream(file).use { data -> return String(DigestUtils.md5(data)) }
}

override fun getUrl(meta: String) = root.resolve(meta).toString()

companion object {
private val logger = LoggerFactory.getLogger(LocalReadBackend::class.java)
}
}
64 changes: 0 additions & 64 deletions box/src/main/java/de/qabel/box/storage/LocalWriteBackend.java

This file was deleted.

58 changes: 58 additions & 0 deletions box/src/main/java/de/qabel/box/storage/LocalWriteBackend.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package de.qabel.box.storage

import de.qabel.box.storage.exceptions.QblStorageException
import de.qabel.box.storage.hash.Md5Hasher
import org.apache.commons.io.IOUtils
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.*

class LocalWriteBackend(private val root: File) : StorageWriteBackend {

@Throws(QblStorageException::class)
override fun upload(name: String, content: InputStream): StorageWriteBackend.UploadResult {
return upload(name, content, null)
}

@Throws(QblStorageException::class)
override fun delete(name: String) {
val file = root.resolve(name)
logger.trace("Deleting file path " + file)
try {
file.delete()
} catch (e: NoSuchFileException) {
// ignore this just like the S3 API
} catch (e: IOException) {
throw QblStorageException(e.message, e)
}

}

@Throws(QblStorageException::class, ModifiedException::class)
override fun upload(name: String, content: InputStream, eTag: String?): StorageWriteBackend.UploadResult {
val file = root.resolve(name)
logger.trace("Uploading file path " + file)
try {
if (file.exists() && eTag != null && hasher.getHash(file) != eTag) {
throw ModifiedException("file has changed")
}
root.resolve("blocks").mkdirs()
FileOutputStream(file).use { output ->
output.write(IOUtils.toByteArray(content))
return StorageWriteBackend.UploadResult(Date(), hasher.getHash(file))
}
} catch (e: IOException) {
throw QblStorageException(e.message, e)
}

}

companion object {

private val logger = LoggerFactory.getLogger(LocalReadBackend::class.java)
private val hasher = Md5Hasher()
}
}
Loading