From 2611ecb265f08325976b3e62f93531b45b0b946a Mon Sep 17 00:00:00 2001 From: payonel Date: Mon, 5 Nov 2018 23:58:58 -0800 Subject: [PATCH 1/2] new filesystem device feature, locked mode A locked filesystem is readonly (in either managed or unmanaged modes) It cannot be unlocked unless its mode is switched or it is recrafted - both actions wipe the drive. The data is thus "locked" or protected unless the drive is wiped. The player's displace name is also recorded and shown in tooltips on the device to indicate who locked it. In this manner, data authenticity can be trusted closes #2138 --- .../assets/opencomputers/lang/en_US.lang | 3 ++ .../opencomputers/textures/gui/drive.png | Bin 326 -> 764 bytes src/main/scala/li/cil/oc/Localization.scala | 6 ++++ .../scala/li/cil/oc/client/PacketSender.scala | 6 ++++ .../scala/li/cil/oc/client/gui/Drive.scala | 18 ++++++++---- .../scala/li/cil/oc/common/PacketType.scala | 1 + .../cil/oc/common/item/data/DriveData.scala | 16 +++++++++-- .../common/item/traits/FileSystemLike.scala | 5 +++- .../opencomputers/DriverFileSystem.scala | 7 +++-- .../li/cil/oc/server/PacketHandler.scala | 26 ++++++++++++++++-- .../li/cil/oc/server/component/Drive.scala | 5 +++- .../li/cil/oc/server/fs/FileSystem.scala | 19 +++++++++++++ 12 files changed, 99 insertions(+), 13 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index bff478316..daf682cf5 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -203,6 +203,8 @@ oc:gui.Chat.WarningRecipes=There were errors loading one or more recipes. Some i oc:gui.Chat.WarningSimpleComponent=An addon (yours?) using the §aSimpleComponent§f interface did §esomething wrong§f. Component logic could not be injected. Please check your log file for more information. oc:gui.Drive.Managed=Managed oc:gui.Drive.Unmanaged=Unmanaged +oc:gui.Drive.ReadOnlyLock=Lock +oc:gui.Drive.ReadOnlyLockWarning=§lRead Only§r lock. Cannot be removed unless the drive is wiped. oc:gui.Drive.Warning=§lWarning§r: switching modes will result in a loss of all data currently stored on the disk! oc:gui.Error.ComponentOverflow=Too many components connected to the computer. oc:gui.Error.InternalError=Internal error, please see the log file. This is probably a bug. @@ -289,6 +291,7 @@ oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7. oc:tooltip.DiskDrive=Allows reading and writing floppies. Can be installed in robots to allow inserting floppies later on. oc:tooltip.DiskDriveMountable=Provides the same functionality as a normal disk drive, but must be installed in a rack. oc:tooltip.DiskUsage=Disk usage: %s/%s Byte +oc:tooltip.DiskLocked=Locked by: %s oc:tooltip.DiskModeManaged=Mode: Managed oc:tooltip.DiskModeUnmanaged=Mode: Unmanaged oc:tooltip.Drone=Drones are light-weight, fast reconnaissance units with limited cargo space. diff --git a/src/main/resources/assets/opencomputers/textures/gui/drive.png b/src/main/resources/assets/opencomputers/textures/gui/drive.png index 124e3e294b7b52a3b5f0357d52efacc0972f62bc..1f86630b7049ab3248122f56ca919c333bcfafb6 100644 GIT binary patch literal 764 zcmeAS@N?(olHy`uVBq!ia0vp^8-O^UgAGXf-1k}nq*#ibJVQ8upoSx*gMoo*v!{z= zNX4ADcOCO)Cy2CO{O*2l%3e?Xmf8cGUL08>c2r_}(Bal%x6m4P$G;+5FLqykwSA+4 z^X&hLGVXsTE!-ORHRJp0Bi=Liy3^7|K9k|AIlZLeJl9( z{EojJ7euUno8^Nk?VIht)#U|4O_;QuakyPTT z{C)R58z}AmZh!pxRqxA}e|c7?Qt|WMlnHJJT!alSviO)V3j0!%`F7K{M_;R=|5Tj1 zec}A~!x!}VJ4<)npLlR%jmU?4Nh12QneRpS{C_O&xw(EelV4}xp68#<9!!xqTJ5)* zarqIAd!K*(*ey`q4HW+tcmPD_@Kxj+{<WKNRyU$p{VI&%n9+7Vm=u`P0DU%;4$j=d#Wzp$PyY>1*f! literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^8-O^JgBeKPdoV8+NJ*BsMwA5Sr==;w|347@4-E|kl2Q|Xi35e$N`m}?fn1=} z=KV|d14VXtx;TbZ+A&!Mg>TEAF-)+L(v4@eS91$JH*;0jsqAw) zg+8C+ChA)(J5&3dnJ?ji?4O@!ciU9$n}1;L-b#k;-{cPL-D|yLXE}5E_kYc|tNR~Z z+x?c|-QMo ItemStack) extends GuiScreen with traits.Window { - override val windowHeight = 85 + override val windowHeight = 120 override def backgroundImage = Textures.guiDrive protected var managedButton: ImageButton = _ protected var unmanagedButton: ImageButton = _ + protected var lockedButton: ImageButton = _ protected override def actionPerformed(button: GuiButton) { if (button.id == 0) { ClientPacketSender.sendDriveMode(false) - } - if (button.id == 1) { + } else if (button.id == 1) { ClientPacketSender.sendDriveMode(true) + } else if (button.id == 2) { + ClientPacketSender.sendDriveLock() } } @@ -30,18 +32,24 @@ class Drive(playerInventory: InventoryPlayer, val driveStack: () => ItemStack) e super.initGui() managedButton = new ImageButton(0, guiLeft + 11, guiTop + 11, 74, 18, Textures.guiButtonDriveMode, text = Localization.Drive.Managed, textColor = 0x608060, canToggle = true) unmanagedButton = new ImageButton(1, guiLeft + 91, guiTop + 11, 74, 18, Textures.guiButtonDriveMode, text = Localization.Drive.Unmanaged, textColor = 0x608060, canToggle = true) + lockedButton = new ImageButton(2, guiLeft + 11, guiTop + windowHeight - 42, 44, 18, Textures.guiButtonDriveMode, text = Localization.Drive.ReadOnlyLock, textColor = 0x608060, canToggle = true) add(buttonList, managedButton) add(buttonList, unmanagedButton) + add(buttonList, lockedButton) } override def updateScreen(): Unit = { - unmanagedButton.toggled = new DriveData(driveStack()).isUnmanaged + val data = new DriveData(driveStack()) + unmanagedButton.toggled = data.isUnmanaged managedButton.toggled = !unmanagedButton.toggled + lockedButton.toggled = data.isLocked + lockedButton.enabled = !data.isLocked super.updateScreen() } override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = { super.drawScreen(mouseX, mouseY, dt) - fontRendererObj.drawSplitString(Localization.Drive.Warning, guiLeft + 7, guiTop + 37, xSize - 16, 0x404040) + fontRendererObj.drawSplitString(Localization.Drive.Warning, guiLeft + 11, guiTop + 37, xSize - 20, 0x404040) + fontRendererObj.drawSplitString(Localization.Drive.LockWarning, guiLeft + 61, guiTop + windowHeight - 48, xSize - 68, 0x404040) } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index 804f245e6..4a260d41a 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -73,6 +73,7 @@ object PacketType extends Enumeration { // Client -> Server ComputerPower, CopyToAnalyzer, + DriveLock, DriveMode, DronePower, KeyDown, diff --git a/src/main/scala/li/cil/oc/common/item/data/DriveData.scala b/src/main/scala/li/cil/oc/common/item/data/DriveData.scala index 8b81d97ea..7b96ecdb2 100644 --- a/src/main/scala/li/cil/oc/common/item/data/DriveData.scala +++ b/src/main/scala/li/cil/oc/common/item/data/DriveData.scala @@ -11,12 +11,24 @@ class DriveData extends ItemData(null) { } var isUnmanaged = false + var lockInfo: String = "" + + def isLocked: Boolean = { + lockInfo != null && !lockInfo.isEmpty + } + + private val UnmanagedKey = Settings.namespace + "unmanaged" + private val LockKey = Settings.namespace + "lock" override def load(nbt: NBTTagCompound) { - isUnmanaged = nbt.getBoolean(Settings.namespace + "unmanaged") + isUnmanaged = nbt.getBoolean(UnmanagedKey) + lockInfo = if (nbt.hasKey(LockKey)) { + nbt.getString(LockKey) + } else "" } override def save(nbt: NBTTagCompound) { - nbt.setBoolean(Settings.namespace + "unmanaged", isUnmanaged) + nbt.setBoolean(UnmanagedKey, isUnmanaged) + nbt.setString(LockKey, lockInfo) } } diff --git a/src/main/scala/li/cil/oc/common/item/traits/FileSystemLike.scala b/src/main/scala/li/cil/oc/common/item/traits/FileSystemLike.scala index 9fc490cd5..99547dd25 100644 --- a/src/main/scala/li/cil/oc/common/item/traits/FileSystemLike.scala +++ b/src/main/scala/li/cil/oc/common/item/traits/FileSystemLike.scala @@ -6,6 +6,7 @@ import li.cil.oc.Localization import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.common.GuiType +import li.cil.oc.common.item.data.DriveData import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.world.World @@ -31,7 +32,9 @@ trait FileSystemLike extends Delegate { } } } - tooltip.add(Localization.Tooltip.DiskMode(nbt.getBoolean(Settings.namespace + "unmanaged"))) + val data = new DriveData(stack) + tooltip.add(Localization.Tooltip.DiskMode(data.isUnmanaged)) + tooltip.add(Localization.Tooltip.DiskLock(data.lockInfo)) } super.tooltipLines(stack, player, tooltip, advanced) } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala index fd2e1e5e5..6beca98b5 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala @@ -70,10 +70,13 @@ object DriverFileSystem extends Item { val sound = Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access") val drive = new DriveData(stack) val environment = if (drive.isUnmanaged) { - new Drive(capacity max 0, platterCount, label, Option(host), Option(sound), speed) + new Drive(capacity max 0, platterCount, label, Option(host), Option(sound), speed, drive.isLocked) } else { - val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity max 0, Settings.get.bufferChanges) + var fs = oc.api.FileSystem.fromSaveDirectory(address, capacity max 0, Settings.get.bufferChanges) + if (drive.isLocked) { + fs = oc.api.FileSystem.asReadOnly(fs) + } oc.api.FileSystem.asManagedEnvironment(fs, label, host, sound, speed) } if (environment != null && environment.node != null) { diff --git a/src/main/scala/li/cil/oc/server/PacketHandler.scala b/src/main/scala/li/cil/oc/server/PacketHandler.scala index c350153d2..fdee66cd7 100644 --- a/src/main/scala/li/cil/oc/server/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/server/PacketHandler.scala @@ -35,6 +35,7 @@ object PacketHandler extends CommonPacketHandler { p.packetType match { case PacketType.ComputerPower => onComputerPower(p) case PacketType.CopyToAnalyzer => onCopyToAnalyzer(p) + case PacketType.DriveLock => onDriveLock(p) case PacketType.DriveMode => onDriveMode(p) case PacketType.DronePower => onDronePower(p) case PacketType.KeyDown => onKeyDown(p) @@ -86,13 +87,34 @@ object PacketHandler extends CommonPacketHandler { } } - def onDriveMode(p: PacketParser) = p.player match { + def onDriveLock(p: PacketParser) = p.player match { case player: EntityPlayerMP => Delegator.subItem(player.getHeldItem) match { case Some(drive: FileSystemLike) => val data = new DriveData(player.getHeldItem) - data.isUnmanaged = p.readBoolean() + data.lockInfo = player.getDisplayName match { + case name: String if name != null && !name.isEmpty => name + case _ => "notch" // meaning: "unknown" + } data.save(player.getHeldItem) + case _ => // Invalid packet + } + case _ => // Invalid Packet + } + + def onDriveMode(p: PacketParser) = p.player match { + case player: EntityPlayerMP => + val heldItem = player.getHeldItem + Delegator.subItem(heldItem) match { + case Some(drive: FileSystemLike) => + val data = new DriveData(heldItem) + val newIsUnmanaged = p.readBoolean() + if (data.isUnmanaged != newIsUnmanaged) { + fs.FileSystem.removeAddress(heldItem) + data.lockInfo = "" + } + data.isUnmanaged = newIsUnmanaged + data.save(heldItem) case _ => // Invalid packet. } case _ => // Invalid packet. diff --git a/src/main/scala/li/cil/oc/server/component/Drive.scala b/src/main/scala/li/cil/oc/server/component/Drive.scala index 3d44eab6a..0dfd5ed1d 100644 --- a/src/main/scala/li/cil/oc/server/component/Drive.scala +++ b/src/main/scala/li/cil/oc/server/component/Drive.scala @@ -28,7 +28,7 @@ import net.minecraftforge.common.DimensionManager import scala.collection.convert.WrapAsJava._ -class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Option[EnvironmentHost], val sound: Option[String], val speed: Int) extends prefab.ManagedEnvironment with DeviceInfo { +class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Option[EnvironmentHost], val sound: Option[String], val speed: Int, val isLocked: Boolean) extends prefab.ManagedEnvironment with DeviceInfo { override val node = Network.newNode(this, Visibility.Network). withComponent("drive", Visibility.Neighbors). withConnector(). @@ -74,6 +74,7 @@ class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Op @Callback(doc = """function(value:string):string -- Sets the label of the drive. Returns the new value, which may be truncated.""") def setLabel(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { + if (isLocked) throw new Exception("drive is read only") if (label == null) throw new Exception("drive does not support labeling") if (args.checkAny(0) == null) label.setLabel(null) else label.setLabel(args.checkString(0)) @@ -101,6 +102,7 @@ class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Op @Callback(direct = true, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""") def writeSector(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { + if (isLocked) throw new Exception("drive is read only") context.consumeCallBudget(writeSectorCosts(speed)) val sectorData = args.checkByteArray(1) val sector = moveToSector(context, checkSector(args, 0)) @@ -120,6 +122,7 @@ class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Op @Callback(direct = true, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""") def writeByte(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { + if (isLocked) throw new Exception("drive is read only") context.consumeCallBudget(writeByteCosts(speed)) val offset = args.checkInteger(0) - 1 val value = args.checkInteger(1).toByte diff --git a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala index 151cc3bb3..859d28834 100755 --- a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala @@ -11,6 +11,8 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.fs.Label import li.cil.oc.api.network.EnvironmentHost +import li.cil.oc.common.item.Delegator +import li.cil.oc.common.item.traits.FileSystemLike import li.cil.oc.integration.Mods import li.cil.oc.integration.computercraft.DriverComputerCraftMedia import li.cil.oc.server.component @@ -112,6 +114,23 @@ object FileSystem extends api.detail.FileSystemAPI { else null } + def removeAddress(fsStack: ItemStack): Boolean = { + Delegator.subItem(fsStack) match { + case Some(drive: FileSystemLike) => { + val data = li.cil.oc.integration.opencomputers.Item.dataTag(fsStack) + if (data.hasKey("node")) { + val nodeData = data.getCompoundTag("node") + if (nodeData.hasKey("address")) { + nodeData.removeTag("address") + return true + } + } + } + case _ => + } + false + } + def fromMemory(capacity: Long): api.fs.FileSystem = new RamFileSystem(capacity) def fromComputerCraft(mount: AnyRef): api.fs.FileSystem = From 4849ca425c366844c475b421acf6909a5e08e8bf Mon Sep 17 00:00:00 2001 From: payonel Date: Tue, 6 Nov 2018 00:13:33 -0800 Subject: [PATCH 2/2] lock only with player, and stop lock overwrite --- src/main/scala/li/cil/oc/server/PacketHandler.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/li/cil/oc/server/PacketHandler.scala b/src/main/scala/li/cil/oc/server/PacketHandler.scala index a539aab78..e5028e2ca 100644 --- a/src/main/scala/li/cil/oc/server/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/server/PacketHandler.scala @@ -100,11 +100,13 @@ object PacketHandler extends CommonPacketHandler { Delegator.subItem(heldItem) match { case Some(drive: FileSystemLike) => val data = new DriveData(heldItem) - data.lockInfo = player.getDisplayName match { - case name: String if name != null && !name.isEmpty => name - case _ => "notch" // meaning: "unknown" + if (!data.isLocked) { + data.lockInfo = player.getName match { + case name: String if name != null && !name.isEmpty => name + case _ => "notch" // meaning: "unknown" + } + data.save(heldItem) } - data.save(heldItem) case _ => // Invalid packet } case _ => // Invalid Packet