Skip to content
Snippets Groups Projects
Verified Commit 8743ef54 authored by Torsten Grote's avatar Torsten Grote
Browse files

API endpoint for wiping the mailbox

parent 2335fae7
No related branches found
No related tags found
1 merge request!33API endpoint for wiping the mailbox
Pipeline #7914 passed
...@@ -7,7 +7,6 @@ import io.ktor.auth.authenticate ...@@ -7,7 +7,6 @@ import io.ktor.auth.authenticate
import io.ktor.features.BadRequestException import io.ktor.features.BadRequestException
import io.ktor.features.MissingRequestParameterException import io.ktor.features.MissingRequestParameterException
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.HttpStatusCode.Companion.BadRequest import io.ktor.http.HttpStatusCode.Companion.BadRequest
import io.ktor.http.HttpStatusCode.Companion.Unauthorized import io.ktor.http.HttpStatusCode.Companion.Unauthorized
import io.ktor.response.respond import io.ktor.response.respond
...@@ -22,18 +21,24 @@ import io.ktor.util.getOrFail ...@@ -22,18 +21,24 @@ import io.ktor.util.getOrFail
import org.briarproject.mailbox.core.contacts.ContactsManager import org.briarproject.mailbox.core.contacts.ContactsManager
import org.briarproject.mailbox.core.files.FileManager import org.briarproject.mailbox.core.files.FileManager
import org.briarproject.mailbox.core.setup.SetupManager import org.briarproject.mailbox.core.setup.SetupManager
import org.briarproject.mailbox.core.setup.WipeManager
import org.briarproject.mailbox.core.system.InvalidIdException import org.briarproject.mailbox.core.system.InvalidIdException
internal const val V = "/" // TODO set to "/v1" for release internal const val V = "/" // TODO set to "/v1" for release
internal fun Application.configureBasicApi(setupManager: SetupManager) = routing { internal fun Application.configureBasicApi(
setupManager: SetupManager,
wipeManager: WipeManager,
) = routing {
route(V) { route(V) {
get { get {
call.respondText("Hello world!", ContentType.Text.Plain) call.respondText("Hello world!", ContentType.Text.Plain)
} }
authenticate { authenticate {
delete { delete {
call.respond(HttpStatusCode.OK, "delete: Not yet implemented") call.handle {
wipeManager.onWipeRequest(call)
}
} }
put("/setup") { put("/setup") {
call.handle { call.handle {
......
...@@ -12,6 +12,7 @@ import org.briarproject.mailbox.core.files.FileManager ...@@ -12,6 +12,7 @@ import org.briarproject.mailbox.core.files.FileManager
import org.briarproject.mailbox.core.lifecycle.Service import org.briarproject.mailbox.core.lifecycle.Service
import org.briarproject.mailbox.core.server.WebServerManager.Companion.PORT import org.briarproject.mailbox.core.server.WebServerManager.Companion.PORT
import org.briarproject.mailbox.core.setup.SetupManager import org.briarproject.mailbox.core.setup.SetupManager
import org.briarproject.mailbox.core.setup.WipeManager
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory.getLogger import org.slf4j.LoggerFactory.getLogger
import javax.inject.Inject import javax.inject.Inject
...@@ -29,6 +30,7 @@ internal class WebServerManagerImpl @Inject constructor( ...@@ -29,6 +30,7 @@ internal class WebServerManagerImpl @Inject constructor(
private val setupManager: SetupManager, private val setupManager: SetupManager,
private val contactsManager: ContactsManager, private val contactsManager: ContactsManager,
private val fileManager: FileManager, private val fileManager: FileManager,
private val wipeManager: WipeManager,
) : WebServerManager { ) : WebServerManager {
internal companion object { internal companion object {
...@@ -50,7 +52,7 @@ internal class WebServerManagerImpl @Inject constructor( ...@@ -50,7 +52,7 @@ internal class WebServerManagerImpl @Inject constructor(
install(ContentNegotiation) { install(ContentNegotiation) {
jackson() jackson()
} }
configureBasicApi(setupManager) configureBasicApi(setupManager, wipeManager)
configureContactApi(contactsManager) configureContactApi(contactsManager)
configureFilesApi(fileManager) configureFilesApi(fileManager)
} }
......
package org.briarproject.mailbox.core.setup
import io.ktor.application.ApplicationCall
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.files.FileManager
import org.briarproject.mailbox.core.server.AuthException
import org.briarproject.mailbox.core.server.MailboxPrincipal
import javax.inject.Inject
class WipeManager @Inject constructor(
private val db: Database,
private val fileManager: FileManager,
) {
/**
* Handler for `DELETE /` API endpoint.
*
* Wipes entire database as well as stored files
* and returns `204 No Content` response if successful
*/
@Throws(AuthException::class)
suspend fun onWipeRequest(call: ApplicationCall) {
val principal = call.principal<MailboxPrincipal>()
if (principal !is MailboxPrincipal.OwnerPrincipal) throw AuthException()
db.transaction(false) { txn ->
db.clearDatabase(txn)
}
fileManager.deleteAllFiles()
call.respond(HttpStatusCode.NoContent)
}
}
...@@ -3,6 +3,7 @@ package org.briarproject.mailbox.core ...@@ -3,6 +3,7 @@ package org.briarproject.mailbox.core
import dagger.Component import dagger.Component
import org.briarproject.mailbox.core.db.Database import org.briarproject.mailbox.core.db.Database
import org.briarproject.mailbox.core.files.FileManager import org.briarproject.mailbox.core.files.FileManager
import org.briarproject.mailbox.core.files.FileProvider
import org.briarproject.mailbox.core.lifecycle.LifecycleManager import org.briarproject.mailbox.core.lifecycle.LifecycleManager
import org.briarproject.mailbox.core.settings.SettingsManager import org.briarproject.mailbox.core.settings.SettingsManager
import org.briarproject.mailbox.core.setup.SetupManager import org.briarproject.mailbox.core.setup.SetupManager
...@@ -23,4 +24,5 @@ interface TestComponent { ...@@ -23,4 +24,5 @@ interface TestComponent {
fun getFileManager(): FileManager fun getFileManager(): FileManager
fun getDatabase(): Database fun getDatabase(): Database
fun getRandomIdManager(): RandomIdManager fun getRandomIdManager(): RandomIdManager
fun getFileProvider(): FileProvider
} }
package org.briarproject.mailbox.core.setup
import io.ktor.client.request.delete
import io.ktor.client.request.post
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.runBlocking
import org.briarproject.mailbox.core.server.IntegrationTest
import org.junit.jupiter.api.Test
import kotlin.random.Random
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
class WipeManagerTest : IntegrationTest() {
private val db by lazy { testComponent.getDatabase() }
@Test
fun `wipe request rejects non-owners`() = runBlocking {
addOwnerToken()
addContact(contact1)
// Unauthorized with random token
val response1 = httpClient.delete<HttpResponse>("$baseUrl/") {
authenticateWithToken(token)
}
assertEquals(HttpStatusCode.Unauthorized, response1.status)
// Unauthorized with contact's token
val response2 = httpClient.delete<HttpResponse>("$baseUrl/") {
authenticateWithToken(contact1.token)
}
assertEquals(HttpStatusCode.Unauthorized, response2.status)
}
@Test
fun `wipe request deletes files and db for owner`() = runBlocking {
addOwnerToken()
addContact(contact1)
addContact(contact2)
// owner uploads a file
val uploadResponse: HttpResponse = httpClient.post("$baseUrl/files/${contact1.inboxId}") {
authenticateWithToken(ownerToken)
body = Random.nextBytes(42)
}
assertEquals(HttpStatusCode.OK, uploadResponse.status)
// owner wipes mailbox
val response = httpClient.delete<HttpResponse>("$baseUrl/") {
authenticateWithToken(ownerToken)
}
assertEquals(HttpStatusCode.NoContent, response.status)
// no more contacts in DB
val contacts = db.transactionWithResult(true) { db.getContacts(it) }
assertEquals(0, contacts.size)
// owner token was cleared as well
val token = db.transactionWithResult(true) { txn ->
testComponent.getSetupManager().getOwnerToken(txn)
}
assertNull(token)
// no more files are stored
val folderRoot = testComponent.getFileProvider().folderRoot
assertTrue(folderRoot.listFiles()?.isEmpty() ?: false)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment