Skip to content

Commit

Permalink
Merge pull request #123 from deltacv/dev
Browse files Browse the repository at this point in the history
v3.8.2
  • Loading branch information
serivesmejia authored Nov 4, 2024
2 parents 2f3ed3f + 5e35615 commit df34e30
Show file tree
Hide file tree
Showing 17 changed files with 452 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ package com.github.serivesmejia.eocvsim.gui.dialog
import com.github.serivesmejia.eocvsim.EOCVSim
import com.github.serivesmejia.eocvsim.gui.dialog.component.BottomButtonsPanel
import com.github.serivesmejia.eocvsim.gui.dialog.component.OutputPanel
import com.github.serivesmejia.eocvsim.util.loggerForThis
import io.github.deltacv.eocvsim.plugin.loader.PluginManager
import io.github.deltacv.eocvsim.plugin.loader.PluginSource
import io.github.deltacv.eocvsim.plugin.repository.PluginRepositoryManager
Expand Down Expand Up @@ -122,6 +123,8 @@ class PluginOutput(

private val mavenOutputPanel = OutputPanel(mavenBottomButtonsPanel)

private val logger by loggerForThis()

init {
output.isModal = true
output.isAlwaysOnTop = true
Expand Down Expand Up @@ -466,6 +469,8 @@ class PluginOutput(
}

tabbedPane.setComponentAt(0, makePluginManagerPanel())
logger.info("Displaying plugin manager dialog")

output.isVisible = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ public static long getMemoryUsageMB() {
return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / MB;
}

public static String loadResStr(String path) throws UnsupportedEncodingException {
return loadIsStr(SysUtil.class.getResourceAsStream(path), Charset.defaultCharset());
}

public static String loadIsStr(InputStream is, Charset charset) throws UnsupportedEncodingException {
return new BufferedReader(new InputStreamReader(is, String.valueOf(charset)))
.lines().collect(Collectors.joining("\n"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ import java.nio.channels.FileLock
*/
class LockFile(pathname: String) : File(pathname) {

private val raf by lazy { RandomAccessFile(this, "rw") }
companion object {
val POR_UNA_NOCHE = try {
SysUtil.loadResStr("/.lock")
} catch(ex: Exception) {
"lock"
}
}

private var raf = RandomAccessFile(this, "rw")

var lock: FileLock? = null
private set
Expand All @@ -30,12 +38,14 @@ class LockFile(pathname: String) : File(pathname) {
true
}

constructor(file: File) : this(file.absolutePath)

init {
if(isDirectory)
throw IllegalArgumentException("Lock file cannot be a directory")

if(!exists())
SysUtil.saveFileStr(this, "")
SysUtil.saveFileStr(this, POR_UNA_NOCHE)
}

/**
Expand All @@ -44,6 +54,8 @@ class LockFile(pathname: String) : File(pathname) {
* @return true if the file was locked, false otherwise
*/
fun tryLock(log: Boolean = true): Boolean {
raf = RandomAccessFile(this, "rw")

return try {
lock = raf.channel.tryLock()
if(log) logger.trace("Probably locked file $absolutePath")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ package com.github.serivesmejia.eocvsim.util.serialization

import com.google.gson.*
import java.lang.reflect.Type

private val gson = Gson()

open class PolymorphicAdapter<T>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import java.util.zip.ZipFile
* ClassLoader for loading classes from a plugin jar file
* @param pluginJar the jar file of the plugin
* @param classpath additional classpath that the plugin may require
* @param pluginContext the plugin context
* @param pluginContextProvider a function that provides the PluginContext for the plugin
*/
class PluginClassLoader(
private val pluginJar: File,
Expand Down Expand Up @@ -96,8 +96,6 @@ class PluginClassLoader(

try {
if (clazz == null) {
var canForName = true

if (!pluginContextProvider().hasSuperAccess) {
var inWhitelist = false

Expand All @@ -109,7 +107,6 @@ class PluginClassLoader(
}

if (!inWhitelist && !pluginContextProvider().hasSuperAccess) {
canForName = false
throw IllegalAccessError("Plugins are not whitelisted to use $name")
}

Expand All @@ -119,31 +116,27 @@ class PluginClassLoader(
if (inWhitelist) continue@blacklistLoop

if (name.contains(blacklistedPackage)) {
canForName = false
throw IllegalAccessError("Plugins are blacklisted to use $name")
}
}

for (blacklistedClass in dynamicLoadingExactMatchBlacklist) {
if (name == blacklistedClass) {
canForName = false
throw IllegalAccessError("Plugins are blacklisted to use $name")
}
}
}

if (canForName) {
clazz = Class.forName(name)
}
clazz = Class.forName(name)
}
} catch(e: Throwable) {
try {
clazz = loadClassStrict(name)
clazz = try {
loadClassStrict(name)
} catch(_: Throwable) {
val classpathClass = classFromClasspath(name)

if(classpathClass != null) {
clazz = classpathClass
classpathClass
} else {
throw e
}
Expand Down Expand Up @@ -200,7 +193,7 @@ class PluginClassLoader(
try {
additionalZipFiles.add(WeakReference(zipFile))
return zipFile.getInputStream(entry)
} catch (e: Exception) {
} catch (_: Exception) {
zipFile.close()
}
} else {
Expand All @@ -226,7 +219,7 @@ class PluginClassLoader(
if (entry != null) {
try {
return URL("jar:file:${file.absolutePath}!/$name")
} catch (e: Exception) {
} catch (_: Exception) {
}
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class PluginManager(val eocvSim: EOCVSim) {

companion object {
val PLUGIN_FOLDER = (EOCVSimFolder + File.separator + "plugins").apply { mkdir() }
val PLUGIN_CACHING_FOLDER = (PLUGIN_FOLDER + File.separator + "caching").apply { mkdir() }
val FILESYSTEMS_FOLDER = (PLUGIN_FOLDER + File.separator + "filesystems").apply { mkdir() }

const val GENERIC_SUPERACCESS_WARN = "Plugins run in a restricted environment by default. <b>SuperAccess will grant full system access. Ensure you trust the authors before accepting.</b>"
Expand Down Expand Up @@ -115,6 +116,8 @@ class PluginManager(val eocvSim: EOCVSim) {
appender.append(PluginOutput.SPECIAL_FREE)
}

appender.appendln(PluginOutput.SPECIAL_SILENT + "Initializing PluginManager")

superAccessDaemonClient.init()

repositoryManager.init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class PluginRepositoryManager(

companion object {
val REPOSITORY_FILE = PluginManager.PLUGIN_FOLDER + File.separator + "repository.toml"
val CACHE_FILE = PluginManager.PLUGIN_FOLDER + File.separator + "cache.toml"
val CACHE_FILE = PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "cache.toml"

val REPOSITORY_TOML_RES = PluginRepositoryManager::class.java.getResourceAsStream("/repository.toml")
val CACHE_TOML_RES = PluginRepositoryManager::class.java.getResourceAsStream("/cache.toml")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@

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

import com.github.serivesmejia.eocvsim.util.io.EOCVSimFolder
import com.github.serivesmejia.eocvsim.util.SysUtil
import com.github.serivesmejia.eocvsim.util.loggerForThis
import com.github.serivesmejia.eocvsim.util.extension.plus
import com.github.serivesmejia.eocvsim.util.io.LockFile
import com.github.serivesmejia.eocvsim.util.io.lockDirectory
import com.moandjiezana.toml.Toml
import io.github.deltacv.eocvsim.plugin.loader.PluginManager
import java.io.File
import java.net.URL
import java.security.KeyFactory
Expand Down Expand Up @@ -55,28 +59,27 @@ object AuthorityFetcher {

const val AUTHORITY_SERVER_URL = "https://raw.githubusercontent.com/deltacv/Authorities/refs/heads/master"

fun sectionRegex(name: String) = Regex("\\[\\Q$name\\E](?:\\n[^\\[]+)*")
private val AUTHORITIES_FILE = PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "authorities.toml"
private val AUTHORITIES_LOCK_FILE = LockFile(PluginManager.PLUGIN_CACHING_FOLDER + File.separator + "authorities.lock")

private val AUTHORITIES_FILE = File(EOCVSimFolder, "authorities.toml")
private val AUTHORITIES_LOCK_FILE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3)

private val TTL_DURATION_MS = TimeUnit.HOURS.toMillis(8)

private val logger by loggerForThis()
private val cache = mutableMapOf<String, CachedAuthority>()

fun fetchAuthority(name: String): Authority? {
// Check if the authority is cached and valid
validateCache()

// Check if the authority is cached and the file is valid
cache[name]?.let { cachedAuthority ->
if (System.currentTimeMillis() - cachedAuthority.fetchedTime < TTL_DURATION_MS) {
logger.info("Returning cached authority for $name")
return cachedAuthority.authority
} else {
logger.info("Cached authority for $name has expired")
}
logger.info("Returning cached authority for $name")
return cachedAuthority.authority
}

// Load authorities from file if it exists
if (AUTHORITIES_FILE.exists()) {
if (AUTHORITIES_FILE.exists() && tryLockAuthoritiesFile()) {
try {
val authoritiesToml = Toml().read(AUTHORITIES_FILE)
val authorityData = authoritiesToml.getTable(name)
Expand All @@ -98,6 +101,8 @@ object AuthorityFetcher {
}
}

AUTHORITIES_LOCK_FILE.unlock()

// Fetch the authority from the server
val authorityUrl = "${AUTHORITY_SERVER_URL.trim('/')}/$name"
return try {
Expand All @@ -119,19 +124,41 @@ object AuthorityFetcher {
}
}

private fun validateCache() {
if(!tryLockAuthoritiesFile()) {
return
}

val currentTime = System.currentTimeMillis()

if(!AUTHORITIES_FILE.exists()) {
SysUtil.saveFileStr(AUTHORITIES_FILE, "timestamp = $currentTime\n")
}

val authoritiesToml = Toml().read(AUTHORITIES_FILE)
val timestamp = authoritiesToml.getLong("timestamp")

if(currentTime - timestamp > TTL_DURATION_MS) {
AUTHORITIES_FILE.delete()
logger.info("Authorities file has expired, clearing cache")
cache.clear()
}

AUTHORITIES_LOCK_FILE.unlock()
}

private fun saveAuthorityToFile(name: String, publicKey: String) {
if(!tryLockAuthoritiesFile()) {
return
}

try {
val sb = StringBuilder()

// Load existing authorities if the file exists
if (AUTHORITIES_FILE.exists()) {
val existingToml = AUTHORITIES_FILE.readText()

sb.append(if(existingToml.contains("[$name]")) {
existingToml.replace(sectionRegex(name), "")
} else {
existingToml
})
sb.append(existingToml)
}

// Append new authority information
Expand All @@ -140,10 +167,28 @@ object AuthorityFetcher {
sb.appendLine("timestamp = ${System.currentTimeMillis()}")

// Write the updated content to the file
AUTHORITIES_FILE.appendText(sb.toString())
SysUtil.saveFileStr(AUTHORITIES_FILE, sb.toString())
} catch (e: Exception) {
logger.error("Failed to save authority to file", e)
} finally {
AUTHORITIES_LOCK_FILE.unlock()
}
}

private fun tryLockAuthoritiesFile(): Boolean {
val time = System.currentTimeMillis()

logger.info("Trying to lock authorities file")

while(!AUTHORITIES_LOCK_FILE.tryLock(false) && System.currentTimeMillis() - time < AUTHORITIES_LOCK_FILE_TIMEOUT_MS) {
Thread.sleep(100)
}

if(!AUTHORITIES_LOCK_FILE.isLocked) {
logger.warn("Failed to lock authorities file")
}

return AUTHORITIES_LOCK_FILE.isLocked
}

fun parsePem(pem: String) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ 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 io.github.deltacv.eocvsim.plugin.loader.PluginManager
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
Expand Down Expand Up @@ -71,7 +72,7 @@ object SuperAccessDaemon {
class Failure(id: Int) : SuperAccessResponse(id)
}

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

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

Expand Down
Loading

0 comments on commit df34e30

Please sign in to comment.