Skip to content
Snippets Groups Projects
Verified Commit ef20cd29 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Make the lib more reusable, prepare for desktop UI

parent e54426c8
Branches
Tags
No related merge requests found
Showing
with 268 additions and 48 deletions
......@@ -22,6 +22,7 @@ package de.kuschku.quasseldroid.ssl
import de.kuschku.libquassel.connection.HostnameVerifier
import de.kuschku.libquassel.connection.QuasselSecurityException
import de.kuschku.libquassel.connection.SocketAddress
import de.kuschku.libquassel.ssl.BrowserCompatibleHostnameVerifier
import de.kuschku.quasseldroid.ssl.custom.QuasselHostnameManager
import java.security.cert.X509Certificate
import javax.net.ssl.SSLException
......
......@@ -33,9 +33,9 @@ import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.quassel.QuasselFeatures
import de.kuschku.libquassel.ssl.X509Helper
import de.kuschku.libquassel.util.helpers.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ssl.X509Helper
import de.kuschku.quasseldroid.util.helper.*
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeature
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
plugins {
application
kotlin("jvm")
kotlin("kapt")
}
application {
mainClassName = "de.kuschku.cli.MainKt"
}
dependencies {
implementation(kotlin("stdlib", "1.3.11"))
implementation("io.reactivex.rxjava2", "rxjava", "2.1.9")
implementation("info.picocli", "picocli", "3.9.0")
implementation(project(":lib"))
testImplementation("junit", "junit", "4.12")
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.desktop
import picocli.CommandLine
class CliArguments {
@CommandLine.Option(names = ["--user"])
var user: String = ""
@CommandLine.Option(names = ["--pass"])
var pass: String = ""
@CommandLine.Option(names = ["--host"])
var host: String = ""
@CommandLine.Option(names = ["--port"])
var port: Int = 4242
override fun toString(): String {
return "CliArguments(user='$user', pass='$pass', host='$host', port='$port')"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CliArguments
if (user != other.user) return false
if (pass != other.pass) return false
if (host != other.host) return false
if (port != other.port) return false
return true
}
override fun hashCode(): Int {
var result = user.hashCode()
result = 31 * result + pass.hashCode()
result = 31 * result + host.hashCode()
result = 31 * result + port.hashCode()
return result
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.desktop
import picocli.CommandLine
fun main(vararg args: String) {
val cliArguments = CliArguments()
CommandLine(cliArguments).parse(*args)
}
......@@ -27,13 +27,17 @@ import de.kuschku.libquassel.protocol.primitive.serializer.IntSerializer
import de.kuschku.libquassel.protocol.primitive.serializer.ProtocolInfoSerializer
import de.kuschku.libquassel.protocol.primitive.serializer.VariantListSerializer
import de.kuschku.libquassel.quassel.ProtocolFeature
import de.kuschku.libquassel.quassel.QuasselFeatures
import de.kuschku.libquassel.session.ProtocolHandler
import de.kuschku.libquassel.ssl.BrowserCompatibleHostnameVerifier
import de.kuschku.libquassel.ssl.TrustManagers
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.compatibility.CompatibilityUtils
import de.kuschku.libquassel.util.compatibility.HandlerService
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN
import de.kuschku.libquassel.util.compatibility.reference.JavaHandlerService
import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.helpers.hexDump
import de.kuschku.libquassel.util.helpers.write
......@@ -49,12 +53,12 @@ import javax.net.ssl.SSLSession
import javax.net.ssl.X509TrustManager
class CoreConnection(
private val clientData: ClientData,
private val features: Features,
private val trustManager: X509TrustManager,
private val hostnameVerifier: HostnameVerifier,
private val address: SocketAddress,
private val handlerService: HandlerService
private val clientData: ClientData = ClientData.DEFAULT,
private val features: Features = Features(clientData.clientFeatures, QuasselFeatures.empty()),
private val handlerService: HandlerService = JavaHandlerService(),
private val trustManager: X509TrustManager = TrustManagers.default(),
private val hostnameVerifier: HostnameVerifier = BrowserCompatibleHostnameVerifier()
) : Thread(), Closeable {
companion object {
private const val TAG = "CoreConnection"
......
......@@ -28,4 +28,17 @@ data class ClientData(
val clientFeatures: QuasselFeatures,
val protocolFeatures: Protocol_Features,
val supportedProtocols: List<Protocol>
) {
companion object {
val DEFAULT = ClientData(
identifier = "libquassel-java",
buildDate = Instant.EPOCH,
clientFeatures = QuasselFeatures.all(),
protocolFeatures = Protocol_Features.of(
Protocol_Feature.Compression,
Protocol_Feature.TLS
),
supportedProtocols = listOf(Protocol.Datastream)
)
}
}
......@@ -28,7 +28,7 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
class BacklogManager(
var session: ISession,
private val backlogStorage: BacklogStorage
private val backlogStorage: BacklogStorage? = null
) : SyncableObject(session.proxy, "BacklogManager"), IBacklogManager {
private val loading = mutableMapOf<BufferId, (List<Message>) -> Boolean>()
private val loadingFiltered = mutableMapOf<BufferId, (List<Message>) -> Boolean>()
......@@ -42,7 +42,7 @@ class BacklogManager(
initialized = true
}
fun updateIgnoreRules() = backlogStorage.updateIgnoreRules(session)
fun updateIgnoreRules() = backlogStorage?.updateIgnoreRules(session)
fun requestBacklog(bufferId: BufferId, first: MsgId = -1, last: MsgId = -1, limit: Int = -1,
additional: Int = 0, callback: (List<Message>) -> Boolean) {
......@@ -79,7 +79,7 @@ class BacklogManager(
val list = messages.mapNotNull<QVariant_, Message>(QVariant_::value)
if (loading.remove(bufferId)?.invoke(list) != false) {
log(DEBUG, "BacklogManager", "storeMessages(${list.size})")
backlogStorage.storeMessages(session, list)
backlogStorage?.storeMessages(session, list)
}
}
......@@ -88,7 +88,7 @@ class BacklogManager(
val list = messages.mapNotNull<QVariant_, Message>(QVariant_::value)
if (loading.remove(-1)?.invoke(list) != false) {
log(DEBUG, "BacklogManager", "storeMessages(${list.size})")
backlogStorage.storeMessages(session, list)
backlogStorage?.storeMessages(session, list)
}
}
......@@ -98,7 +98,7 @@ class BacklogManager(
val list = messages.mapNotNull<QVariant_, Message>(QVariant_::value)
if (loadingFiltered.remove(bufferId)?.invoke(list) != false) {
log(DEBUG, "BacklogManager", "storeMessages(${list.size})")
backlogStorage.storeMessages(session, list)
backlogStorage?.storeMessages(session, list)
}
}
......@@ -107,11 +107,11 @@ class BacklogManager(
val list = messages.mapNotNull<QVariant_, Message>(QVariant_::value)
if (loadingFiltered.remove(-1)?.invoke(list) != false) {
log(DEBUG, "BacklogManager", "storeMessages(${list.size})")
backlogStorage.storeMessages(session, list)
backlogStorage?.storeMessages(session, list)
}
}
fun removeBuffer(buffer: BufferId) {
backlogStorage.clearMessages(buffer)
backlogStorage?.clearMessages(buffer)
}
}
......@@ -32,7 +32,7 @@ import io.reactivex.subjects.BehaviorSubject
class BufferSyncer constructor(
var session: ISession,
private val notificationManager: NotificationManager?
private val notificationManager: NotificationManager? = null
) : SyncableObject(session.proxy, "BufferSyncer"), IBufferSyncer {
override fun deinit() {
super.deinit()
......
......@@ -32,8 +32,8 @@ import java.nio.ByteBuffer
class RpcHandler(
override val session: Session,
private val backlogStorage: BacklogStorage,
private val notificationManager: NotificationManager?
private val backlogStorage: BacklogStorage? = null,
private val notificationManager: NotificationManager? = null
) : IRpcHandler {
override fun displayStatusMsg(net: String, msg: String) {
}
......@@ -61,7 +61,7 @@ class RpcHandler(
override fun displayMsg(message: Message) {
session.bufferSyncer.bufferInfoUpdated(message.bufferInfo)
backlogStorage.storeMessages(session, message)
backlogStorage?.storeMessages(session, message)
notificationManager?.processMessages(session, true, message)
}
......
......@@ -32,7 +32,7 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
import java.io.Closeable
abstract class ProtocolHandler(
private val exceptionHandler: (Throwable) -> Unit
private val exceptionHandler: ((Throwable) -> Unit)? = null
) : SignalProxy, AuthHandler, Closeable {
protected var closed = false
protected abstract val objectStorage: ObjectStorage
......@@ -61,7 +61,7 @@ abstract class ProtocolHandler(
} catch (e: ObjectNotFoundException) {
log(DEBUG, "ProtocolHandler", "An error has occured while processing $f", e)
} catch (e: Throwable) {
exceptionHandler.invoke(MessageHandlingException.SignalProxy(f, e))
exceptionHandler?.invoke(MessageHandlingException.SignalProxy(f, e))
}
return true
}
......@@ -76,7 +76,7 @@ abstract class ProtocolHandler(
} catch (e: ObjectNotFoundException) {
log(DEBUG, "ProtocolHandler", "An error has occured while processing $f", e)
} catch (e: Throwable) {
exceptionHandler.invoke(MessageHandlingException.Handshake(f, e))
exceptionHandler?.invoke(MessageHandlingException.Handshake(f, e))
}
return true
}
......@@ -103,7 +103,7 @@ abstract class ProtocolHandler(
try {
this.handle(it)
} catch (e: Throwable) {
exceptionHandler.invoke(e)
exceptionHandler?.invoke(e)
}
}
}
......
......@@ -26,9 +26,12 @@ import de.kuschku.libquassel.protocol.message.SignalProxyMessage
import de.kuschku.libquassel.quassel.ExtendedFeature
import de.kuschku.libquassel.quassel.QuasselFeatures
import de.kuschku.libquassel.quassel.syncables.*
import de.kuschku.libquassel.ssl.BrowserCompatibleHostnameVerifier
import de.kuschku.libquassel.ssl.TrustManagers
import de.kuschku.libquassel.util.compatibility.HandlerService
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
import de.kuschku.libquassel.util.compatibility.reference.JavaHandlerService
import de.kuschku.libquassel.util.rxjava.ReusableUnicastSubject
import io.reactivex.Observable
import io.reactivex.subjects.BehaviorSubject
......@@ -37,19 +40,19 @@ import org.threeten.bp.Instant
import javax.net.ssl.X509TrustManager
class Session(
clientData: ClientData,
trustManager: X509TrustManager,
hostnameVerifier: HostnameVerifier,
address: SocketAddress,
private val handlerService: HandlerService,
backlogStorage: BacklogStorage,
private val notificationManager: NotificationManager?,
private var userData: Pair<String, String>,
heartBeatFactory: () -> HeartBeatRunner,
val disconnectFromCore: (() -> Unit)?,
private val initCallback: ((Session) -> Unit)?,
exceptionHandler: (Throwable) -> Unit,
private val hasErroredCallback: (Error) -> Unit
trustManager: X509TrustManager = TrustManagers.default(),
hostnameVerifier: HostnameVerifier = BrowserCompatibleHostnameVerifier(),
clientData: ClientData = ClientData.DEFAULT,
private val handlerService: HandlerService = JavaHandlerService(),
heartBeatFactory: () -> HeartBeatRunner = ::JavaHeartBeatRunner,
val disconnectFromCore: (() -> Unit)? = null,
private val initCallback: ((Session) -> Unit)? = null,
exceptionHandler: ((Throwable) -> Unit)? = null,
private val hasErroredCallback: ((Error) -> Unit)? = null,
private val notificationManager: NotificationManager? = null,
backlogStorage: BacklogStorage? = null
) : ProtocolHandler(exceptionHandler), ISession {
override val objectStorage: ObjectStorage = ObjectStorage(this)
override val proxy: SignalProxy = this
......@@ -59,12 +62,12 @@ class Session(
get() = coreConnection.sslSession
private val coreConnection = CoreConnection(
address,
clientData,
features,
handlerService,
trustManager,
hostnameVerifier,
address,
handlerService
hostnameVerifier
)
override val state = coreConnection.state
......@@ -112,7 +115,7 @@ class Session(
}
private fun handleError(error: Error) {
hasErroredCallback.invoke(error)
hasErroredCallback?.invoke(error)
this.error.onNext(error)
}
......
......@@ -124,19 +124,19 @@ class SessionManager(
hasErrored = false
inProgressSession.onNext(
Session(
clientData,
address,
userData,
trustManager,
hostnameVerifier,
address,
clientData,
handlerService,
backlogStorage,
notificationManager,
userData,
heartBeatFactory,
disconnectFromCore,
initCallback,
exceptionHandler,
::hasErroredCallback
::hasErroredCallback,
notificationManager,
backlogStorage
)
)
}
......
......@@ -17,11 +17,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ssl
package de.kuschku.libquassel.ssl
import de.kuschku.libquassel.connection.HostnameVerifier
import de.kuschku.libquassel.connection.SocketAddress
import de.kuschku.quasseldroid.ssl.X509Helper.hostnames
import de.kuschku.libquassel.ssl.X509Helper.hostnames
import java.net.IDN
import java.security.cert.X509Certificate
import javax.net.ssl.SSLException
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.ssl
import de.kuschku.libquassel.connection.HostnameVerifier
import de.kuschku.libquassel.connection.SocketAddress
import java.security.cert.X509Certificate
class TrustAllHostnameVerifier : HostnameVerifier {
override fun checkValid(address: SocketAddress, chain: Array<out X509Certificate>) = Unit
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.ssl
import java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.cert.X509Certificate
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
object TrustManagers {
fun default() = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()).apply {
init(null as KeyStore?)
}.trustManagers.mapNotNull {
it as? X509TrustManager
}.firstOrNull() ?: throw GeneralSecurityException("No TrustManager available")
fun trustAll() = TrustAllX509TrustManager()
class TrustAllX509TrustManager : X509TrustManager {
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) = Unit
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) = Unit
override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
}
}
......@@ -17,14 +17,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ssl
package de.kuschku.libquassel.ssl
import java.security.cert.X509Certificate
// FIXME: re-read RFC and check it's actually secure
object X509Helper {
fun hostnames(certificate: X509Certificate): Sequence<String> =
(sequenceOf(commonName(certificate)) + subjectAlternativeNames(certificate))
(sequenceOf(commonName(certificate)) + subjectAlternativeNames(
certificate))
.filterNotNull()
.distinct()
......
......@@ -17,9 +17,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
include ':invokerannotations', ':lifecycle-ktx',
include ':invokerannotations',
':invokergenerator',
':lib',
':lifecycle-ktx',
':desktop',
":viewmodel",
":persistence",
':malheur',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment