Skip to content
Open
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this test case would work as expected.

As far as I understand, GenerateOneTimeAppPasswordRemoteOperation should only return an app password when authenticated using a one time password. However, nextcloudClient doesn't use a one time password, but a regular authenticated login instead. This means that any call to GenerateOneTimeAppPasswordRemoteOperation will fail and subsequently cause this test case to also fail.

On my machine the remote operation always returns a 403 Forbidden.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2020-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2020 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/
package com.nextcloud.android.lib.resources.users

import android.text.TextUtils
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.resources.status.NextcloudVersion
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import org.junit.Test

class GenerateOneTimeAppPasswordRemoteOperationIT : AbstractIT() {
@Test
fun generateAppPassword() {
// only on NC34+
testOnlyOnServer(NextcloudVersion.nextcloud_34)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment in GenerateOneTimeAppPasswordRemoteOperation.kt says that this feature is available from Nextcloud 33.


val sut = GenerateOneTimeAppPasswordRemoteOperation()
val result = sut.execute(nextcloudClient)

assertTrue(result.isSuccess)

val appPassword = result.getResultData()
assertFalse(TextUtils.isEmpty(appPassword))

// re-using onetime password should fail
assertFalse(GenerateOneTimeAppPasswordRemoteOperation().execute(nextcloudClient).isSuccess)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky
* SPDX-License-Identifier: MIT
*/
package com.nextcloud.android.lib.resources.users

import com.nextcloud.common.NextcloudClient
import com.nextcloud.operations.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.OCSRemoteOperation
import okio.IOException
import org.apache.commons.httpclient.HttpStatus
import org.json.JSONObject

/**
* Generate an app password via username / login and **onetime** password. Available since Nextcloud 33
*/
class GenerateOneTimeAppPasswordRemoteOperation : OCSRemoteOperation<String?>() {
override fun run(client: NextcloudClient): RemoteOperationResult<String?> {
var result: RemoteOperationResult<String?>
var getMethod: GetMethod? = null

try {
getMethod = GetMethod(client.baseUri.toString() + ENDPOINT + JSON_FORMAT, true)

// remote request
val status: Int = client.execute(getMethod)

if (status == HttpStatus.SC_OK) {
val response = getMethod.getResponseBodyAsString()

val respJSON = JSONObject(response)
val password =
respJSON.getJSONObject(NODE_OCS).getJSONObject(NODE_DATA).getString(
NODE_APPPASSWORD
)

result = RemoteOperationResult(true, getMethod)
result.resultData = password
} else {
result = RemoteOperationResult(false, getMethod)
}
} catch (e: IOException) {
result = RemoteOperationResult(e)
Log_OC.e(
TAG,
"Generate app password failed: " + result.getLogMessage(),
result.exception
)
} catch (e: org.json.JSONException) {
result = RemoteOperationResult(e)
Log_OC.e(
TAG,
"Generate app password failed: " + result.getLogMessage(),
result.exception
)
} finally {
getMethod?.releaseConnection()
}
return result
}

companion object {
private val TAG: String = GenerateOneTimeAppPasswordRemoteOperation::class.java.getSimpleName()
private const val ENDPOINT = "/ocs/v2.php/core/getapppassword-onetime"

// JSON node names
private const val NODE_OCS = "ocs"
private const val NODE_DATA = "data"
private const val NODE_APPPASSWORD = "apppassword"
}
}
Loading