Skip to content

Commit

Permalink
Add support for digest authentication
Browse files Browse the repository at this point in the history
Co-authored-by: fa1seu <[email protected]>
  • Loading branch information
alexbakker and fa1seut0pia committed Oct 19, 2024
1 parent 37f4bd7 commit 08f7b05
Show file tree
Hide file tree
Showing 19 changed files with 408 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.iml
.gradle
.kotlin/
/local.properties
/.idea
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.11.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.11.0'
implementation 'com.github.thegrizzlylabs:sardine-android:0.9'
implementation 'io.github.rburgst:okhttp-digest:3.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'
kapt "androidx.room:room-compiler:$roomVersion"
Expand Down
176 changes: 176 additions & 0 deletions app/schemas/dev.rocli.android.webdav.data.AppDatabase/5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
{
"formatVersion": 1,
"database": {
"version": 5,
"identityHash": "c98cd93c63f8ee003926006b68582ecf",
"entities": [
{
"tableName": "account",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `url` TEXT, `protocol` TEXT NOT NULL DEFAULT 'AUTO', `verify_certs` INTEGER NOT NULL, `auth_type` TEXT NOT NULL DEFAULT 'NONE', `username` TEXT, `password` TEXT, `client_cert` TEXT, `max_cache_file_size` INTEGER NOT NULL, `act_as_local_storage` INTEGER NOT NULL DEFAULT false)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "protocol",
"columnName": "protocol",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'AUTO'"
},
{
"fieldPath": "verifyCerts",
"columnName": "verify_certs",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "authType",
"columnName": "auth_type",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'NONE'"
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "clientCert",
"columnName": "client_cert",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "maxCacheFileSize",
"columnName": "max_cache_file_size",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "actAsLocalStorage",
"columnName": "act_as_local_storage",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "cache_entry",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account_id` INTEGER NOT NULL, `status` TEXT NOT NULL, `path` TEXT NOT NULL, `etag` TEXT, `content_length` INTEGER, `last_modified` INTEGER, FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "account_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "etag",
"columnName": "etag",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentLength",
"columnName": "content_length",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastModified",
"columnName": "last_modified",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_cache_entry_account_id_path",
"unique": true,
"columnNames": [
"account_id",
"path"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_cache_entry_account_id_path` ON `${TABLE_NAME}` (`account_id`, `path`)"
}
],
"foreignKeys": [
{
"table": "account",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"account_id"
],
"referencedColumns": [
"id"
]
}
]
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c98cd93c63f8ee003926006b68582ecf')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,18 @@ class DocumentsProviderTest(private val testName: String, private val account: A
arrayOf("hacdias", Account(
name = "Hacdias",
url = "http://${HOST}:8001",
authType = Account.AuthType.BASIC,
username = SecretString("test"),
password = SecretString("test")
)
),
)),
arrayOf("nginx", Account(
name = "Nginx",
url = "http://${HOST}:8002"
)),
arrayOf("nextcloud", Account(
name = "Nextcloud",
url = "http://${HOST}:8003/remote.php/dav/files/test",
authType = Account.AuthType.BASIC,
username = SecretString("test"),
password = SecretString("ilovepasswordstrengthchecks")
)),
Expand All @@ -79,6 +80,13 @@ class DocumentsProviderTest(private val testName: String, private val account: A
name = "Apache (subpath) proxied through Nginx",
url = "http://${HOST}:8005/webdav"
)),
arrayOf("apache-digest", Account(
name = "Apache using digest auth",
url = "http://${HOST}:8006",
authType = Account.AuthType.DIGEST,
username = SecretString("test"),
password = SecretString("test")
)),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class ScreenshotTest {
Account(
name = "Nextcloud",
url = "http://${host}:8003/remote.php/dav/files/admin",
authType = Account.AuthType.BASIC,
username = SecretString("admin"),
password = SecretString("admin")
),
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/dev/rocli/android/webdav/data/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ data class Account(
@ColumnInfo(name = "verify_certs")
var verifyCerts: Boolean = true,

@ColumnInfo(name = "auth_type", defaultValue = "NONE")
var authType: AuthType = AuthType.NONE,

@ColumnInfo(name = "username")
var username: SecretString? = null,

Expand Down Expand Up @@ -73,6 +76,12 @@ data class Account(
enum class Protocol {
AUTO, HTTP1
}

enum class AuthType {
NONE,
BASIC,
DIGEST
}
}

fun List<Account>.byId(id: Long): Account {
Expand Down
13 changes: 11 additions & 2 deletions app/src/main/java/dev/rocli/android/webdav/data/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@ import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.AutoMigrationSpec
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(
version = 4,
version = 5,
exportSchema = true,
entities = [Account::class, CacheEntry::class],
autoMigrations = [
AutoMigration(from = 1, to = 2),
AutoMigration(from = 2, to = 3),
AutoMigration(from = 3, to = 4)
AutoMigration(from = 3, to = 4),
AutoMigration(from = 4, to = 5, spec = AppDatabase.AuthTypeMigration::class)
]
)
@TypeConverters(SecretStringConverter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun accountDao(): AccountDao
abstract fun cacheDao(): CacheDao

class AuthTypeMigration : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
db.execSQL("UPDATE account SET auth_type = 'BASIC' WHERE username IS NOT NULL OR password IS NOT NULL")
}
}
}
Loading

0 comments on commit 08f7b05

Please sign in to comment.