Skip to content
Draft
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
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ android {

defaultConfig {
applicationId "com.hegocre.nextcloudpasswords"
minSdk 24
minSdk 26
targetSdk 36
versionCode 38
versionName "1.0.12"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.hegocre.nextcloudpasswords
import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import com.hegocre.nextcloudpasswords.api.ApiController
import com.hegocre.nextcloudpasswords.data.user.UserController
import com.hegocre.nextcloudpasswords.utils.OkHttpRequest
import com.hegocre.nextcloudpasswords.utils.PreferencesManager
import org.junit.Assert
Expand All @@ -16,10 +17,8 @@ class ApiControllerTest {
@Before
fun setup() {
context = InstrumentationRegistry.getInstrumentation().targetContext
with(PreferencesManager.getInstance(context)) {
setLoggedInServer("")
setLoggedInUser("")
setLoggedInPassword("")
with(UserController.getInstance(context)) {
logIn("","","")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import com.hegocre.nextcloudpasswords.api.encryption.CSEv1Keychain
import com.hegocre.nextcloudpasswords.utils.LazySodiumUtils
import com.hegocre.nextcloudpasswords.utils.decryptValue
import com.hegocre.nextcloudpasswords.utils.encryptValue
import org.junit.Assert
import org.junit.Assert.assertTrue
import org.junit.Assert.assertEquals
import org.junit.Ignore
import org.junit.Test
import java.util.Locale

class SodiumTest {

@Ignore("passwordHash returns something. Needs to be checked.")
@Test
fun testSodiumSolve() {
val salts = Array(3) { "" }
Expand Down Expand Up @@ -56,7 +57,7 @@ class SodiumTest {
)

val secret = sodium.sodiumBin2Hex(passwordHash)
assertTrue(secret.lowercase(Locale.getDefault()) == "")
assertEquals("", secret.lowercase(Locale.getDefault()))
}

@Test
Expand All @@ -72,6 +73,6 @@ class SodiumTest {
val encryptedString = testString.encryptValue("test_key", csEv1Keychain)
val decryptedString = encryptedString.decryptValue("test_key", csEv1Keychain)

Assert.assertEquals(testString, decryptedString)
assertEquals(testString, decryptedString)
}
}
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ui.activities.AccountsActivity"
android:exported="false">
<intent-filter>
<action android:name="com.hegocre.nextcloudpasswords.action.accounts" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ui.activities.AboutActivity"
android:exported="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,15 @@ import kotlinx.coroutines.withContext
*
* @param context Context of the application.
*/
class ApiController private constructor(context: Context) {
private val server = UserController.getInstance(context).getServer()
class ApiController private constructor(private final val context: Context) {

private val preferencesManager = PreferencesManager.getInstance(context)

private val passwordsApi = PasswordsApi.getInstance(server)
private val foldersApi = FoldersApi.getInstance(server)
private val sessionApi = SessionApi.getInstance(server)
private val serviceApi = ServiceApi.getInstance(server)
private val settingsApi = SettingsApi.getInstance(server)
private val passwordsApi = PasswordsApi.getInstance(context)
private val foldersApi = FoldersApi.getInstance(context)
private val sessionApi = SessionApi.getInstance(context)
private val serviceApi = ServiceApi.getInstance(context)
private val settingsApi = SettingsApi.getInstance(context)

private var sessionCode: String? = null

Expand Down Expand Up @@ -146,12 +145,12 @@ class ApiController private constructor(context: Context) {
when (requestResult.code) {
Error.API_TIMEOUT -> Log.e(
"API Controller",
"Timeout requesting session, user ${server.username}"
"Timeout requesting session, user ${getServer().username}"
)

Error.API_BAD_RESPONSE -> Log.e(
"API Controller",
"Bad response on session request, user ${server.username}"
"Bad response on session request, user ${getServer().username}"
)
}
}
Expand Down Expand Up @@ -182,12 +181,12 @@ class ApiController private constructor(context: Context) {
when (openedSessionRequest.code) {
Error.API_TIMEOUT -> Log.e(
"API Controller",
"Timeout opening session, user ${server.username}"
"Timeout opening session, user ${getServer().username}"
)

Error.API_BAD_RESPONSE -> Log.e(
"API Controller",
"Bad response on session open, user ${server.username}"
"Bad response on session open, user ${getServer().username}"
)
}
}
Expand Down Expand Up @@ -350,11 +349,16 @@ class ApiController private constructor(context: Context) {
return result is Result.Success
}

fun getServer() = UserController.getInstance(context).getServer()

fun getFaviconServiceRequest(url: String): Pair<String, Server> =
Pair(serviceApi.getFaviconUrl(url), server)
Pair(serviceApi.getFaviconUrl(url), getServer())

fun getAvatarServiceRequest(): Pair<String, Server> =
Pair(serviceApi.getAvatarUrl(), server)
Pair(serviceApi.getAvatarUrl(), getServer())

fun getAvatarServiceUrl(server: Server) = serviceApi.getAvatarUrl(server)


companion object {
private var instance: ApiController? = null
Expand Down
39 changes: 22 additions & 17 deletions app/src/main/java/com/hegocre/nextcloudpasswords/api/FoldersApi.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.hegocre.nextcloudpasswords.api

import android.content.Context
import com.hegocre.nextcloudpasswords.BuildConfig
import com.hegocre.nextcloudpasswords.data.folder.DeletedFolder
import com.hegocre.nextcloudpasswords.data.folder.Folder
import com.hegocre.nextcloudpasswords.data.folder.NewFolder
import com.hegocre.nextcloudpasswords.data.folder.UpdatedFolder
import com.hegocre.nextcloudpasswords.data.user.UserController
import com.hegocre.nextcloudpasswords.utils.Error
import com.hegocre.nextcloudpasswords.utils.OkHttpRequest
import com.hegocre.nextcloudpasswords.utils.Result
Expand All @@ -13,15 +15,16 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.net.SocketTimeoutException
import javax.net.ssl.SSLHandshakeException
import kotlin.context

/**
* Class with methods used to interact with the
* [Folder API](https://git.mdns.eu/nextcloud/passwords/-/wikis/Developers/Api/Folder-Api).
* This is a Singleton class and will have only one instance.
*
* @property server The [Server] where the requests will be made.
* @property context The [Context] where the requests will be made.
*/
class FoldersApi private constructor(private var server: Server) {
class FoldersApi private constructor(private var context: Context) {

/**
* Sends a request to the api to list all the user passwords. If the user uses CSE, a
Expand All @@ -36,10 +39,10 @@ class FoldersApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().get(
sUrl = server.url + LIST_URL,
sUrl = getServer().url + LIST_URL,
sessionCode = sessionCode,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -88,12 +91,12 @@ class FoldersApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().post(
sUrl = server.url + CREATE_URL,
sUrl = getServer().url + CREATE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(newFolder),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -140,12 +143,12 @@ class FoldersApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().patch(
sUrl = server.url + UPDATE_URL,
sUrl = getServer().url + UPDATE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(updatedFolder),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -191,12 +194,12 @@ class FoldersApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().delete(
sUrl = server.url + DELETE_URL,
sUrl = getServer().url + DELETE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(deletedFolder),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -228,6 +231,8 @@ class FoldersApi private constructor(private var server: Server) {
}
}

fun getServer() = UserController.getInstance(context).getServer()

companion object {
private const val LIST_URL = "/index.php/apps/passwords/api/1.0/folder/list"
private const val CREATE_URL = "/index.php/apps/passwords/api/1.0/folder/create"
Expand All @@ -240,15 +245,15 @@ class FoldersApi private constructor(private var server: Server) {
/**
* Get the instance of the [FoldersApi], and create it if null.
*
* @param server The [Server] where the requests will be made.
* @param context The [Context] where the requests will be made.
* @return The instance of the api.
*/
fun getInstance(server: Server): FoldersApi {
fun getInstance(context: Context): FoldersApi {
synchronized(this) {
var tempInstance = instance

if (tempInstance == null) {
tempInstance = FoldersApi(server)
tempInstance = FoldersApi(context)
instance = tempInstance
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.hegocre.nextcloudpasswords.api

import android.content.Context
import com.hegocre.nextcloudpasswords.BuildConfig
import com.hegocre.nextcloudpasswords.data.password.DeletedPassword
import com.hegocre.nextcloudpasswords.data.password.NewPassword
import com.hegocre.nextcloudpasswords.data.password.Password
import com.hegocre.nextcloudpasswords.data.password.UpdatedPassword
import com.hegocre.nextcloudpasswords.data.user.UserController
import com.hegocre.nextcloudpasswords.utils.Error
import com.hegocre.nextcloudpasswords.utils.OkHttpRequest
import com.hegocre.nextcloudpasswords.utils.Result
Expand All @@ -19,9 +21,9 @@ import javax.net.ssl.SSLHandshakeException
* [Password API](https://git.mdns.eu/nextcloud/passwords/-/wikis/Developers/Api/Password-Api).
* This is a Singleton class and will have only one instance.
*
* @param server The [Server] where the requests will be made.
* @param context The [Context] where the requests will be made.
*/
class PasswordsApi private constructor(private var server: Server) {
class PasswordsApi private constructor(private var context: Context) {

/**
* Sends a request to the api to list all the user passwords. If the user uses CSE, a
Expand All @@ -36,10 +38,10 @@ class PasswordsApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().get(
sUrl = server.url + LIST_URL,
sUrl = getServer().url + LIST_URL,
sessionCode = sessionCode,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -89,12 +91,12 @@ class PasswordsApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().post(
sUrl = server.url + CREATE_URL,
sUrl = getServer().url + CREATE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(newPassword),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -141,12 +143,12 @@ class PasswordsApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().patch(
sUrl = server.url + UPDATE_URL,
sUrl = getServer().url + UPDATE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(updatedPassword),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -192,12 +194,12 @@ class PasswordsApi private constructor(private var server: Server) {
return try {
val apiResponse = withContext(Dispatchers.IO) {
OkHttpRequest.getInstance().delete(
sUrl = server.url + DELETE_URL,
sUrl = getServer().url + DELETE_URL,
sessionCode = sessionCode,
body = Json.encodeToString(deletedPassword),
mediaType = OkHttpRequest.JSON,
username = server.username,
password = server.password
username = getServer().username,
password = getServer().password
)
}

Expand Down Expand Up @@ -229,6 +231,8 @@ class PasswordsApi private constructor(private var server: Server) {
}
}

fun getServer() = UserController.getInstance(context).getServer()

companion object {
private const val LIST_URL = "/index.php/apps/passwords/api/1.0/password/list"
private const val CREATE_URL = "/index.php/apps/passwords/api/1.0/password/create"
Expand All @@ -240,15 +244,15 @@ class PasswordsApi private constructor(private var server: Server) {
/**
* Get the instance of the [PasswordsApi], and create it if null.
*
* @param server The [Server] where the requests will be made.
* @param context The [Context] where the requests will be made.
* @return The instance of the api.
*/
fun getInstance(server: Server): PasswordsApi {
fun getInstance(context: Context): PasswordsApi {
synchronized(this) {
var tempInstance = instance

if (tempInstance == null) {
tempInstance = PasswordsApi(server)
tempInstance = PasswordsApi(context)
instance = tempInstance
}

Expand Down
Loading