diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt index e582dbc9cdc9773be40da4b5758992abb3071ba3..1c8453b8516351a225252ef6f31941bc5acb41ad 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt @@ -5,8 +5,8 @@ import io.ktor.auth.principal import io.ktor.http.HttpStatusCode import io.ktor.response.respond import org.briarproject.mailbox.core.db.Database +import org.briarproject.mailbox.core.server.AuthException import org.briarproject.mailbox.core.server.AuthManager -import org.briarproject.mailbox.core.server.AuthenticationException import org.briarproject.mailbox.core.server.MailboxPrincipal import org.briarproject.mailbox.core.system.InvalidIdException import org.briarproject.mailbox.core.system.RandomIdManager @@ -21,12 +21,12 @@ class FileManager @Inject constructor( /** * Used by contacts to send files to the owner and by the owner to send files to contacts. * - * Checks if provided auth token is allowed to upload to given [folderId], + * Checks if the authenticated [MailboxPrincipal] is allowed to upload to given [folderId], * Responds with 200 (OK) if upload was successful * (no 201 as the uploader doesn't need to know the $fileId) * The mailbox chooses a random ID string for the file ID. */ - @Throws(AuthenticationException::class, InvalidIdException::class) + @Throws(AuthException::class, InvalidIdException::class) suspend fun postFile(call: ApplicationCall, folderId: String) { val principal: MailboxPrincipal? = call.principal() randomIdManager.assertIsRandomId(folderId) @@ -40,7 +40,7 @@ class FileManager @Inject constructor( /** * Used by owner and contacts to list their files to retrieve. * - * Checks if provided auth token is allowed to download from [folderId]. + * Checks if the authenticated [MailboxPrincipal] is allowed to download from [folderId]. * Responds with 200 (OK) with the list of files in JSON. */ suspend fun listFiles(call: ApplicationCall, folderId: String) { @@ -56,10 +56,10 @@ class FileManager @Inject constructor( /** * Used by owner and contacts to retrieve a file. * - * Checks if provided auth token is allowed to download from $folderId + * Checks if the authenticated [MailboxPrincipal] is allowed to download from $folderId * Returns 200 (OK) if successful with the files' bytes in the response body */ - @Throws(AuthenticationException::class, InvalidIdException::class) + @Throws(AuthException::class, InvalidIdException::class) suspend fun getFile(call: ApplicationCall, folderId: String, fileId: String) { val principal: MailboxPrincipal? = call.principal() randomIdManager.assertIsRandomId(folderId) @@ -77,7 +77,7 @@ class FileManager @Inject constructor( /** * Used by owner and contacts to delete files. * - * Checks if provided auth token is allowed to download from [folderId]. + * Checks if the authenticated [MailboxPrincipal] is allowed to download from [folderId]. * Responds with 200 (OK) if deletion was successful. */ suspend fun deleteFile(call: ApplicationCall, folderId: String, fileId: String) { diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt index 9b9127f70acd87b87d02e4e85f6ec1eb7c58690e..6d4f5a8a1f533c359862249344b757dfe51018c9 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt @@ -3,6 +3,8 @@ package org.briarproject.mailbox.core.server import io.ktor.auth.Principal import org.briarproject.mailbox.core.api.Contact import org.briarproject.mailbox.core.db.Database +import org.briarproject.mailbox.core.server.MailboxPrincipal.ContactPrincipal +import org.briarproject.mailbox.core.server.MailboxPrincipal.OwnerPrincipal import org.briarproject.mailbox.core.settings.SettingsManager import org.briarproject.mailbox.core.system.RandomIdManager import javax.inject.Inject @@ -28,62 +30,62 @@ class AuthManager @Inject constructor( return db.transactionWithResult(true) { txn -> val contact = db.getContactWithToken(txn, token) if (contact != null) { - MailboxPrincipal.ContactPrincipal(contact) + ContactPrincipal(contact) } else { val settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER) - if (token == settings[SETTINGS_OWNER_TOKEN]) MailboxPrincipal.Owner + if (token == settings[SETTINGS_OWNER_TOKEN]) OwnerPrincipal else null } } } /** - * @throws [AuthenticationException] when given [principal] is NOT allowed + * @throws [AuthException] when given [principal] is NOT allowed * to download or delete from the given [folderId] which is assumed to be validated already. */ - @Throws(AuthenticationException::class) + @Throws(AuthException::class) fun assertCanDownloadFromFolder(principal: MailboxPrincipal?, folderId: String) { - if (principal == null) throw AuthenticationException() + if (principal == null) throw AuthException() - if (principal is MailboxPrincipal.Owner) { + if (principal is OwnerPrincipal) { val contacts = db.transactionWithResult(true) { txn -> db.getContacts(txn) } val noOutboxFound = contacts.none { c -> folderId == c.outboxId } - if (noOutboxFound) throw AuthenticationException() - } else if (principal is MailboxPrincipal.ContactPrincipal) { - if (folderId != principal.contact.inboxId) throw AuthenticationException() + if (noOutboxFound) throw AuthException() + } else if (principal is ContactPrincipal) { + if (folderId != principal.contact.inboxId) throw AuthException() } } /** - * @throws [AuthenticationException] when given [principal] is NOT allowed + * @throws [AuthException] when given [principal] is NOT allowed * to post to the given [folderId] which is assumed to be validated already. */ - @Throws(AuthenticationException::class) + @Throws(AuthException::class) fun assertCanPostToFolder(principal: MailboxPrincipal?, folderId: String) { - if (principal == null) throw AuthenticationException() + if (principal == null) throw AuthException() - if (principal is MailboxPrincipal.Owner) { + if (principal is OwnerPrincipal) { val contacts = db.transactionWithResult(true) { txn -> db.getContacts(txn) } val noInboxFound = contacts.none { c -> folderId == c.inboxId } - if (noInboxFound) throw AuthenticationException() - } else if (principal is MailboxPrincipal.ContactPrincipal) { - if (folderId != principal.contact.outboxId) throw AuthenticationException() + if (noInboxFound) throw AuthException() + } else if (principal is ContactPrincipal) { + if (folderId != principal.contact.outboxId) throw AuthException() } } /** - * @throws [AuthenticationException] when given [principal] is NOT the mailbox owner. + * @throws [AuthException] when given [principal] is NOT the mailbox owner. */ - @Throws(AuthenticationException::class) + @Throws(AuthException::class) fun assertIsOwner(principal: MailboxPrincipal?) { - if (principal !is MailboxPrincipal.Owner) throw AuthenticationException() + if (principal !is OwnerPrincipal) throw AuthException() } } sealed class MailboxPrincipal : Principal { - object Owner : MailboxPrincipal() + object OwnerPrincipal : MailboxPrincipal() class ContactPrincipal(val contact: Contact) : MailboxPrincipal() } -class AuthenticationException : IllegalStateException() +class AuthException : IllegalStateException() diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/Routing.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/Routing.kt index d01769460bbcbfb58ecb417927382806b37880fc..526ff542f8d8d094d5b264ccdcc9659b175efa0c 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/Routing.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/Routing.kt @@ -104,7 +104,7 @@ internal fun Application.configureFilesApi(fileManager: FileManager) = routing { private suspend fun ApplicationCall.handle(block: suspend () -> Unit) { try { block() - } catch (e: AuthenticationException) { + } catch (e: AuthException) { respond(HttpStatusCode.Unauthorized, HttpStatusCode.Unauthorized.description) } catch (e: InvalidIdException) { respond(HttpStatusCode.BadRequest, "Malformed ID: ${e.id}") diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/RandomIdManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/RandomIdManager.kt index 4e8c89cd2672d8e238ff441bb9fb01d69f735f95..e7379b9903d5ebece7825fad8523a8770e57aec3 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/RandomIdManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/RandomIdManager.kt @@ -6,6 +6,10 @@ import javax.inject.Inject private const val ID_SIZE = 32 private const val ID_HEX_SIZE = ID_SIZE * 2 +/** + * Generates and validates random IDs + * that are being used for auth tokens, folder IDs and file names. + */ class RandomIdManager @Inject constructor() { private val secureRandom = SecureRandom()