Simplify password connections
This commit is contained in:
parent
1347b9ea10
commit
e1c8ffcd5d
4 changed files with 14 additions and 48 deletions
|
@ -6,15 +6,11 @@ import androidx.core.content.edit
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.wbrawner.piholeclient.PiHoleApiService
|
import com.wbrawner.piholeclient.PiHoleApiService
|
||||||
import com.wbrawner.piholeclient.Summary
|
|
||||||
import com.wbrawner.piholeclient.VersionResponse
|
import com.wbrawner.piholeclient.VersionResponse
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.net.ConnectException
|
import java.net.ConnectException
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.util.regex.Pattern
|
|
||||||
import java.util.regex.Pattern.DOTALL
|
|
||||||
|
|
||||||
const val KEY_BASE_URL = "baseUrl"
|
const val KEY_BASE_URL = "baseUrl"
|
||||||
const val KEY_API_KEY = "apiKey"
|
const val KEY_API_KEY = "apiKey"
|
||||||
|
@ -56,7 +52,9 @@ class AddPiHelperViewModel(
|
||||||
suspend fun beginScanning(deviceIpAddress: String) {
|
suspend fun beginScanning(deviceIpAddress: String) {
|
||||||
val addressParts = deviceIpAddress.split(".").toMutableList()
|
val addressParts = deviceIpAddress.split(".").toMutableList()
|
||||||
var chunks = 1
|
var chunks = 1
|
||||||
val ipAddresses = mutableListOf<String>()
|
// If the Pi-hole is correctly set up, then there should be a special host for it as
|
||||||
|
// "pi.hole"
|
||||||
|
val ipAddresses = mutableListOf("pi.hole")
|
||||||
while (chunks <= IP_MAX) {
|
while (chunks <= IP_MAX) {
|
||||||
val chunkSize = (IP_MAX - IP_MIN + 1) / chunks
|
val chunkSize = (IP_MAX - IP_MIN + 1) / chunks
|
||||||
if (chunkSize == 1) {
|
if (chunkSize == 1) {
|
||||||
|
@ -111,16 +109,8 @@ class AddPiHelperViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun authenticateWithPassword(password: String) {
|
suspend fun authenticateWithPassword(password: String) {
|
||||||
// Perform the login to get the PHPSESSID cookie set
|
// The Pi-hole API key is just the web password hashed twice with SHA-256
|
||||||
apiService.login(password)
|
authenticateWithApiKey(password.hash().hash())
|
||||||
val html = apiService.getApiToken()
|
|
||||||
val matcher = Pattern.compile(".*Raw API Token: ([a-z0-9]+).*", DOTALL)
|
|
||||||
.matcher(html)
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw RuntimeException("Unable to retrieve API token from password")
|
|
||||||
}
|
|
||||||
val apiToken = matcher.group(1)!!
|
|
||||||
authenticateWithApiKey(apiToken)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun authenticateWithApiKey(apiKey: String) {
|
suspend fun authenticateWithApiKey(apiKey: String) {
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
package com.wbrawner.pihelper
|
package com.wbrawner.pihelper
|
||||||
|
|
||||||
fun <T, R> R.transform(block: (R) -> T): T = block(this)
|
import java.math.BigInteger
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
fun String.hash(): String = BigInteger(
|
||||||
|
1,
|
||||||
|
MessageDigest.getInstance("SHA-256").digest(this.toByteArray())
|
||||||
|
).toString(16)
|
||||||
|
|
|
@ -15,12 +15,11 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.wbrawner.pihelper.MainActivity.Companion.ACTION_FORGET_PIHOLE
|
import com.wbrawner.pihelper.MainActivity.Companion.ACTION_FORGET_PIHOLE
|
||||||
import kotlinx.android.synthetic.main.fragment_main.toolbar
|
|
||||||
import kotlinx.android.synthetic.main.fragment_info.*
|
import kotlinx.android.synthetic.main.fragment_info.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_main.toolbar
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.lang.RuntimeException
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class InfoFragment : Fragment(), CoroutineScope {
|
class InfoFragment : Fragment(), CoroutineScope {
|
||||||
|
@ -30,7 +29,6 @@ class InfoFragment : Fragment(), CoroutineScope {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
throw RuntimeException("I crashed!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
|
|
@ -4,20 +4,14 @@ import com.squareup.moshi.Moshi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
interface PiHoleApiService {
|
interface PiHoleApiService {
|
||||||
var baseUrl: String?
|
var baseUrl: String?
|
||||||
var apiKey: String?
|
var apiKey: String?
|
||||||
|
|
||||||
suspend fun login(password: String): String
|
|
||||||
|
|
||||||
suspend fun getApiToken(): String
|
|
||||||
|
|
||||||
suspend fun getSummary(
|
suspend fun getSummary(
|
||||||
version: Boolean = false,
|
version: Boolean = false,
|
||||||
type: Boolean = false
|
type: Boolean = false
|
||||||
|
@ -48,8 +42,6 @@ interface PiHoleApiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const val BASE_PATH = "/admin/api.php"
|
const val BASE_PATH = "/admin/api.php"
|
||||||
const val INDEX_PATH = "/admin/index.php"
|
|
||||||
const val API_TOKEN_PATH = "/admin/scripts/pi-hole/php/api_token.php"
|
|
||||||
|
|
||||||
class OkHttpPiHoleApiService(
|
class OkHttpPiHoleApiService(
|
||||||
private val okHttpClient: OkHttpClient,
|
private val okHttpClient: OkHttpClient,
|
||||||
|
@ -110,26 +102,6 @@ class OkHttpPiHoleApiService(
|
||||||
return sendRequest(request.build(), TopItemsResponse::class)!!
|
return sendRequest(request.build(), TopItemsResponse::class)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun login(password: String): String {
|
|
||||||
val url = urlBuilder
|
|
||||||
.encodedPath(INDEX_PATH)
|
|
||||||
.addQueryParameter("login", "")
|
|
||||||
val body = "pw=$password".toRequestBody("application/x-www-form-urlencoded".toMediaType())
|
|
||||||
val request = Request.Builder()
|
|
||||||
.post(body)
|
|
||||||
.url(url.build())
|
|
||||||
return sendRequest(request.build(), String::class)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getApiToken(): String {
|
|
||||||
val url = urlBuilder
|
|
||||||
.encodedPath(API_TOKEN_PATH)
|
|
||||||
val request = Request.Builder()
|
|
||||||
.get()
|
|
||||||
.url(url.build())
|
|
||||||
return sendRequest(request.build(), String::class)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun enable(): StatusResponse {
|
override suspend fun enable(): StatusResponse {
|
||||||
val apiToken = this.apiKey ?: throw java.lang.IllegalStateException("No API Token provided")
|
val apiToken = this.apiKey ?: throw java.lang.IllegalStateException("No API Token provided")
|
||||||
val url = urlBuilder
|
val url = urlBuilder
|
||||||
|
|
Loading…
Reference in a new issue