Skip to content

Commit

Permalink
Autoaccept super access coming from trusted source & bundle PaperVision
Browse files Browse the repository at this point in the history
  • Loading branch information
serivesmejia committed Nov 21, 2024
1 parent 4dc3bb7 commit de7d7a9
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 39 deletions.
7 changes: 7 additions & 0 deletions Common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
plugins {
id 'kotlin'
id 'signing'
id 'com.github.johnrengelman.shadow'
id "com.vanniktech.maven.publish" version "0.30.0"
}

apply from: '../build.common.gradle'

shadowJar {
dependencies {
exclude "nu/pattern/*"
}
}

dependencies {
api "org.openpnp:opencv:$opencv_version"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class PluginSigningTool : Runnable {
privateKeyFile.readBytes()
}

val keyString = String(keyBytes)
val keyString = String(keyBytes, Charsets.UTF_8)
val decodedKey = Base64.getDecoder().decode(AuthorityFetcher.parsePem(keyString))

val keySpec = PKCS8EncodedKeySpec(decodedKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class Config {
@Deprecated
public volatile List<String> superAccessPluginHashes = new ArrayList<>();

public volatile boolean autoAcceptSuperAccessOnTrusted = true;

public volatile HashMap<String, Boolean> flags = new HashMap<>();

public boolean hasFlag(String flagName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ public class Configuration {
private final EOCVSim eocvSim;
public JPanel contents = new JPanel(new GridBagLayout());
public JComboBox<String> themeComboBox = new JComboBox<>();
public JCheckBox superAccessCheckBox = new JCheckBox("Auto Accept SuperAccess on Trusted Plugins");

public JButton acceptButton = new JButton("Accept");

public JCheckBox pauseOnImageCheckBox = new JCheckBox();
public JCheckBox pauseOnImageCheckBox = new JCheckBox("Pause with Image Sources");

public EnumComboBox<PipelineTimeout> pipelineTimeoutComboBox = null;
public EnumComboBox<PipelineFps> pipelineFpsComboBox = null;
Expand Down Expand Up @@ -81,7 +82,7 @@ private void initConfiguration() {
UI TAB
*/

JPanel uiPanel = new JPanel(new GridLayout(1, 1, 1, 8));
JPanel uiPanel = new JPanel(new GridLayout(2, 1, 1, 8));

/* THEME SETTING */
JPanel themePanel = new JPanel(new FlowLayout());
Expand All @@ -98,6 +99,16 @@ private void initConfiguration() {
themePanel.add(this.themeComboBox);
uiPanel.add(themePanel);

/* AUTO ACCEPT SUPERACCESS ON TRUSTED PLUGINS */

JPanel superAccessPanel = new JPanel(new FlowLayout());

superAccessCheckBox.setSelected(config.autoAcceptSuperAccessOnTrusted);

superAccessPanel.add(superAccessCheckBox);

uiPanel.add(superAccessPanel);

tabbedPane.addTab("Interface", uiPanel);

/*
Expand All @@ -107,12 +118,10 @@ private void initConfiguration() {

/* PAUSE WITH IMAGE SOURCES OPTION */
JPanel pauseOnImagePanel = new JPanel(new FlowLayout());
JLabel pauseOnImageLabel = new JLabel("Pause with Image Sources");

pauseOnImageCheckBox.setSelected(config.pauseOnImages);

pauseOnImagePanel.add(pauseOnImageCheckBox);
pauseOnImagePanel.add(pauseOnImageLabel);

inputSourcesPanel.add(pauseOnImagePanel);

Expand Down Expand Up @@ -215,6 +224,7 @@ private void applyChanges() {
config.pipelineMaxFps = pipelineFpsComboBox.getSelectedEnum();
config.videoRecordingSize = videoRecordingSize.getCurrentSize();
config.videoRecordingFps = videoRecordingFpsComboBox.getSelectedEnum();
config.autoAcceptSuperAccessOnTrusted = superAccessCheckBox.isSelected();

eocvSim.configManager.saveToFile(); //update config file

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ class PluginLoader(
}

pluginClass = pluginClassLoader.loadClassStrict(pluginToml.getString("main"))
plugin = pluginClass.getConstructor().newInstance() as EOCVSimPlugin
plugin = try {
pluginClass.getConstructor().newInstance() as EOCVSimPlugin
} catch(e: Throwable) {
throw InvalidPluginException("Failed to instantiate plugin class ${pluginClass.name}. Make sure your plugin class has a public no-args constructor.")
}

plugin.onLoad()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ class PluginManager(val eocvSim: EOCVSim) {

val logger by loggerForThis()

val superAccessDaemonClient = SuperAccessDaemonClient()
val superAccessDaemonClient by lazy {
SuperAccessDaemonClient(
autoacceptOnTrusted = eocvSim.config.autoAcceptSuperAccessOnTrusted
)
}

private val _loadedPluginHashes = mutableListOf<String>()
val loadedPluginHashes get() = _loadedPluginHashes.toList()
Expand Down Expand Up @@ -270,6 +274,8 @@ class PluginManager(val eocvSim: EOCVSim) {
haltCondition.await()
}

appender.appendln(PluginOutput.SPECIAL_SILENT + "Super access for ${loader.pluginName} v${loader.pluginVersion} was ${if(access) "granted" else "denied"}")

return access
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import java.io.File
import java.lang.Exception
import java.lang.Thread.sleep
import java.net.URI
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.zip.ZipFile
import javax.swing.SwingUtilities
Expand Down Expand Up @@ -73,29 +75,30 @@ object SuperAccessDaemon {

val SUPERACCESS_FILE = PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "superaccess.txt"

private val access = mutableMapOf<String, Boolean>()
private val access = ConcurrentHashMap<String, Boolean>()

@JvmStatic
fun main(args: Array<String>) {
if(args.isEmpty()) {
logger.error("Port is required.")
return
if(args.size < 2) {
logger.error("Usage: <port> <autoAcceptOnTrusted (true/false)>")
exitProcess(-1)
}
if(args.size > 1) {
if(args.size > 2) {
logger.warn("Ignoring extra arguments.")
}

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

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

class WsClient(port: Int) : WebSocketClient(URI("ws://localhost:$port")) {
class WsClient(port: Int, val autoacceptTrusted: Boolean) : WebSocketClient(URI("ws://localhost:$port")) {

private val executor = Executors.newFixedThreadPool(4)

override fun onOpen(p0: ServerHandshake?) {
logger.info("SuperAccessDaemon connection opened")
logger.info("SuperAccessDaemon connection opened.")
logger.info("Autoaccept on trusted: $autoacceptTrusted")
}

override fun onMessage(msg: String) {
Expand Down Expand Up @@ -164,21 +167,32 @@ object SuperAccessDaemon {
warning += "<br><br><i>$reason</i>"
}

// helper function to grant access, avoid code duplication
fun grant() {
SUPERACCESS_FILE.appendText(pluginFile.fileHash() + "\n")
accessGranted(message.id, message.pluginPath)
}

warning += if(validAuthority != null) {
"<br><br>This plugin has been digitally signed by <b>${validAuthority.name}</b>, ensuring its integrity and authenticity.<br><b>${validAuthority.name}</b> is a trusted authority in the EOCV-Sim ecosystem."
"<br><br>This plugin has been digitally signed by <b>${validAuthority.name}</b>.<br>It is a trusted authority in the EOCV-Sim ecosystem."
} else if(untrusted) {
"<br><br>This plugin claims to be made by trusted authority <b>${parser.pluginAuthor}</b>, but it has not been digitally signed by them.<br><h2>Beware of potential security risks.</h2>"
"<br><br>This plugin claims to be made by <b>${parser.pluginAuthor}</b>, but it has not been digitally signed by them.<br><h2>Beware of potential security risks.</h2>"
} else {
GENERIC_LAWYER_YEET
}

warning += "</html>"

if(validAuthority != null && autoacceptTrusted) {
grant()
logger.info("Granted automatic SuperAccess to $name. The plugin has been signed by ${validAuthority.name}")
return
}

SwingUtilities.invokeLater {
SuperAccessRequest(name, warning, validAuthority == null || untrusted) { granted ->
SuperAccessRequest(name, warning, validAuthority == null) { granted ->
if(granted) {
SUPERACCESS_FILE.appendText(pluginFile.fileHash() + "\n")
accessGranted(message.id, message.pluginPath)
grant()
} else {
accessDenied(message.id, message.pluginPath)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,11 @@ private data class AccessCache(
val file: String,
val hasAccess: Boolean,
val timestamp: Long
) {
init {
// get calling class
val stackTrace = Thread.currentThread().stackTrace
val callingClass = stackTrace[2].className

if(callingClass != SuperAccessDaemonClient::class.java.name) {
throw IllegalAccessException("AccessCache should only be created from SuperAccessDaemonClient")
}
}
}
)

class SuperAccessDaemonClient(
val cacheTTLMillis: Long = 3_000
val cacheTTLMillis: Long = 3_000,
autoacceptOnTrusted: Boolean
) {

val logger by loggerForThis()
Expand All @@ -68,7 +59,7 @@ class SuperAccessDaemonClient(
private val accessCache = mutableMapOf<String, AccessCache>()

// create a new WebSocket server
private val server = WsServer(startLock, startCondition)
private val server = WsServer(startLock, startCondition, autoacceptOnTrusted)

fun init() {
server.start()
Expand All @@ -89,10 +80,19 @@ class SuperAccessDaemonClient(
server.broadcast(SuperAccessDaemon.gson.toJson(request))

server.addResponseReceiver(request.id) { response ->
if(response is SuperAccessDaemon.SuperAccessResponse.Success) {
var result = if(response is SuperAccessDaemon.SuperAccessResponse.Success) {
onResponse(true)
true
} else if(response is SuperAccessDaemon.SuperAccessResponse.Failure) {
onResponse(false)
false
} else null

if(result != null) {
synchronized(cacheLock) {
val newCache = AccessCache(request.pluginPath, result, System.currentTimeMillis())
accessCache[request.pluginPath] = newCache
}
}
}
}
Expand Down Expand Up @@ -147,6 +147,7 @@ class SuperAccessDaemonClient(
private class WsServer(
val startLock: ReentrantLock,
val startCondition: Condition,
val autoacceptOnTrusted: Boolean
) : WebSocketServer(InetSocketAddress("127.0.0.1", 0)) {
// create an executor with 1 thread
private val executor = Executors.newSingleThreadExecutor()
Expand Down Expand Up @@ -220,7 +221,7 @@ class SuperAccessDaemonClient(
SuperAccessDaemon::class.java,
JavaProcess.SLF4JIOReceiver(logger),
listOf("-Dlog4j.configurationFile=log4j2_nofile.xml"),
listOf(port.toString())
listOf(port.toString(), autoacceptOnTrusted.toString())
)

if(processRestarts == 6) {
Expand Down
9 changes: 5 additions & 4 deletions EOCV-Sim/src/main/resources/repository.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[repositories]
# Declare the URL of the Maven repositories to use, with a friendly name.
# Declare the URL of the Maven repositories to use, with a key name.
# The URL must preferably end with a slash to be handled correctly.
central = "https://repo.maven.apache.org/maven2/"
jitpack = "https://jitpack.io/"

[plugins]
# Declare the plugin ID and the Maven coordinates of the plugin, similar to how you do it in Gradle.
# (group:artifact:version) which will be used to download the plugin from one of Maven repositories.
# Any dependency that does not have a plugin.toml in its jar will not be considered after download.
# Declare the ID and the Maven coordinates of the plugin (group:artifact:version)
# which will be used to download the plugin from one of Maven repositories specified above.
# Any dependency that does not have a plugin.toml in its jar will not be considered after download.
PaperVision = "org.deltacv.PaperVision:EOCVSimPlugin:1.0.0"

0 comments on commit de7d7a9

Please sign in to comment.