Skip to content
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ dependencies {
implementation(libs.conscrypt.android) // To Fix SSL Fu*kery on Android 9
implementation(libs.jackson.module.kotlin) // JSON Parser
implementation(libs.zipline)
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 @@ -16,6 +16,8 @@ import com.lagradost.cloudstream3.plugins.PluginManager.getPluginSanitizedFileNa
import com.lagradost.cloudstream3.plugins.PluginManager.unloadPlugin
import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY
import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.algorithms.SHA256
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.SerialName
Expand All @@ -24,7 +26,6 @@ import java.io.File
import java.nio.file.AtomicMoveNotSupportedException
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.security.MessageDigest
import java.util.concurrent.TimeUnit

/**
Expand Down Expand Up @@ -103,22 +104,31 @@ object RepositoryManager {
private val GH_REGEX =
Regex("^https://raw.githubusercontent.com/([A-Za-z0-9-]+)/([A-Za-z0-9_.-]+)/(.*)$")


/** Returns a SHA-256 string of the file content.
* Example: "sha256-b70462c264cb7f90fc2860a8e58d7544ce747ff347d1d11fa093623901853573" **/
@WorkerThread
fun sha256(file: File): String {
val digest = MessageDigest.getInstance("SHA-256")

file.inputStream().use { fis ->
val buffer = ByteArray(8192)
var read = fis.read(buffer)
while (read != -1) {
digest.update(buffer, 0, read)
read = fis.read(buffer)
val hashFunction = CryptographyProvider.Default.get(SHA256)
.hasher().createHashFunction()
// Use kotlinx-io eventually
/*
return hashFunction.use {
it.update(file.asSource())
"sha256-" + it.hashToByteArray().joinToString("") { b -> "%02x".format(b) }
}
*/
hashFunction.use {
file.inputStream().use { fis ->
val buffer = ByteArray(8192)
var read = fis.read(buffer)
while (read != -1) {
it.update(buffer, 0, read)
read = fis.read(buffer)
}
}

return "sha256-" + it.hashToByteArray().joinToString("") { b -> "%02x".format(b) }
}
return "sha256-" + digest.digest().joinToString("") { "%02x".format(it) }
}

/* Convert raw.githubusercontent.com urls to cdn.jsdelivr.net if enabled in settings */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import com.lagradost.cloudstream3.CloudStreamApp.Companion.context
import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey
import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey
import com.lagradost.cloudstream3.R
import java.security.MessageDigest
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.Coroutines.main
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.algorithms.SHA256
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.SerialName
Expand All @@ -19,14 +20,13 @@ object VotingApi {
private const val LOGKEY = "VotingApi"
private const val API_DOMAIN = "https://api.countify.xyz"

private fun transformUrl(url: String): String =
MessageDigest
.getInstance("SHA-256")
.digest("${url}#funny-salt".toByteArray())
private suspend fun transformUrl(url: String): String =
CryptographyProvider.Default.get(SHA256)
.hasher().hash("$url#funny-salt".encodeToByteArray())
.fold("") { str, it -> str + "%02x".format(it) }

suspend fun SitePlugin.getVotes(): Int = getVotes(url)
fun SitePlugin.hasVoted(): Boolean = hasVoted(url)
suspend fun SitePlugin.hasVoted(): Boolean = hasVoted(url)
suspend fun SitePlugin.vote(): Int = vote(url)
fun SitePlugin.canVote(): Boolean = canVote(this.url)

Expand All @@ -52,7 +52,7 @@ object VotingApi {
votesCache[pluginUrl] = it
}

fun hasVoted(pluginUrl: String): Boolean =
suspend fun hasVoted(pluginUrl: String): Boolean =
getKey<Boolean>("cs3-votes/${transformUrl(pluginUrl)}") ?: false

fun canVote(pluginUrl: String): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import com.lagradost.cloudstream3.APIHolder.unixTimeMS
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING
import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery
import dev.whyoleg.cryptography.random.CryptographyRandom
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import java.net.URI
import java.security.SecureRandom

data class AuthLoginPage(
/** The website to open to authenticate */
Expand Down Expand Up @@ -182,9 +182,7 @@ abstract class AuthAPI {
fun generateCodeVerifier(): String {
// It is recommended to use a URL-safe string as code_verifier.
// See section 4 of RFC 7636 for more details.
val secureRandom = SecureRandom()
val codeVerifierBytes = ByteArray(96) // base64 has 6bit per char; (8/6)*96 = 128
secureRandom.nextBytes(codeVerifierBytes)
val codeVerifierBytes = CryptographyRandom.nextBytes(96) // base64 has 6bit per char; (8/6)*96 = 128
return base64Encode(codeVerifierBytes).trimEnd('=')
.replace("+", "-").replace("/", "_").replace("\n", "")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.DataStoreHelper.toYear
import com.lagradost.cloudstream3.utils.serializers.NonEmptySerializer
import com.lagradost.cloudstream3.utils.txt
import dev.whyoleg.cryptography.random.CryptographyRandom
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KeepGeneratedSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.math.BigInteger
import java.security.SecureRandom
import java.text.SimpleDateFormat
import java.time.Instant
import java.util.Date
Expand Down Expand Up @@ -987,7 +987,7 @@ class SimklApi : SyncAPI() {
}

override fun loginRequest(): AuthLoginPage? {
val lastLoginState = BigInteger(130, SecureRandom()).toString(32)
val lastLoginState = BigInteger(130, CryptographyRandom.nextBytes(17)).toString(32)
val url = "https://simkl.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$APP_STRING://$redirectUrlIdentifier&state=$lastLoginState"
return AuthLoginPage(
url = url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ import kotlinx.coroutines.delay
import okhttp3.Interceptor
import org.chromium.net.CronetEngine
import java.io.File
import java.security.SecureRandom
import java.util.UUID
import java.util.concurrent.Executors
import javax.net.ssl.HttpsURLConnection
Expand Down Expand Up @@ -1893,7 +1892,7 @@ class CS3IPlayer : IPlayer {
if (ignoreSSL) {
// Disables ssl check
val sslContext: SSLContext = SSLContext.getInstance("TLS")
sslContext.init(null, arrayOf(SSLTrustManager()), SecureRandom())
sslContext.init(null, arrayOf(SSLTrustManager()), null)
sslContext.createSSLEngine()
HttpsURLConnection.setDefaultHostnameVerifier { _: String, _: SSLSession ->
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class PluginDetailsFragment(val data: PluginViewData) : BaseBottomSheetDialogFra
}
}

private fun updateVoting(value: Int) {
private suspend fun updateVoting(value: Int) {
val metadata = data.pluginWrapper.plugin
binding?.apply {
pluginVotes.text = value.toString()
Expand All @@ -149,4 +149,4 @@ class PluginDetailsFragment(val data: PluginViewData) : BaseBottomSheetDialogFra
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import com.lagradost.cloudstream3.syncproviders.PlainAuthRepo
import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.DelicateCryptographyApi
import dev.whyoleg.cryptography.algorithms.MD5
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.math.BigInteger
import java.util.concurrent.ConcurrentHashMap
import java.security.MessageDigest

class AnimeSkipAuth : AuthAPI() {
override val name = "AnimeSkip"
Expand All @@ -31,9 +33,12 @@ class AnimeSkipAuth : AuthAPI() {
override val hasInApp = true
override val createAccountUrl = "https://anime-skip.com/account"
val baseClientId = "as1JgiMbW4wKfmTLWXS79iTDQFll76pk"
fun md5(input: String): String {
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0')

suspend fun md5(input: String): String {
@OptIn(DelicateCryptographyApi::class)
val digest = CryptographyProvider.Default.get(MD5)
.hasher().hash(input.encodeToByteArray())
return BigInteger(1, digest).toString(16).padStart(32, '0')
}

@Serializable
Expand Down