mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 04:52:39 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1531a558a5 | |||
| f19b7fa584 | |||
| c8ab7f7d42 | |||
| 5b03a1e99c |
@@ -42,7 +42,8 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
|
||||
private val _client = ManagedHttpClient();
|
||||
|
||||
private var _config : SourcePluginConfig? = null;
|
||||
private var _config: SourcePluginConfig? = null;
|
||||
private var _script: String? = null;
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -81,7 +82,7 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
}
|
||||
_buttonInstall.setOnClickListener {
|
||||
_config?.let {
|
||||
install(_config!!);
|
||||
install(_config!!, _script!!);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -114,6 +115,7 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
setLoading(true);
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val config: SourcePluginConfig;
|
||||
try {
|
||||
val configResp = _client.get(url);
|
||||
if(!configResp.isOk)
|
||||
@@ -121,33 +123,51 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
val configJson = configResp.body?.string();
|
||||
if(configJson.isNullOrEmpty())
|
||||
throw IllegalStateException("No response");
|
||||
val config = SourcePluginConfig.fromJson(configJson, url);
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loadConfig(config);
|
||||
}
|
||||
}
|
||||
catch(ex: SerializationException) {
|
||||
config = SourcePluginConfig.fromJson(configJson, url);
|
||||
} catch(ex: SerializationException) {
|
||||
Logger.e(TAG, "Failed decode config", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showDialog(this@AddSourceActivity, R.drawable.ic_error,
|
||||
"Invalid Config Format", null, null,
|
||||
0, UIDialogs.Action("Ok", { finish() }, UIDialogs.ActionStyle.PRIMARY));
|
||||
};
|
||||
}
|
||||
catch(ex: Exception) {
|
||||
return@launch;
|
||||
} catch(ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch config", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, "Failed to fetch configuration", ex);
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
||||
val script: String?
|
||||
try {
|
||||
val scriptResp = _client.get(config.absoluteScriptUrl);
|
||||
if (!scriptResp.isOk)
|
||||
throw IllegalStateException("script not available [${scriptResp.code}]");
|
||||
script = scriptResp.body?.string();
|
||||
if (script.isNullOrEmpty())
|
||||
throw IllegalStateException("script empty");
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch script", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(this@AddSourceActivity, "Failed to fetch script", ex);
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loadConfig(config, script);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fun loadConfig(config: SourcePluginConfig) {
|
||||
private fun loadConfig(config: SourcePluginConfig, script: String) {
|
||||
_config = config;
|
||||
_script = script;
|
||||
|
||||
_sourceHeader.loadConfig(config);
|
||||
_sourceHeader.loadConfig(config, script);
|
||||
_sourcePermissions.removeAllViews();
|
||||
_sourceWarnings.removeAllViews();
|
||||
|
||||
@@ -171,7 +191,7 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
|
||||
val pastelRed = resources.getColor(R.color.pastel_red);
|
||||
|
||||
for(warning in config.getWarnings())
|
||||
for(warning in config.getWarnings(script))
|
||||
_sourceWarnings.addView(
|
||||
SourceInfoView(this,
|
||||
R.drawable.ic_security_pred,
|
||||
@@ -182,8 +202,8 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
fun install(config: SourcePluginConfig) {
|
||||
StatePlugins.instance.installPlugin(this, lifecycleScope, config) {
|
||||
fun install(config: SourcePluginConfig, script: String) {
|
||||
StatePlugins.instance.installPlugin(this, lifecycleScope, config, script) {
|
||||
if(it)
|
||||
backToSources();
|
||||
}
|
||||
|
||||
+10
@@ -4,6 +4,7 @@ import android.net.Uri
|
||||
import com.futo.platformplayer.SignatureProvider
|
||||
import com.futo.platformplayer.api.media.Serializer
|
||||
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||
import com.futo.platformplayer.states.StatePlugins
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
@@ -78,6 +79,15 @@ class SourcePluginConfig(
|
||||
fun getWarnings(scriptToCheck: String? = null) : List<Pair<String,String>> {
|
||||
val list = mutableListOf<Pair<String,String>>();
|
||||
|
||||
val currentlyInstalledPlugin = StatePlugins.instance.getPlugin(id);
|
||||
if (currentlyInstalledPlugin != null) {
|
||||
if (currentlyInstalledPlugin.config.scriptPublicKey != scriptPublicKey) {
|
||||
list.add(Pair(
|
||||
"Different Author",
|
||||
"This plugin was signed by a different author. Please ensure that this is correct and that the plugin was not provided by a malicious actor."));
|
||||
}
|
||||
}
|
||||
|
||||
if(scriptPublicKey.isNullOrEmpty() || scriptSignature.isNullOrEmpty())
|
||||
list.add(Pair(
|
||||
"Missing Signature",
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ class SourceDetailFragment : MainFragment() {
|
||||
val config = _config;
|
||||
|
||||
if (config != null) {
|
||||
_sourceHeader.loadConfig(config);
|
||||
_sourceHeader.loadConfig(config, StatePlugins.instance.getScript(config.id));
|
||||
} else {
|
||||
_sourceHeader.clear();
|
||||
}
|
||||
|
||||
@@ -177,18 +177,16 @@ class StatePlugins {
|
||||
}
|
||||
fun installPlugin(context: Context, scope: CoroutineScope, sourceUrl: String, handler: ((Boolean) -> Unit)? = null) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val client = ManagedHttpClient();
|
||||
val config: SourcePluginConfig;
|
||||
try {
|
||||
val configResp = ManagedHttpClient().get(sourceUrl);
|
||||
val configResp = client.get(sourceUrl);
|
||||
if(!configResp.isOk)
|
||||
throw IllegalStateException("Failed request with ${configResp.code}");
|
||||
val configJson = configResp.body?.string();
|
||||
if(configJson.isNullOrEmpty())
|
||||
throw IllegalStateException("No response");
|
||||
val config = SourcePluginConfig.fromJson(configJson, sourceUrl);
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
installPlugin(context, scope, config, handler);
|
||||
}
|
||||
config = SourcePluginConfig.fromJson(configJson, sourceUrl);
|
||||
}
|
||||
catch(ex: SerializationException) {
|
||||
Logger.e(TAG, "Failed decode config", ex);
|
||||
@@ -199,8 +197,8 @@ class StatePlugins {
|
||||
finish();
|
||||
handler?.invoke(false);
|
||||
}, UIDialogs.ActionStyle.PRIMARY));
|
||||
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
catch(ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch config", ex);
|
||||
@@ -209,13 +207,36 @@ class StatePlugins {
|
||||
handler?.invoke(false);
|
||||
});
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
||||
val script: String?
|
||||
try {
|
||||
val scriptResp = client.get(config.absoluteScriptUrl);
|
||||
if (!scriptResp.isOk)
|
||||
throw IllegalStateException("script not available [${scriptResp.code}]");
|
||||
script = scriptResp.body?.string();
|
||||
if (script.isNullOrEmpty())
|
||||
throw IllegalStateException("script empty");
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(TAG, "Failed fetch script", ex);
|
||||
withContext(Dispatchers.Main) {
|
||||
UIDialogs.showGeneralErrorDialog(context, "Failed to fetch script", ex);
|
||||
};
|
||||
return@launch;
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
installPlugin(context, scope, config, script, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
fun installPlugin(context: Context, scope: CoroutineScope, config: SourcePluginConfig, handler: ((Boolean)->Unit)? = null) {
|
||||
fun installPlugin(context: Context, scope: CoroutineScope, config: SourcePluginConfig, script: String, handler: ((Boolean)->Unit)? = null) {
|
||||
val client = ManagedHttpClient();
|
||||
val warnings = config.getWarnings();
|
||||
|
||||
if (script.isEmpty())
|
||||
throw IllegalStateException("script empty");
|
||||
|
||||
fun doInstall(reinstall: Boolean) {
|
||||
UIDialogs.showDialogProgress(context) {
|
||||
@@ -224,13 +245,6 @@ class StatePlugins {
|
||||
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val scriptResp = client.get(config.absoluteScriptUrl);
|
||||
if (!scriptResp.isOk)
|
||||
throw IllegalStateException("script not available [${scriptResp.code}]");
|
||||
val script = scriptResp.body?.string();
|
||||
if (script.isNullOrEmpty())
|
||||
throw IllegalStateException("script empty");
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
it.setText("Validating script...");
|
||||
it.setProgress(0.25);
|
||||
|
||||
@@ -23,6 +23,7 @@ class SourceHeaderView : LinearLayout {
|
||||
private val _sourceVersion: TextView;
|
||||
private val _sourceRepositoryUrl: TextView;
|
||||
private val _sourceScriptUrl: TextView;
|
||||
private val _sourceSignature: TextView;
|
||||
|
||||
private var _config : SourcePluginConfig? = null;
|
||||
|
||||
@@ -38,6 +39,7 @@ class SourceHeaderView : LinearLayout {
|
||||
_sourceVersion = findViewById(R.id.source_version);
|
||||
_sourceRepositoryUrl = findViewById(R.id.source_repo);
|
||||
_sourceScriptUrl = findViewById(R.id.source_script);
|
||||
_sourceSignature = findViewById(R.id.source_signature);
|
||||
|
||||
_sourceBy.setOnClickListener {
|
||||
if(!_config?.authorUrl.isNullOrEmpty())
|
||||
@@ -53,7 +55,7 @@ class SourceHeaderView : LinearLayout {
|
||||
};
|
||||
}
|
||||
|
||||
fun loadConfig(config: SourcePluginConfig) {
|
||||
fun loadConfig(config: SourcePluginConfig, script: String?) {
|
||||
_config = config;
|
||||
|
||||
val loadedIcon = StatePlugins.instance.getPluginIconOrNull(config.id);
|
||||
@@ -76,6 +78,22 @@ class SourceHeaderView : LinearLayout {
|
||||
_sourceBy.setTextColor(resources.getColor(R.color.colorPrimary));
|
||||
else
|
||||
_sourceBy.setTextColor(Color.WHITE);
|
||||
|
||||
if (!config.scriptPublicKey.isNullOrEmpty() && !config.scriptSignature.isNullOrEmpty()) {
|
||||
if (script == null) {
|
||||
_sourceSignature.setTextColor(Color.rgb(0xAC, 0xAC, 0xAC));
|
||||
_sourceSignature.text = "Script is not available";
|
||||
} else if (config.validate(script)) {
|
||||
_sourceSignature.setTextColor(Color.rgb(0, 255, 0));
|
||||
_sourceSignature.text = "Signature is valid";
|
||||
} else {
|
||||
_sourceSignature.setTextColor(Color.rgb(255, 0, 0));
|
||||
_sourceSignature.text = "Signature is invalid";
|
||||
}
|
||||
} else {
|
||||
_sourceSignature.setTextColor(Color.rgb(255, 0, 0));
|
||||
_sourceSignature.text = "No signature available";
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
|
||||
@@ -144,4 +144,27 @@
|
||||
android:fontFamily="@font/inter_extra_light"
|
||||
android:text="https://some.repository.url/whatever/someScript.js" />
|
||||
</LinearLayout>
|
||||
|
||||
<!--Script Url-->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14dp"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginTop="10dp"
|
||||
android:fontFamily="@font/inter_light"
|
||||
android:text="Signature" />
|
||||
<TextView
|
||||
android:id="@+id/source_signature"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14dp"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:fontFamily="@font/inter_extra_light"
|
||||
android:text="Valid" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
Submodule app/src/playstore/assets/sources/peertube updated: 0e2bdc5671...c46006bb65
Submodule app/src/stable/assets/sources/kick updated: a0223bd896...82aa06b98e
Submodule app/src/stable/assets/sources/nebula updated: 0950f45053...aa2a4f2970
Submodule app/src/stable/assets/sources/odysee updated: 9901701fb1...474672bcc0
Submodule app/src/stable/assets/sources/patreon updated: e47253c805...54a3cc4efe
Submodule app/src/stable/assets/sources/peertube updated: 0e2bdc5671...c46006bb65
Submodule app/src/stable/assets/sources/rumble updated: cb42f49532...16c09b9e21
Submodule app/src/stable/assets/sources/soundcloud updated: 27bf23c1af...3e3f95365a
Submodule app/src/stable/assets/sources/twitch updated: faa84134da...7e8ce3a2ed
Submodule app/src/stable/assets/sources/youtube updated: d52e3ebaf5...35ac3ba949
Submodule app/src/unstable/assets/sources/kick updated: a0223bd896...82aa06b98e
Submodule app/src/unstable/assets/sources/nebula updated: 0950f45053...aa2a4f2970
Submodule app/src/unstable/assets/sources/odysee updated: 9901701fb1...474672bcc0
Submodule app/src/unstable/assets/sources/patreon updated: e47253c805...54a3cc4efe
Submodule app/src/unstable/assets/sources/peertube updated: 0e2bdc5671...c46006bb65
Submodule app/src/unstable/assets/sources/rumble updated: cb42f49532...16c09b9e21
Submodule app/src/unstable/assets/sources/soundcloud updated: 27bf23c1af...3e3f95365a
Submodule app/src/unstable/assets/sources/twitch updated: faa84134da...7e8ce3a2ed
Submodule app/src/unstable/assets/sources/youtube updated: d52e3ebaf5...35ac3ba949
+1
-1
@@ -3,7 +3,7 @@ DOCUMENT_ROOT=/var/www/html
|
||||
|
||||
# Sign sources
|
||||
echo "Signing all sources..."
|
||||
bash ./sign-all-sources.sh
|
||||
/usr/bin/bash ./sign-all-sources.sh
|
||||
|
||||
# Build content
|
||||
echo "Building content..."
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ DOCUMENT_ROOT=/var/www/html
|
||||
|
||||
# Sign sources
|
||||
echo "Signing all sources..."
|
||||
bash ./sign-all-sources.sh
|
||||
/usr/bin/bash ./sign-all-sources.sh
|
||||
|
||||
# Build content
|
||||
echo "Building content..."
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/bin/sh
|
||||
DOCUMENT_ROOT=/var/www/html
|
||||
|
||||
# Sign sources
|
||||
echo "Signing all sources..."
|
||||
/usr/bin/bash ./sign-all-sources.sh
|
||||
|
||||
# Build content
|
||||
echo "Building content..."
|
||||
./gradlew --stacktrace assembleUnstableRelease
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
PRIVATE_KEY=$(openssl genpkey -algorithm RSA -outform PEM)
|
||||
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | openssl rsa -pubout -outform PEM)
|
||||
echo -en "\nPrivate key:\n$PRIVATE_KEY\n"
|
||||
echo -en "\nPrivate key (base64):\n$(echo "$PRIVATE_KEY" | base64 -w 0)\n"
|
||||
echo -en "\nPublic key:\n$PUBLIC_KEY\n"
|
||||
echo -en "\nPublic key (base64):\n$(echo "$PUBLIC_KEY" | base64 -w 0)\n"
|
||||
Reference in New Issue
Block a user