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
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ colorpicker = "6b46b49"
conscryptAndroid = { strictly = "2.5.2" } # 2.5.3 crashes everything
constraintlayout = "2.2.1"
coreKtx = "1.18.0"
cryptography = "0.6.0"
desugar_jdk_libs_nio = "2.1.5"
dokkaGradlePlugin = "2.2.0"
espressoCore = "3.7.0"
Expand Down Expand Up @@ -77,6 +78,8 @@ conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref =
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
core = { module = "androidx.test:core" }
core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
cryptography-core = { module = "dev.whyoleg.cryptography:cryptography-core", version.ref = "cryptography" }
cryptography-provider-optimal = { module = "dev.whyoleg.cryptography:cryptography-provider-optimal", version.ref = "cryptography" }
databinding = { module = "androidx.databinding:viewbinding", version.ref = "androidGradlePlugin" }
desugar_jdk_libs_nio = { module = "com.android.tools:desugar_jdk_libs_nio", version.ref = "desugar_jdk_libs_nio" }
espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" }
Expand Down Expand Up @@ -141,6 +144,7 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi

[bundles]
coil = ["coil", "coil-network-okhttp"]
cryptography = ["cryptography-core", "cryptography-provider-optimal"]
lifecycle = ["lifecycle-livedata-ktx", "lifecycle-viewmodel-ktx"]
media3 = ["media3-cast", "media3-common", "media3-container", "media3-datasource-cronet", "media3-datasource-okhttp", "media3-exoplayer", "media3-exoplayer-dash", "media3-exoplayer-hls", "media3-session", "media3-ui"]
navigation = ["navigation-fragment-ktx", "navigation-ui-ktx"]
Expand Down
1 change: 1 addition & 0 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ kotlin {
implementation(libs.rhino) // Run JavaScript
implementation(libs.newpipeextractor)
implementation(libs.tmdb.java) // TMDB API v3 Wrapper Made with RetroFit
implementation(libs.bundles.cryptography) // Cryptography

// Deprecated; will be removed once extensions have time to migrate from using it
implementation("me.xdrop:fuzzywuzzy:1.4.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.DelicateCryptographyApi
import dev.whyoleg.cryptography.algorithms.AES
import java.net.URI
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

class Bysezejataos : ByseSX() {
class Bysezejataos : ByseSX() {
override var name = "Bysezejataos"
override var mainUrl = "https://bysezejataos.com"
}
Expand All @@ -38,6 +38,8 @@ open class ByseSX : ExtractorApi() {
override var mainUrl = "https://byse.sx"
override val requiresReferer = true

private val aesGcm = CryptographyProvider.Default.get(AES.GCM)

private fun b64UrlDecode(s: String): ByteArray {
val fixed = s.replace('-', '+').replace('_', '/')
val pad = (4 - fixed.length % 4) % 4
Expand Down Expand Up @@ -82,31 +84,29 @@ open class ByseSX : ExtractorApi() {
return p1 + p2
}

@OptIn(DelicateCryptographyApi::class)
private fun decryptPlayback(playback: Playback): String? {
val keyBytes = buildAesKey(playback)
val ivBytes = b64UrlDecode(playback.iv)
val cipherBytes = b64UrlDecode(playback.payload)

val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val spec = GCMParameterSpec(128, ivBytes)
val secretKey = SecretKeySpec(keyBytes, "AES")
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)
val aesKey = aesGcm.keyDecoder().decodeFromByteArrayBlocking(AES.Key.Format.RAW, keyBytes)
// 128-bit GCM tag (default)
val cipher = aesKey.cipher()
val plainBytes = cipher.decryptWithIvBlocking(ivBytes, cipherBytes)

val plainBytes = cipher.doFinal(cipherBytes)
var jsonStr = plainBytes.decodeToString()

if (jsonStr.startsWith("\uFEFF")) jsonStr = jsonStr.substring(1)

val root = try {
tryParseJson<PlaybackDecrypt>((jsonStr))
tryParseJson<PlaybackDecrypt>(jsonStr)
} catch (_: Exception) {
return null
}

return root?.sources?.firstOrNull()?.url
}


override suspend fun getUrl(
url: String,
referer: String?,
Expand All @@ -115,8 +115,7 @@ open class ByseSX : ExtractorApi() {
) {
val refererUrl = getBaseUrl(url)
val playbackRoot = getPlayback(url) ?: return
val streamUrl = decryptPlayback(playbackRoot.playback) ?: return

val streamUrl = decryptPlayback(playbackRoot.playback) ?: return

val headers = mapOf("Referer" to refererUrl)
M3u8Helper.generateM3u8(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ open class Gdriveplayer : ExtractorApi() {
it.toInt().toChar().toString()
}.let { Regex("var pass = \"(\\S+?)\"").first(it ?: return)?.toByteArray() }
?: throw ErrorLoadingException("can't find password")
val decryptedData = cryptoAESHandler(data, password, false, "AES/CBC/NoPadding")?.let { getAndUnpack(it) }?.replace("\\", "")
val decryptedData = cryptoAESHandler(data, password, false, false)?.let { getAndUnpack(it) }?.replace("\\", "")

val sourceData = decryptedData?.substringAfter("sources:[")?.substringBefore("],")
val subData = decryptedData?.substringAfter("tracks:[")?.substringBefore("],")
Expand Down Expand Up @@ -116,13 +116,11 @@ open class Gdriveplayer : ExtractorApi() {
)
}
}

}

data class Tracks(
@JsonProperty("file") val file: String,
@JsonProperty("kind") val kind: String,
@JsonProperty("label") val label: String
@JsonProperty("label") val label: String,
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.DelicateCryptographyApi
import dev.whyoleg.cryptography.algorithms.AES
import dev.whyoleg.cryptography.algorithms.MD5

class Megacloud : Rabbitstream() {
override val name = "Megacloud"
Expand Down Expand Up @@ -62,7 +62,6 @@ class Megacloud : Rabbitstream() {

return indexPairs
}

}

class Dokicloud : Rabbitstream() {
Expand All @@ -79,6 +78,10 @@ open class Rabbitstream : ExtractorApi() {
open val embed = "ajax/embed-4"
open val key = "https://raw.githubusercontent.com/eatmynerds/key/e4/key.txt"

private val aesCbc = CryptographyProvider.Default.get(AES.CBC)
@OptIn(DelicateCryptographyApi::class)
private val md5Hasher = CryptographyProvider.Default.get(MD5).hasher()

override suspend fun getUrl(
url: String,
referer: String?,
Expand Down Expand Up @@ -122,8 +125,6 @@ open class Rabbitstream : ExtractorApi() {
)
)
}


}

open suspend fun extractRealKey(sources: String): Pair<String, String> {
Expand All @@ -140,8 +141,8 @@ open class Rabbitstream : ExtractorApi() {
private fun decrypt(input: String, key: String): String {
return decryptSourceUrl(
generateKey(
base64DecodeArray(input).copyOfRange(8, 16),
key.toByteArray()
salt = base64DecodeArray(input).copyOfRange(8, 16),
secret = key.toByteArray()
), input
)
}
Expand All @@ -156,20 +157,18 @@ open class Rabbitstream : ExtractorApi() {
return currentKey
}

private fun md5(input: ByteArray): ByteArray {
return MessageDigest.getInstance("MD5").digest(input)
}
private fun md5(input: ByteArray): ByteArray =
md5Hasher.hashBlocking(input)

@OptIn(DelicateCryptographyApi::class)
private fun decryptSourceUrl(decryptionKey: ByteArray, sourceUrl: String): String {
val cipherData = base64DecodeArray(sourceUrl)
val encrypted = cipherData.copyOfRange(16, cipherData.size)
val aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding")
aesCBC.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(decryptionKey.copyOfRange(0, 32), "AES"),
IvParameterSpec(decryptionKey.copyOfRange(32, decryptionKey.size))
)
val decryptedData = aesCBC?.doFinal(encrypted) ?: throw ErrorLoadingException("Cipher not found")
val keyBytes = decryptionKey.copyOfRange(0, 32)
val ivBytes = decryptionKey.copyOfRange(32, decryptionKey.size)

val aesKey = aesCbc.keyDecoder().decodeFromByteArrayBlocking(AES.Key.Format.RAW, keyBytes)
val decryptedData = aesKey.cipher(padding = true).decryptWithIvBlocking(ivBytes, encrypted)
return decryptedData.decodeToString()
}

Expand All @@ -195,5 +194,4 @@ open class Rabbitstream : ExtractorApi() {
@JsonProperty("encrypted") val encrypted: Boolean? = null,
@JsonProperty("tracks") val tracks: List<Tracks?>? = emptyList(),
)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ 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 java.net.URI
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

class Server1uns : VidStack() {
override var name = "Vidstack"
Expand All @@ -32,8 +32,7 @@ open class VidStack : ExtractorApi() {
referer: String?,
subtitleCallback: (SubtitleFile) -> 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("/")
val baseurl = getBaseUrl(url)
Expand Down Expand Up @@ -93,16 +92,16 @@ open class VidStack : ExtractorApi() {
}

object AesHelper {
private const val TRANSFORMATION = "AES/CBC/PKCS5PADDING"
private val aesCbc = CryptographyProvider.Default.get(AES.CBC)

@OptIn(DelicateCryptographyApi::class)
fun decryptAES(inputHex: String, key: String, iv: String): String {
val cipher = Cipher.getInstance(TRANSFORMATION)
val secretKey = SecretKeySpec(key.toByteArray(Charsets.UTF_8), "AES")
val ivSpec = IvParameterSpec(iv.toByteArray(Charsets.UTF_8))

cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)
val decryptedBytes = cipher.doFinal(inputHex.hexToByteArray())
return String(decryptedBytes, Charsets.UTF_8)
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 {
Expand Down
Loading