Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package com.lagradost.cloudstream3.extractors
import com.lagradost.api.Log
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.extractors.helper.AesHelper.hexToByteArray
import com.lagradost.cloudstream3.extractors.helper.AesHelper.rawAesCbc
import com.lagradost.cloudstream3.newSubtitleFile
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.ExtractorLinkType
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.fixUrl
import com.lagradost.cloudstream3.utils.newExtractorLink
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.DelicateCryptographyApi
import dev.whyoleg.cryptography.algorithms.AES
import io.ktor.http.Url

class Server1uns : VidStack() {
Expand All @@ -21,7 +20,6 @@ class Server1uns : VidStack() {
override var requiresReferer = true
}


open class VidStack : ExtractorApi() {
override var name = "Vidstack"
override var mainUrl = "https://vidstack.io"
Expand All @@ -31,7 +29,7 @@ open class VidStack : ExtractorApi() {
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
callback: (ExtractorLink) -> Unit,
) {
val headers = mapOf("User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0")
val hash = url.substringAfterLast("#").substringAfter("/")
Expand All @@ -44,8 +42,14 @@ open class VidStack : ExtractorApi() {

val decryptedText = ivList.firstNotNullOfOrNull { iv ->
try {
AesHelper.decryptAES(encoded, key, iv)
} catch (e: Exception) {
rawAesCbc(
input = encoded.hexToByteArray(),
key = key.encodeToByteArray(),
iv = iv.encodeToByteArray(),
encrypt = false,
padding = true,
).decodeToString()
} catch (_: Exception) {
null
}
} ?: throw Exception("Failed to decrypt with all IVs")
Expand Down Expand Up @@ -73,7 +77,7 @@ open class VidStack : ExtractorApi() {
source = this.name,
name = this.name,
url = m3u8,
type = ExtractorLinkType.M3U8
type = ExtractorLinkType.M3U8,
) {
this.referer = url
this.quality = Qualities.Unknown.value
Expand All @@ -90,22 +94,3 @@ open class VidStack : ExtractorApi() {
}
}
}

object AesHelper {
private val aesCbc = CryptographyProvider.Default.get(AES.CBC)

@OptIn(DelicateCryptographyApi::class)
fun decryptAES(inputHex: String, key: String, iv: String): String {
val keyBytes = key.encodeToByteArray()
val ivBytes = iv.encodeToByteArray()
val aesKey = aesCbc.keyDecoder().decodeFromByteArrayBlocking(AES.Key.Format.RAW, keyBytes)
val cipher = aesKey.cipher(padding = true)
val decrypted = cipher.decryptWithIvBlocking(ivBytes, inputHex.hexToByteArray())
return decrypted.decodeToString()
}

private fun String.hexToByteArray(): ByteArray {
check(length % 2 == 0) { "Hex string must have an even length" }
return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ object AesHelper {
private val md5Hasher = provider.get(MD5).hasher()

@OptIn(DelicateCryptographyApi::class)
@Prerelease
suspend fun rawAesCbc(
input: ByteArray,
key: ByteArray,
iv: ByteArray,
encrypt: Boolean = true,
padding: Boolean = true,
): ByteArray {
val aesKey = aesCbc.keyDecoder().decodeFromByteArray(AES.Key.Format.RAW, key)
val cipher = aesKey.cipher(padding = padding)
return if (!encrypt) {
cipher.decryptWithIv(iv, input)
} else cipher.encryptWithIv(iv, input)
}

suspend fun cryptoAESHandler(
data: String,
pass: ByteArray,
Expand All @@ -35,14 +50,11 @@ object AesHelper {
saltLength = parse.s.length / 2,
) ?: return null

val aesKey = aesCbc.keyDecoder().decodeFromByteArray(AES.Key.Format.RAW, key)
val cipher = aesKey.cipher(padding = padding)

return if (!encrypt) {
val plainBytes = cipher.decryptWithIv(iv, base64DecodeArray(parse.ct))
val plainBytes = rawAesCbc(base64DecodeArray(parse.ct), key, iv, encrypt = false, padding = padding)
plainBytes.decodeToString()
} else {
base64Encode(cipher.encryptWithIv(iv, parse.ct.encodeToByteArray()))
base64Encode(rawAesCbc(parse.ct.encodeToByteArray(), key, iv, encrypt = true, padding = padding))
}
}

Expand Down