Skip to content

Commit

Permalink
Add double confirmation on superaccess request for untrusted
Browse files Browse the repository at this point in the history
  • Loading branch information
serivesmejia committed Oct 29, 2024
1 parent e95c53d commit 8470509
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 59 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ fabric.properties

*.log

*.pem

**/Build.java
**/build/*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
public class Config {
public volatile Theme simTheme = Theme.Light;

@Deprecated
public volatile double zoom = 1;

public volatile PipelineFps pipelineMaxFps = PipelineFps.MEDIUM;
Expand All @@ -63,6 +64,7 @@ public class Config {

public volatile HashMap<String, TunableFieldPanelConfig.Config> specificTunableFieldConfig = new HashMap<>();

@Deprecated
public volatile List<String> superAccessPluginHashes = new ArrayList<>();

public volatile HashMap<String, Boolean> flags = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,11 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing
import java.awt.Dimension
import java.awt.GridBagConstraints
import java.awt.GridBagLayout
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection
import javax.swing.*
import java.awt.GridBagConstraints
import java.awt.GridBagLayout
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import javax.swing.event.ChangeEvent
import javax.swing.event.ChangeListener

Expand Down Expand Up @@ -231,34 +229,40 @@ class PluginOutput(
anchor = GridBagConstraints.CENTER
})

val signatureStatus = if(loader.signature.verified)
"This plugin has been verified and was signed by ${loader.signature.authority!!.name}."
else "This plugin is not signed."

val authorEmail = if(loader.pluginAuthorEmail.isBlank())
"The author did not provide contact information."
else "Contact the author at ${loader.pluginAuthorEmail}"

val description = if(loader.pluginDescription.isBlank())
"No description available."
else loader.pluginDescription

val source = if(loader.pluginSource == PluginSource.REPOSITORY)
"Maven repository"
else "local file"

val sourceEnabled = if(loader.shouldEnable) "It was loaded from a $source." else "It is disabled, it comes from a $source."

val superAccess = if(loader.hasSuperAccess)
"This plugin has super access."
else "This plugin does not have super access."
"It has super access."
else "It does not have super access."

val wantsSuperAccess = if(loader.pluginToml.getBoolean("super-access", false))
"It requests super access in its manifest."
else "It does not request super access in its manifest."

val description = if(loader.pluginDescription.isBlank())
"No description available."
else loader.pluginDescription

val font = pluginNameLabel.font.deriveFont(13.0f)

// add a text area for the plugin description
val pluginDescriptionArea = JTextArea("""
$signatureStatus
$authorEmail
${if(loader.shouldEnable) "This plugin was loaded from a $source." else "This plugin is disabled, it comes from a $source."}
$superAccess $wantsSuperAccess
** $sourceEnabled $superAccess $wantsSuperAccess **
$description
""".trimIndent())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@

package com.github.serivesmejia.eocvsim.util.extension

import com.github.serivesmejia.eocvsim.util.SysUtil
import java.io.File
import java.security.MessageDigest

/**
* Operator function to concatenate a string to a file path
*/
operator fun File.plus(str: String): File {
return File(this.absolutePath, str)
}


