Jump to content

Question

Posted

Добрый день!

Купил keenetic air, стоит ndms 3.5.1 . 

Требуется сделать реконнект, например с помощью curl.

Ни в какую не получается авторизоваться, шлю {"login":"admin","password":"md5($password)"} на /auth , в чем проблема авторизации, непонятно. Защита яваскрипт какая-то?

Есть готовые решения у кого-нибудь?

Спасибо!

2 answers to this question

Recommended Posts

  • 0
Posted
1 час назад, Roundik сказал:

Добрый день!

Купил keenetic air, стоит ndms 3.5.1 . 

Требуется сделать реконнект, например с помощью curl.

Ни в какую не получается авторизоваться, шлю {"login":"admin","password":"md5($password)"} на /auth , в чем проблема авторизации, непонятно. Защита яваскрипт какая-то?

Есть готовые решения у кого-нибудь?

Спасибо!

 

  • Thanks 1
  • 0
Posted

Т.к. тема с примерами кода закрыта, отправлю сюда вариант на Kotlin + Ktor (gist):

import kotlinx.serialization.Serializable
import io.ktor.http.*
import java.security.MessageDigest
import java.util.*
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.*
import io.ktor.client.features.cookies.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.features.logging.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.runBlocking
  
private const val LOGIN = "login"
private const val PASSWORD = "password"    
  
data class KeeneticAuthHeaderValues(
    val map: Map<KeeneticAuthHeaderEnum, String>
) {
    val xndmChallenge: String by lazy { map.getValue(KeeneticAuthHeaderEnum.XNDMChallenge) }
    val xndmRealm: String by lazy { map.getValue(KeeneticAuthHeaderEnum.XNDMRealm) }
}

@Serializable
data class UserCredentials(val login: String, val password: String)
  
fun Headers.asMap(): EnumMap<KeeneticAuthHeaderEnum, String> = EnumMap(
    entries().asSequence()
        .filter { it -> it.key in KeeneticAuthHeaderEnum.values().map { it.title } }
        .associate { header -> KeeneticAuthHeaderEnum.from(header.key) to header.value.first() }
)

// However, here we have to use a custom byte to hex converter to get the hashed value in hexadecimal
private fun printHexBinary(hash: ByteArray): String {
    val hexString = StringBuilder(2 * hash.size)
    for (i in hash.indices) {
        val hex = Integer.toHexString(0xff and hash[i].toInt())
        if (hex.length == 1) {
            hexString.append('0')
        }
        hexString.append(hex)
    }
    return hexString.toString()
}

fun String.encodeMd5(): String {
    return printHexBinary(MessageDigest.getInstance("MD5").digest(toByteArray()))
}

// see more https://www.baeldung.com/sha-256-hashing-java
fun String.encodeSha256(): String {
// Java provides inbuilt MessageDigest class for SHA-256 hashing
    return printHexBinary(MessageDigest.getInstance("SHA-256").digest(toByteArray()))
}

fun main() = runBlocking {
    // HttpClientEngineFactory using a Coroutine based I/O implementation
    val client = HttpClient(CIO) {
        install(JsonFeature) {
            serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
                ignoreUnknownKeys = true
                prettyPrint = true
                isLenient = true
            })
        }
        //log all requests
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.ALL
        }
        install(HttpCookies) {
            // Will keep an in-memory map with all the cookies from previous requests.
            storage = AcceptAllCookiesStorage()
        }
    }
    // try with resource kotlin way
    client.use {
        // do auth
        authorized(client) {
            // here we have authorize
            val interfaceInfo: HttpResponse = client.get("http://192.168.1.1/rci/show/interface?name=ISP")
        }

    }

}

private suspend fun authorized(client: HttpClient, body: suspend () -> Unit) {
    val unauthorizedResponse = client.get<HttpResponse>("http://192.168.1.1/auth") { expectSuccess = false }

    if (unauthorizedResponse.status == HttpStatusCode.Unauthorized) {
        val tokenAndRealm = KeeneticAuthHeaderValues(unauthorizedResponse.headers.asMap())
        val authPostResponse = authRequest(client, tokenAndRealm, LOGIN, PASSWORD)
        if (authPostResponse.status == HttpStatusCode.OK) {
            body()
        }
    } else if(unauthorizedResponse.status == HttpStatusCode.OK){
        body()
    }
}

private suspend fun authRequest(
    client: HttpClient,
    tokenAndRealm: KeeneticAuthHeaderValues,
): HttpResponse {
    val authPostResponse = client.post<HttpResponse>("http://192.168.1.1/auth") {
        contentType(ContentType.Application.Json)
        expectSuccess = false
        val md5 = (LOGIN + ":" + tokenAndRealm.xndmRealm + ':' + PASSWORD).encodeMd5()
        body = UserCredentials(
            login = LOGIN,
            password = (tokenAndRealm.xndmChallenge + md5).encodeSha256()
        )
    }
    return authPostResponse
}

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...