mirror of https://github.com/Corewala/Buran
Added signature system for sites which do not require certs
Also broke a bunch of things, but we'll get there I swear.
This commit is contained in:
parent
29fe06ba54
commit
da4702b1a0
|
@ -10,6 +10,7 @@ sealed class GemState {
|
||||||
data class NotGeminiRequest(val uri: URI) : GemState()
|
data class NotGeminiRequest(val uri: URI) : GemState()
|
||||||
data class ResponseGemtext(val uri: URI, val header: GeminiResponse.Header, val lines: List<String>) : GemState()
|
data class ResponseGemtext(val uri: URI, val header: GeminiResponse.Header, val lines: List<String>) : GemState()
|
||||||
data class ResponseInput(val uri: URI, val header: GeminiResponse.Header) : GemState()
|
data class ResponseInput(val uri: URI, val header: GeminiResponse.Header) : GemState()
|
||||||
|
class Redirect(val uri: String) : GemState()
|
||||||
data class ResponseText(val uri: URI, val header: GeminiResponse.Header, val content: String) : GemState()
|
data class ResponseText(val uri: URI, val header: GeminiResponse.Header, val content: String) : GemState()
|
||||||
data class ResponseImage(val uri: URI, val header: GeminiResponse.Header, val cacheUri: Uri) : GemState()
|
data class ResponseImage(val uri: URI, val header: GeminiResponse.Header, val cacheUri: Uri) : GemState()
|
||||||
data class ResponseBinary(val uri: URI, val header: GeminiResponse.Header, val cacheUri: Uri) : GemState()
|
data class ResponseBinary(val uri: URI, val header: GeminiResponse.Header, val cacheUri: Uri) : GemState()
|
||||||
|
|
|
@ -8,7 +8,6 @@ import java.net.URI
|
||||||
interface Datasource {
|
interface Datasource {
|
||||||
fun request(address: String, forceDownload: Boolean, clientCertPassword: String?, onUpdate: (state: GemState) -> Unit)
|
fun request(address: String, forceDownload: Boolean, clientCertPassword: String?, onUpdate: (state: GemState) -> Unit)
|
||||||
fun canGoBack(): Boolean
|
fun canGoBack(): Boolean
|
||||||
fun goBack(onUpdate: (state: GemState) -> Unit)
|
|
||||||
|
|
||||||
companion object{
|
companion object{
|
||||||
fun factory(context: Context, history: BuranHistory): Datasource {
|
fun factory(context: Context, history: BuranHistory): Datasource {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import corewala.buran.OppenURI
|
||||||
import corewala.buran.io.GemState
|
import corewala.buran.io.GemState
|
||||||
import corewala.buran.io.database.history.BuranHistory
|
import corewala.buran.io.database.history.BuranHistory
|
||||||
import corewala.buran.io.keymanager.BuranKeyManager
|
import corewala.buran.io.keymanager.BuranKeyManager
|
||||||
|
import corewala.toURI
|
||||||
import corewala.toUri
|
import corewala.toUri
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
@ -30,7 +31,7 @@ class GeminiDatasource(private val context: Context, val history: BuranHistory):
|
||||||
|
|
||||||
private var socketFactory: SSLSocketFactory? = null
|
private var socketFactory: SSLSocketFactory? = null
|
||||||
|
|
||||||
override fun request(address: String, forceDownload: Boolean, clientCertPassword: String?, onUpdate: (state: GemState) -> Unit) {
|
override fun request(address: String, forceDownload: Boolean, clientCertPassword: String?, onUpdate: (state: GemState) -> Unit) {
|
||||||
this.forceDownload = forceDownload
|
this.forceDownload = forceDownload
|
||||||
|
|
||||||
this.onUpdate = onUpdate
|
this.onUpdate = onUpdate
|
||||||
|
@ -113,7 +114,7 @@ class GeminiDatasource(private val context: Context, val history: BuranHistory):
|
||||||
|
|
||||||
when {
|
when {
|
||||||
header.code == GeminiResponse.INPUT -> onUpdate(GemState.ResponseInput(uri, header))
|
header.code == GeminiResponse.INPUT -> onUpdate(GemState.ResponseInput(uri, header))
|
||||||
header.code == GeminiResponse.REDIRECT -> request(resolve(uri.host, header.meta), false, null, onUpdate)
|
header.code == GeminiResponse.REDIRECT -> onUpdate(GemState.Redirect(resolve(uri.host, header.meta)))
|
||||||
header.code == GeminiResponse.CLIENT_CERTIFICATE_REQUIRED -> onUpdate(GemState.ClientCertRequired(uri, header))
|
header.code == GeminiResponse.CLIENT_CERTIFICATE_REQUIRED -> onUpdate(GemState.ClientCertRequired(uri, header))
|
||||||
header.code != GeminiResponse.SUCCESS -> onUpdate(GemState.ResponseError(header))
|
header.code != GeminiResponse.SUCCESS -> onUpdate(GemState.ResponseError(header))
|
||||||
header.meta.startsWith("text/gemini") -> getGemtext(bufferedReader, uri, header, onUpdate)
|
header.meta.startsWith("text/gemini") -> getGemtext(bufferedReader, uri, header, onUpdate)
|
||||||
|
@ -217,11 +218,6 @@ class GeminiDatasource(private val context: Context, val history: BuranHistory):
|
||||||
|
|
||||||
override fun canGoBack(): Boolean = runtimeHistory.isEmpty() || runtimeHistory.size > 1
|
override fun canGoBack(): Boolean = runtimeHistory.isEmpty() || runtimeHistory.size > 1
|
||||||
|
|
||||||
override fun goBack(onUpdate: (state: GemState) -> Unit) {
|
|
||||||
runtimeHistory.removeLast()
|
|
||||||
request(runtimeHistory.last().toString(), false, null, onUpdate)
|
|
||||||
}
|
|
||||||
|
|
||||||
//This just forces the factory to rebuild before the next request
|
//This just forces the factory to rebuild before the next request
|
||||||
fun invalidate() {
|
fun invalidate() {
|
||||||
socketFactory = null
|
socketFactory = null
|
||||||
|
|
|
@ -20,8 +20,7 @@ class BuranKeyManager(val context: Context, val onKeyError: (error: String) -> U
|
||||||
|
|
||||||
//If the user has a key loaded load it here - or else return null
|
//If the user has a key loaded load it here - or else return null
|
||||||
fun getFactory(clientCertPassword: String?): KeyManagerFactory? {
|
fun getFactory(clientCertPassword: String?): KeyManagerFactory? {
|
||||||
return when {
|
return when { !clientCertPassword.isNullOrEmpty() -> {
|
||||||
clientCertPassword != null -> {
|
|
||||||
lastCallUsedKey = true
|
lastCallUsedKey = true
|
||||||
val keyStore: KeyStore = KeyStore.getInstance("pkcs12")
|
val keyStore: KeyStore = KeyStore.getInstance("pkcs12")
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import android.view.WindowManager
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.annotation.Nullable
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
@ -48,6 +49,7 @@ import corewala.buran.ui.modals_menus.about.AboutDialog
|
||||||
import corewala.buran.ui.modals_menus.history.HistoryDialog
|
import corewala.buran.ui.modals_menus.history.HistoryDialog
|
||||||
import corewala.buran.ui.modals_menus.overflow.OverflowPopup
|
import corewala.buran.ui.modals_menus.overflow.OverflowPopup
|
||||||
import corewala.buran.ui.settings.SettingsActivity
|
import corewala.buran.ui.settings.SettingsActivity
|
||||||
|
import kotlinx.android.synthetic.main.bookmark.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
@ -115,8 +117,13 @@ class GemActivity : AppCompatActivity() {
|
||||||
private val inlineImage: (link: URI, adapterPosition: Int) -> Unit = { uri, position: Int ->
|
private val inlineImage: (link: URI, adapterPosition: Int) -> Unit = { uri, position: Int ->
|
||||||
if(getInternetStatus()){
|
if(getInternetStatus()){
|
||||||
omniTerm.imageAddress(uri.toString())
|
omniTerm.imageAddress(uri.toString())
|
||||||
|
val clientCertPassword = if(isHostSigned(uri)){
|
||||||
|
certPassword
|
||||||
|
}else{
|
||||||
|
null
|
||||||
|
}
|
||||||
omniTerm.uri.let{
|
omniTerm.uri.let{
|
||||||
model.requestInlineImage(URI.create(it.toString())){ imageUri ->
|
model.requestInlineImage(URI.create(it.toString()), clientCertPassword){ imageUri ->
|
||||||
imageUri?.let{
|
imageUri?.let{
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
loadImage(position, imageUri)
|
loadImage(position, imageUri)
|
||||||
|
@ -249,6 +256,20 @@ class GemActivity : AppCompatActivity() {
|
||||||
binding.addressEdit.requestFocus()
|
binding.addressEdit.requestFocus()
|
||||||
inSearch = true
|
inSearch = true
|
||||||
}
|
}
|
||||||
|
R.id.overflow_menu_sign -> {
|
||||||
|
if(prefs.getBoolean("use_biometrics", false) and certPassword.isNullOrEmpty()){
|
||||||
|
biometricSecureRequest(binding.addressEdit.text.toString())
|
||||||
|
}else{
|
||||||
|
if(certPassword.isNullOrEmpty()){
|
||||||
|
certPassword = prefs.getString(
|
||||||
|
Buran.PREF_KEY_CLIENT_CERT_PASSWORD,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
gemRequest(binding.addressEdit.text.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
R.id.overflow_menu_bookmark -> {
|
R.id.overflow_menu_bookmark -> {
|
||||||
val name = adapter.inferTitle()
|
val name = adapter.inferTitle()
|
||||||
BookmarkDialog(
|
BookmarkDialog(
|
||||||
|
@ -407,6 +428,8 @@ class GemActivity : AppCompatActivity() {
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is GemState.Redirect -> gemRequest(state.uri)
|
||||||
|
|
||||||
is GemState.ClientCertRequired -> runOnUiThread {
|
is GemState.ClientCertRequired -> runOnUiThread {
|
||||||
loadingView(false)
|
loadingView(false)
|
||||||
val builder = AlertDialog.Builder(this, R.style.AppDialogTheme)
|
val builder = AlertDialog.Builder(this, R.style.AppDialogTheme)
|
||||||
|
@ -463,12 +486,17 @@ class GemActivity : AppCompatActivity() {
|
||||||
val download = getString(R.string.download)
|
val download = getString(R.string.download)
|
||||||
|
|
||||||
if(getInternetStatus()) {
|
if(getInternetStatus()) {
|
||||||
|
val clientCertPassword = if(isHostSigned(state.uri)){
|
||||||
|
certPassword
|
||||||
|
}else{
|
||||||
|
null
|
||||||
|
}
|
||||||
AlertDialog.Builder(this, R.style.AppDialogTheme)
|
AlertDialog.Builder(this, R.style.AppDialogTheme)
|
||||||
.setTitle("$download: ${state.header.meta}")
|
.setTitle("$download: ${state.header.meta}")
|
||||||
.setMessage("${state.uri}")
|
.setMessage("${state.uri}")
|
||||||
.setPositiveButton(getString(R.string.download).toUpperCase()) { _, _ ->
|
.setPositiveButton(getString(R.string.download).toUpperCase()) { _, _ ->
|
||||||
loadingView(true)
|
loadingView(true)
|
||||||
model.requestBinaryDownload(state.uri)
|
model.requestBinaryDownload(state.uri, clientCertPassword)
|
||||||
}
|
}
|
||||||
.setNegativeButton(getString(R.string.cancel).toUpperCase()) { _, _ -> }
|
.setNegativeButton(getString(R.string.cancel).toUpperCase()) { _, _ -> }
|
||||||
.show()
|
.show()
|
||||||
|
@ -755,11 +783,16 @@ class GemActivity : AppCompatActivity() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun gemRequest(address: String){
|
private fun isHostSigned(uri: URI): Boolean{
|
||||||
if(address.toURI().host != omniTerm.getCurrent().toURI().host) {
|
if((uri.host != omniTerm.getCurrent().toURI().host) && !certPassword.isNullOrEmpty()) {
|
||||||
certPassword = null
|
return false
|
||||||
}
|
}
|
||||||
println(certPassword)
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun gemRequest(address: String){
|
||||||
|
val clientCertAllowed = isHostSigned(address.toURI())
|
||||||
|
if(!clientCertAllowed) certPassword = null
|
||||||
|
|
||||||
if(getInternetStatus()){
|
if(getInternetStatus()){
|
||||||
if(initialised){
|
if(initialised){
|
||||||
|
|
|
@ -28,15 +28,15 @@ class GemViewModel: ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestBinaryDownload(uri: URI) {
|
fun requestBinaryDownload(uri: URI, clientCertPassword: String?) {
|
||||||
gemini.request(uri.toString(), true, null){ state ->
|
gemini.request(uri.toString(), true, clientCertPassword){ state ->
|
||||||
onState(state)
|
onState(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo - same action as above... refactor
|
//todo - same action as above... refactor
|
||||||
fun requestInlineImage(uri: URI, onImageReady: (cacheUri: Uri?) -> Unit){
|
fun requestInlineImage(uri: URI, clientCertPassword: String?, onImageReady: (cacheUri: Uri?) -> Unit){
|
||||||
gemini.request(uri.toString(), false, null){ state ->
|
gemini.request(uri.toString(), false, clientCertPassword){ state ->
|
||||||
when (state) {
|
when (state) {
|
||||||
is GemState.ResponseImage -> onImageReady(state.cacheUri)
|
is GemState.ResponseImage -> onImageReady(state.cacheUri)
|
||||||
else -> onState(state)
|
else -> onState(state)
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/overflow_menu_search"
|
android:id="@+id/overflow_menu_search"
|
||||||
android:title="@string/search"/>
|
android:title="@string/search"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/overflow_menu_sign"
|
||||||
|
android:title="@string/sign"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/overflow_menu_bookmark"
|
android:id="@+id/overflow_menu_bookmark"
|
||||||
android:title="@string/add_bookmark"/>
|
android:title="@string/add_bookmark"/>
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
<string name="confirm_your_identity">Confirmez votre identité</string>
|
<string name="confirm_your_identity">Confirmez votre identité</string>
|
||||||
<string name="use_biometric_unlock">Utilisez vos informations biométriques pour continuer</string>
|
<string name="use_biometric_unlock">Utilisez vos informations biométriques pour continuer</string>
|
||||||
<string name="biometric_cert_verification">Certificat Client biométrique</string>
|
<string name="biometric_cert_verification">Certificat Client biométrique</string>
|
||||||
|
<string name="sign">Certifier</string>
|
||||||
<string name="set_home_capsule">Choisir comme capsule d\'accueil</string>
|
<string name="set_home_capsule">Choisir comme capsule d\'accueil</string>
|
||||||
<string name="check_for_updates">Rechercher des nouvelles versions</string>
|
<string name="check_for_updates">Rechercher des nouvelles versions</string>
|
||||||
<string name="new_version_available">Nouvelle version disponible</string>
|
<string name="new_version_available">Nouvelle version disponible</string>
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
<string name="confirm_your_identity">Confirm your identity</string>
|
<string name="confirm_your_identity">Confirm your identity</string>
|
||||||
<string name="use_biometric_unlock">Verify your biometric credentials to continue</string>
|
<string name="use_biometric_unlock">Verify your biometric credentials to continue</string>
|
||||||
<string name="biometric_cert_verification">Client Certificate biometrics</string>
|
<string name="biometric_cert_verification">Client Certificate biometrics</string>
|
||||||
|
<string name="sign">Sign</string>
|
||||||
<string name="set_home_capsule">Set home capsule</string>
|
<string name="set_home_capsule">Set home capsule</string>
|
||||||
<string name="check_for_updates">Check for updates</string>
|
<string name="check_for_updates">Check for updates</string>
|
||||||
<string name="new_version_available">New version available</string>
|
<string name="new_version_available">New version available</string>
|
||||||
|
|
Loading…
Reference in New Issue