fun File.fileHash(algorithm: String = "SHA-256"): String {
val messageDigest = MessageDigest.getInstance(algorithm)
messageDigest.update(readBytes())
return SysUtil.byteArray2Hex(messageDigest.digest())
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import java.awt.event.WindowEvent
import java.awt.event.WindowListener
import javax.swing.*

class SuperAccessRequest(sourceName: String, reason: String, val callback: (Boolean) -> Unit) {
class SuperAccessRequest(sourceName: String, reason: String, val untrusted: Boolean, val callback: (Boolean) -> Unit) {

init {
FlatArcDarkIJTheme.setup()
Expand Down Expand Up @@ -76,7 +76,23 @@ class SuperAccessRequest(sourceName: String, reason: String, val callback: (Bool
val acceptButton = JButton("Accept").apply {
preferredSize = Dimension(100, 30)
addActionListener {
callback(true)
if(untrusted) {
JOptionPane.showConfirmDialog(
frame,
"We were unable to verify the integrity and origin of the plugin. Are you sure you want to accept this request? Do so at your own risk.",
"Confirm",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE
).let {
if(it == JOptionPane.YES_OPTION) {
callback(true)
} else {
callback(false)
}
}
} else {
callback(true)
}

frame.isVisible = false
frame.dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.github.serivesmejia.eocvsim.gui.dialog.AppendDelegate
import com.github.serivesmejia.eocvsim.gui.dialog.PluginOutput
import com.github.serivesmejia.eocvsim.util.SysUtil
import com.github.serivesmejia.eocvsim.util.event.EventHandler
import com.github.serivesmejia.eocvsim.util.extension.fileHash
import com.github.serivesmejia.eocvsim.util.extension.hashString
import com.github.serivesmejia.eocvsim.util.extension.plus
import com.github.serivesmejia.eocvsim.util.loggerForThis
Expand All @@ -48,15 +49,15 @@ enum class PluginSource {
}

class PluginParser(pluginToml: Toml) {
val pluginName = pluginToml.getString("name") ?: throw InvalidPluginException("No name in plugin.toml")
val pluginVersion = pluginToml.getString("version") ?: throw InvalidPluginException("No version in plugin.toml")
val pluginName = pluginToml.getString("name")?.trim() ?: throw InvalidPluginException("No name in plugin.toml")
val pluginVersion = pluginToml.getString("version")?.trim() ?: throw InvalidPluginException("No version in plugin.toml")

val pluginAuthor = pluginToml.getString("author") ?: throw InvalidPluginException("No author in plugin.toml")
val pluginAuthorEmail = pluginToml.getString("author-email", "")
val pluginAuthor = pluginToml.getString("author")?.trim() ?: throw InvalidPluginException("No author in plugin.toml")
val pluginAuthorEmail = pluginToml.getString("author-email", "")?.trim()

val pluginMain = pluginToml.getString("main") ?: throw InvalidPluginException("No main in plugin.toml")
val pluginMain = pluginToml.getString("main")?.trim() ?: throw InvalidPluginException("No main in plugin.toml")

val pluginDescription = pluginToml.getString("description", "")
val pluginDescription = pluginToml.getString("description", "")?.trim()

/**
* Get the hash of the plugin based off the plugin name and author
Expand Down Expand Up @@ -162,8 +163,8 @@ class PluginLoader(
pluginName = parser.pluginName
pluginVersion = parser.pluginVersion
pluginAuthor = parser.pluginAuthor
pluginAuthorEmail = parser.pluginAuthorEmail
pluginDescription = parser.pluginDescription
pluginAuthorEmail = parser.pluginAuthorEmail ?: ""
pluginDescription = parser.pluginDescription ?: ""
}

/**
Expand All @@ -183,6 +184,8 @@ class PluginLoader(

appender.appendln("${PluginOutput.SPECIAL_SILENT}Loading plugin $pluginName v$pluginVersion by $pluginAuthor from ${pluginSource.name}")

signature

setupFs()

if(pluginToml.contains("api-version") || pluginToml.contains("min-api-version")) {
Expand Down Expand Up @@ -293,14 +296,4 @@ class PluginLoader(
*/
fun hash() = "${pluginName}${PluginOutput.SPECIAL}${pluginAuthor}".hashString

/**
* Get the hash of the plugin file based off the file contents
* @return the hash
*/
val pluginFileHash by lazy {
val messageDigest = MessageDigest.getInstance("SHA-256")
messageDigest.update(pluginFile.readBytes())
SysUtil.byteArray2Hex(messageDigest.digest())
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ object AuthorityFetcher {
// Load existing authorities if the file exists
if (AUTHORITIES_FILE.exists()) {
val existingToml = AUTHORITIES_FILE.readText()
if(existingToml.contains("[$name]")) {
// remove the existing authority. we need to delete the [$name] and the next two lines
val lines = existingToml.lines().toMutableList()
val index = lines.indexOfFirst { it == "[$name]" }

if(index != -1) {
lines.removeAt(index)
lines.removeAt(index)
lines.removeAt(index)
}
sb.append(lines.joinToString("\n"))
}

sb.append(existingToml)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ object PluginSignatureVerifier {
}

if(signatureStatus.containsValue(false)) {
logger.warn("Not all classes were signed")
return emptyResult
throw InvalidPluginException("Some classes in the plugin are not signed. Please try to re-download the plugin or discard it immediately.")
}

logger.info("Plugin signature of ${pluginFile.absolutePath} verified, signed by $authorityName")
logger.info("Plugin ${pluginFile.absolutePath} has been verified, signed by $authorityName")


return PluginSignature(true, authority, System.currentTimeMillis(), )
return PluginSignature(true, authority, System.currentTimeMillis())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,28 @@

package io.github.deltacv.eocvsim.plugin.security.superaccess

import com.github.serivesmejia.eocvsim.util.JavaProcess
import com.github.serivesmejia.eocvsim.util.SysUtil
import com.github.serivesmejia.eocvsim.util.extension.plus
import com.github.serivesmejia.eocvsim.util.extension.fileHash
import com.github.serivesmejia.eocvsim.util.io.EOCVSimFolder
import com.github.serivesmejia.eocvsim.util.loggerForThis
import com.github.serivesmejia.eocvsim.util.extension.plus
import com.github.serivesmejia.eocvsim.util.serialization.PolymorphicAdapter
import com.google.gson.GsonBuilder
import com.moandjiezana.toml.Toml
import io.github.deltacv.eocvsim.gui.dialog.SuperAccessRequest
import javax.swing.SwingUtilities
import io.github.deltacv.eocvsim.plugin.loader.PluginManager.Companion.GENERIC_LAWYER_YEET
import io.github.deltacv.eocvsim.plugin.loader.PluginManager.Companion.GENERIC_SUPERACCESS_WARN
import io.github.deltacv.eocvsim.plugin.loader.PluginParser
import io.github.deltacv.eocvsim.plugin.security.Authority
import io.github.deltacv.eocvsim.plugin.security.AuthorityFetcher
import io.github.deltacv.eocvsim.plugin.security.MutablePluginSignature
import kotlinx.coroutines.newFixedThreadPoolContext
import org.java_websocket.client.WebSocketClient
import java.net.URI
import org.java_websocket.handshake.ServerHandshake
import java.util.zip.ZipFile
import java.io.File
import java.lang.Exception
import java.security.MessageDigest
import java.net.URI
import java.util.concurrent.Executors
import java.util.zip.ZipFile
import javax.swing.SwingUtilities
import kotlin.system.exitProcess

object SuperAccessDaemon {
Expand Down Expand Up @@ -88,12 +85,14 @@ object SuperAccessDaemon {
logger.warn("Ignoring extra arguments.")
}

System.setProperty("sun.java2d.d3d", "false")

WsClient(args[0].toIntOrNull() ?: throw IllegalArgumentException("Port is not a valid int")).connect()
}

class WsClient(port: Int) : WebSocketClient(URI("ws://localhost:$port")) {

private val executor = Executors.newFixedThreadPool(6)
private val executor = Executors.newFixedThreadPool(4)

override fun onOpen(p0: ServerHandshake?) {
logger.info("SuperAccessDaemon connection opened")
Expand Down Expand Up @@ -153,7 +152,7 @@ object SuperAccessDaemon {
}
} else {
val fetch = AuthorityFetcher.fetchAuthority(parser.pluginAuthor)
untrusted = fetch != null // the plugin is claiming to be made by the authority but it's not signed by them
untrusted = fetch != null // the plugin is claiming to be made by the authority, but it's not signed by them
}

val reason = message.reason
Expand All @@ -176,7 +175,7 @@ object SuperAccessDaemon {
warning += "</html>"

SwingUtilities.invokeLater {
SuperAccessRequest(name, warning) { granted ->
SuperAccessRequest(name, warning, validAuthority == null || untrusted) { granted ->
if(granted) {
SUPERACCESS_FILE.appendText(pluginFile.fileHash() + "\n")
accessGranted(message.id, message.pluginPath)
Expand All @@ -200,25 +199,13 @@ object SuperAccessDaemon {

val pluginFile = File(message.pluginPath)

val parser = parsePlugin(pluginFile) ?: run {
logger.error("Failed to parse plugin at ${message.pluginPath}")
send(gson.toJson(SuperAccessResponse.Failure(message.id)))
return
}

if(SUPERACCESS_FILE.exists() && SUPERACCESS_FILE.readLines().contains(pluginFile.fileHash())) {
accessGranted(message.id, message.pluginPath)
} else {
accessDenied(message.id, message.pluginPath)
}
}

private fun File.fileHash(): String {
val messageDigest = MessageDigest.getInstance("SHA-256")
messageDigest.update(readBytes())
return SysUtil.byteArray2Hex(messageDigest.digest())
}

private fun accessGranted(id: Int, pluginPath: String) {
access[pluginPath] = true
send(gson.toJson(SuperAccessResponse.Success(id)))
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ Join the [deltacv discord server](https://discord.gg/A3RMYzf6DA) !

### Formerly, EOCV-Sim was hosted on a [personal account repo](https://github.com/serivesmejia/EOCV-Sim/). Released prior to 3.0.0 can be found there for historic purposes.


## [v3.8.0 - Better FTC VisionPortal support & Plugin System Fixes](https://github.com/deltacv/EOCV-Sim/releases/tag/v3.8.0)
- This is the 25th release for EOCV-Sim
- Changelog
- Update skiko to 0.8.15
- Fixes Typeface.DEFAULT_BOLD and Typeface.DEFAULT_ITALIC to actually work
- Adds a stub no-op implementation for the FTC SDK Gamepad class into OpMode
- Adds android.opengl.Matrix implementation and matrices from the FTC SDK
- Adds navigation classes from the FTC SDK (AngleUnit, AxesOrder, AxesReference, etc)
- Adds the ConceptAprilTagLocalization, ConceptVisionColorLocator and ConceptVisionColorSensor samples
- Reimplements Telemetry to EOCVSimTelemetryImpl with stubs for Telemetry#talk
- Internal changes:
- Plugin virtual filesystems now use the name and author in the TOML to generate the fs name
- Allows to specify JVM args in JavaExec
- Rename some internal classes
- Better handling of Pipeline/OpMode tab switching

## [v3.7.1 - Better FTC VisionPortal support & Plugin System Fixes](https://github.com/deltacv/EOCV-Sim/releases/tag/v3.7.1)
- This is the 24th release for EOCV-Sim
- Changelog
Expand Down

0 comments on commit 8470509

Please sign in to comment.