├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .vs ├── opencomputer-security-system │ ├── FileContentIndex │ │ └── read.lock │ └── v17 │ │ └── .wsuo └── slnx.sqlite ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── doorsetup ├── door.lua └── finish.lua ├── modules.txt ├── permissions.txt ├── remotecontrol └── main.lua ├── sectors ├── Database Module │ └── Main.lua ├── Server Module │ └── sectors.lua ├── sectorcontrol.lua └── sectorcontrolgui.lua ├── security ├── Database Module │ ├── Main.lua │ ├── Pass.lua │ └── User.lua ├── Server Module │ └── security.lua ├── autoinstaller.lua ├── diagnostic.lua ├── doorControl.lua ├── quikidlink.lua └── securityAPI.lua └── whattodo.txt /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | What should it be doing? 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Mod versions:** 27 | -Open Computers version: # 28 | -Open Security version: # 29 | 30 | **Other Mods (optional in case it's being used as part of a system** 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | .vs/VSWorkspaceState.json 4 | .vs/slnx.sqlite 5 | .vs/opencomputer-security-system/v17/.wsuo 6 | *.sqlite 7 | *.vsidx 8 | *.sqlite 9 | .vs/slnx.sqlite 10 | .vs/opencomputer-security-system/v17/.wsuo 11 | .vs/opencomputer-security-system/FileContentIndex/9d9cebae-4c71-423c-bb87-e5d813dec504.vsidx 12 | -------------------------------------------------------------------------------- /.vs/opencomputer-security-system/FileContentIndex/read.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/731bf46fc76339673a55b87a03d83d6ccc009c3a/.vs/opencomputer-security-system/FileContentIndex/read.lock -------------------------------------------------------------------------------- /.vs/opencomputer-security-system/v17/.wsuo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/731bf46fc76339673a55b87a03d83d6ccc009c3a/.vs/opencomputer-security-system/v17/.wsuo -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/731bf46fc76339673a55b87a03d83d6ccc009c3a/.vs/slnx.sqlite -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "githubPullRequests.ignoredPullRequestBranches": [ 3 | "main" 4 | ] 5 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | If you wish to contribute, there are a few things to remember 2 | 1. Minor changes that don't really affect every single program change the third number (2.2.1 goes to 2.2.2) This means that all numbers are compatable with eachother (a 2.2.0 server works with a 2.2.2 door) 3 | 2. Major changes that cause every device to need an update or be on the same version need the second number changed (2.2.1 goes to 2.3.0) 4 | 3. Version changes to the door control likely need a version checking update in the diagnostic tablet. I'll be happy enough to do this part for you however, so it isn't that important. 5 | 4. The autoinstaller and anything that downloads code from the web download from the main branch, so if you are testing a doorcontrol and autoinstaller update, you will have to wget the new code yourself afterward 6 | 7 | In order to contribute, you just have to fork the repository, make the necessary changes, and when you think it's good enough, pull request in. 8 | I will fix or perform changes in the following conditions: 9 | 1. Diagnostic tablet versioning (if you don't make any changes to the diagnostic tablet, I'll add the version number myself) 10 | 2. The bug is minor enough that I can easilly spot it 11 | 12 | I will not fix or do changes myself on the following: 13 | 1. You need help coding a certain part of the program 14 | 2. The bug is very well hidden (eg: I cannot see the problem easily) 15 | 16 | I might add more to this later when I figure out what else I need. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # opensecurity-security-system 2 | 3 | A Fully fleshed out Security System solution for OpenComputers and OpenSecurity using the servertine system. 4 | 5 | Featuring... 6 | 17 | 18 | If you have used this before, you may be wondering, "what's servertine?" I split up the server and database from the security system and am making them into a new project called "Servertine", which is a powerful system you can create powerful modules for and easilly connect to them using the servertine API. They also support other features like the range extender. The reason being for this is an API I can easilly build more programs off of and ease of updating the existing passes system. The move to a modular system brings no drawbacks to the system as well. 19 | 20 | Download servertine here 21 | Join the Servertine discord 22 | 23 | I will be making a full video tutorial series soon. Channel is here 24 | 25 | ----Server: The brain of the system. Install the security module onto the servertine server and keep it running and everything is handled for you! it stores user data as well as pass data and handles the logic for doorcontrol systems. 26 | 27 | ----Database: Where you modify the system parameters. Install the Servertine Database on MineOS and install the security module and manage users, passes, and such with ease and speed. 28 | 29 | ----Door Control: Control security door and redstone from these convenient door systems! Easy to set up and easy to change settings with, these really have it all. 30 | 31 | Autoinstaller setup: Run the command "pastebin run cP70MhB0" and follow the prompts. Syncs nicely with the accelerated door setup program on the diagnostic tablet to allow for scanning of the doors and readers instead of copying the uuid with an analyzer. 32 | 33 | Door Setup module setup: Setup the passes and simple settings on the database, install the stuff onto a drive, and finish on the computer. 34 | 35 | ----Autoinstaller: Install the doors with ths simple autoinstaller! Just follow the prompts 36 | 37 | pastebin run cP70MhB0 38 | 39 | ----Diagnostic tablet: A program with a whole bunch of programs to make door setup, management, and more easier 40 | 41 | Diagnostics: a special program that works with the new admin card to get info about a door and it's settings and if it works. It is best used with a tablet that has a tier 2 gpu, a wireless modem, and an internet card. When the admin card is scanned, it sends all the info of the computer to the tablet. It's most noteable use is with the multidoor computer, as it tells you if that magnetic card reader is connected to a door, what the key of the door is (if you want to edit door settings after first set up) and more. 42 | 43 | Accelerated door setup program to put on a tablet. This helps accelerate multi-door setup time, as it is portable compared to moving back and forth between the pc and the door. Also, if your tablet has an analyzer with it, you can scan the blocks with the tablet instead of just entering the uuid manually 44 | 45 | Door editing: Lets you edit doors with amazing ease. Just swipe the door with an admin card and change settings, add/delete doors, and more. Is a major game changer compared to autoinstaller door editing. 46 | 47 | Remote Control: Open and close doors from any distance without having to swipe cards. You get access to every single door linked to the server. This also lets you open doors contrary to what the settings are set to for the door, like toggling doors that would normally be delayed. 48 | 49 | ----Security API is a modified version of the Servertine API, with locked data that is sent to the server, ability to check passes from a card that is swiped, and get and set variables in user accounts (if string) 50 | 51 | ----Optional modules for more functionality 52 | 53 | Sector system- Give doors groups which you can manage with the sector control computer. Lock doors open or lock them shut and let certain passes either bypass these or turn them off. 54 | 55 | If you have any questions, don't hesitate to ask! 56 | 57 | Tutorial playlist here (older videos may be outdated) 58 | 59 | ![2022-03-31_18 17 37](https://user-images.githubusercontent.com/75097681/161160569-b7cc527d-f03e-4b8a-8c1c-ba9df040ddf7.png) 60 | ![2022-03-31_18 17 25](https://user-images.githubusercontent.com/75097681/161160580-5213b4f9-2f69-4f06-ae74-f48a20d6c1c4.png) 61 | ![image](https://user-images.githubusercontent.com/75097681/153966774-ddea0e15-01ef-47db-a975-8f0b3b63fed0.png) 62 | 63 | Changelog: Before splitting off 64 | 82 | 83 | Seperate Changelogs (Using format on website of incrementing it by a digit) 84 | 85 | Security: 86 |
    87 |
  1. Setup module on website (right before version 4.0.0 on above changelog)
  2. 88 |
  3. Biometrics, unblocked some extra features, pretty much update 4.0.0
  4. 89 |
  5. Minor bug fix for callback int on certain buttons
  6. 90 |
  7. Split module into multiple files and such (exact same as version 4.0.2)
  8. 91 |
  9. Accidental duplication of previous update (whoops)
  10. 92 |
  11. Fixed rcdoors command sending every device even if not a doorsystem. Added sector control program to the diagnostic tablet. Readded the ability to change readers using runtime door editing
  12. 93 |
94 | Sector: 95 |
    96 |
  1. Setup module on website (right before version 4.0.0 on above changelog)
  2. 97 |
  3. Sector control overhaul (Exact same as update version 4.0.0)
  4. 98 |
  5. Updated to support latest Security module version (exact same as update version 4.0.2)
  6. 99 |
  7. Accidental duplication of previous update (what is wrong with meeee)
  8. 100 |
101 | Door Editing: 102 |
    103 |
  1. Setup module on website (right before version 4.0.0 on above changelog)
  2. 104 |
  3. Fixed a bug with path towards the finish.lua (finishing program) file
  4. 105 |
  5. Progress is saved when switching modules from this one, updating finish.lua to work with biometrics, etc. (Exact same as version 4.0.0)
  6. 106 |
  7. Updated to support latest Security module version (exact same as update version 4.0.2)
  8. 107 |
  9. Hotfixed loadTable function to use compat file rather than built in one (which didn't support OpenOS)
  10. 108 |
  11. Added the ability to reset the progress in case you need it. Databackup also resets if you export the door.
  12. 109 |
110 | Remote Control: 111 |
    112 |
  1. Released Remote Control!
  2. 113 |
114 | 115 | Queued updates: 116 |
    117 |
  1. none queued yet
  2. 118 |
119 | 120 | Future updates: 121 |
    122 |
  1. none queued yet
  2. 123 |
124 | 125 | Important information: 126 | If you have anything you would like to try adding yourself, feel free to add whatever you want to the code and pull request it into the main branch. I can then check if it's a worthwhile update and merge. 127 | -------------------------------------------------------------------------------- /doorsetup/finish.lua: -------------------------------------------------------------------------------- 1 | --The program installed on a drive by the doorsetup module to finish up setup on the pc 2 | local component = require("component") 3 | local term = require("term") 4 | local io = require("io") 5 | local ser = require("serialization") 6 | local fs = require("filesystem") 7 | local shell = require("shell") 8 | local event = require("event") 9 | local uuid = require("uuid") 10 | local thread = require("thread") 11 | local modem = component.modem 12 | local link 13 | local modemPort = 1000 14 | local syncPort = 199 15 | local diagPort = 180 16 | 17 | local program = "ctrl.lua" 18 | local settingFileName = "doorSettings.txt" 19 | local configFileName = "extraConfig.txt" 20 | local doorCode = "https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/security/doorControl.lua" 21 | 22 | local settingData = {} 23 | local randomNameArray = {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "a", "s", "d", "f", "g", "h", "j", "k", "l", "z", "x", "c", "v", "b", "n", "m"} 24 | local commandArray = {"getInput","analyzer","clearTerm","terminate","advanalyzer"} 25 | 26 | local query = {["num"]=0} 27 | local editorSettings = {} 28 | 29 | local function saveTable(table, location) 30 | --saves a table to a file 31 | local tableFile = assert(io.open(location, "w")) 32 | tableFile:write(ser.serialize(table)) 33 | tableFile:close() 34 | end 35 | local function loadTable(location) 36 | --returns a table stored in a file. 37 | local tableFile = assert(io.open(location)) 38 | return ser.unserialize(tableFile:read("*all")) 39 | end 40 | 41 | local function send(label,port,linker,...) 42 | if linker and link ~= nil then 43 | link.send(modem.address,...) 44 | return 45 | end 46 | if label then 47 | modem.send(label,port,...) 48 | else 49 | modem.broadcast(port,...) 50 | end 51 | end 52 | 53 | local function sendMsg(...) 54 | local arg = table.pack(...) 55 | for i=1,#arg,1 do 56 | local argType = type(arg[i]) 57 | if editorSettings.accelerate == true then 58 | if argType == "string" then 59 | send(editorSettings.from,editorSettings.port,false,"print",arg[i]) 60 | elseif argType == "number" then 61 | send(editorSettings.from,editorSettings.port,false,commandArray[arg[i]]) 62 | if arg[i] < 3 then 63 | local e, _, _, _, _, text = event.pull("modem_message") 64 | return text 65 | end 66 | if arg[i] == 4 then 67 | print("terminated connection") 68 | end 69 | if arg[i] == 5 then 70 | local wait = true 71 | local distable = {} 72 | while wait do 73 | local e, _, _, _, _, text = event.pull("modem_message") 74 | if text == "finished" then 75 | return distable 76 | else 77 | table.insert(distable,text) 78 | end 79 | end 80 | end 81 | else 82 | send(editorSettings.from,editorSettings.port,false,"print","potential error in code for sendMsg") 83 | end 84 | else 85 | if argType == "string" then 86 | print(arg[i]) 87 | elseif argType == "number" then 88 | if arg[i] == 1 then 89 | local text = term.read() 90 | return text:sub(1,-2) 91 | elseif arg[i] == 2 then 92 | return "nil" 93 | elseif arg[i] == 3 then 94 | term.clear() 95 | elseif arg[i] == 4 then 96 | print("Finished editing.") 97 | elseif arg[i] == 5 then 98 | local wait = true 99 | local distable = {} 100 | while wait do 101 | local text = term.read() 102 | text = text:sub(1,-2) 103 | if text == "" then 104 | return distable 105 | else 106 | table.insert(distable,text) 107 | end 108 | end 109 | else 110 | print("potential error in code for sendMsg") 111 | end 112 | end 113 | end 114 | end 115 | return true 116 | end 117 | 118 | term.clear() 119 | print("Checking for finishing file...") 120 | local finishTable = loadTable("finishSettings.txt") 121 | if finishTable == nil then 122 | print("Error getting table") 123 | os.exit() 124 | end 125 | print("Success...") 126 | modemPort = finishTable.config.port 127 | modem.close() 128 | if component.isAvailable("tunnel") then 129 | link = component.tunnel 130 | end 131 | 132 | print("Sending query to server...") 133 | if link == nil then 134 | modem.open(modemPort) 135 | end 136 | send(nil,modemPort,true,"getquery",ser.serialize({"passSettings","sectors","&&&crypt"})) 137 | local e,_,from,port,_,msg = event.pull(3,"modem_message") 138 | if e == nil then 139 | print("No query received. Assuming old server system is in place and will not work.") 140 | os.exit() 141 | end 142 | print("Query received") 143 | query = ser.unserialize(msg) 144 | if query.num ~= 3 then 145 | print("Security server is not valid. Must be 3.0.0 and up") 146 | os.exit() 147 | end 148 | editorSettings.x = 2 149 | editorSettings.num = query.num 150 | editorSettings.version = query.version 151 | editorSettings.hassector = query.data.sectors ~= nil 152 | editorSettings.settings = query.data.passSettings 153 | editorSettings.settings.sectors = query.data.sectors 154 | editorSettings.scanner = false 155 | editorSettings.accelerate = false 156 | editorSettings.single = false 157 | term.clear() 158 | local text = sendMsg("Would you like to use an external device for accelerated setup?","This makes it easier to set up doors without having to move from the door to the pc constantly.","It requires a diagnostic tablet (found on github)","1 for yes, 2 for no",1) 159 | if tonumber(text) == 1 then 160 | modem.open(diagPort) 161 | modem.close(modemPort) 162 | sendMsg("Start up accelerated door setup on your diagnostic tablet","in 60 seconds with no changes the program will close") 163 | 164 | local time = 0 165 | local timer = function(seconds) 166 | time = seconds 167 | for i=1,seconds, 1 do 168 | os.sleep(1) 169 | time = time - 1 170 | end 171 | end 172 | local waiter = true 173 | local e, _, from, port, _, msg, barcode, t 174 | t = thread.create(timer) --setup incorrect 175 | while waiter do 176 | e, _, from, port, _, msg, barcode = event.pull(time, "modem_message") 177 | if e then 178 | if msg == "accsetup" then 179 | waiter = false 180 | end 181 | else 182 | waiter = false 183 | end 184 | end 185 | 186 | if e then 187 | if link == nil then 188 | modem.open(modemPort) 189 | end 190 | t:kill() 191 | send(from,port,false,"connected") 192 | term.clear() 193 | sendMsg("Connection successful! All prompts will be on the tablet now on.") 194 | os.sleep(1) 195 | editorSettings.scanner = barcode 196 | editorSettings.accelerate = true 197 | editorSettings.from = from 198 | editorSettings.port = port 199 | else 200 | modem.close(diagPort) 201 | print("Setup cancelled") 202 | os.exit() 203 | end 204 | else 205 | print("normal setup initiating") 206 | end 207 | editorSettings.type = "doorsystem" 208 | os.execute("wget -f " .. doorCode .. " " .. program) 209 | editorSettings.x = tonumber(sendMsg("Would you like to use the simple pass setup or new advanced one?","1 for simple, 2 for advanced",1)) 210 | 211 | local config = {} 212 | config.type = editorSettings.type 213 | config.num = editorSettings.num 214 | config.version = editorSettings.version 215 | config.cryptKey = finishTable.config.cryptKey 216 | config.port = modemPort 217 | saveTable(config,configFileName) 218 | 219 | editorSettings.single = #finishTable == 1 and true or false 220 | 221 | settingData = {} 222 | for i=1,#finishTable,1 do 223 | local loopArray = {} 224 | sendMsg(3) 225 | local j 226 | if editorSettings.single == false then 227 | sendMsg("Door # " .. i .. " out of " .. #finishTable .. " is being edited: " .. finishTable[i].name.data) 228 | local keepLoop = true 229 | while keepLoop do 230 | j = randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))] 231 | keepLoop = false 232 | for key,value in pairs(settingData) do 233 | if key == j then 234 | keepLoop = true 235 | end 236 | end 237 | end 238 | text = sendMsg("Magnetic card reader?",editorSettings.scanner and "Scan the magnetic card reader with your tablet." or "Enter the uuid of the device in TEXT. When finished, don't type anything and just press enter",5) 239 | loopArray["reader"] = {} 240 | local hasPad = false 241 | for _, value in pairs(text) do 242 | local thisType = component.type(value) 243 | if thisType == "os_magreader" then 244 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="swipe"}) 245 | elseif thisType == "os_biometric" then 246 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="biometric"}) 247 | elseif thisType == "os_rfidreader" then 248 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="rfid"}) 249 | elseif thisType == "os_keypad" then 250 | hasPad = true 251 | component.proxy(value).setDisplay("inactive", 6) 252 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="keypad",["global"]=false,["pass"]="1111"}) 253 | end 254 | end 255 | if hasPad then 256 | text = sendMsg("Keypads detected: Would you like to use a global or local password?","global passwords are set by the database. local are set and saved on this door computer","1 for global, 2 for local",1) 257 | if text == "1" then 258 | text = sendMsg("What is the key for that keypad variable?",1) 259 | else 260 | hasPad = false 261 | text = sendMsg("What is the pin for the keypad to need to allow you in?","4 or less numbers (4 recommended)",1) 262 | end 263 | for key, value in pairs(loopArray["reader"]) do 264 | if value.type == "keypad" then 265 | loopArray["reader"][key].global = hasPad 266 | loopArray["reader"][key].pass = text 267 | end 268 | end 269 | end 270 | else 271 | local hasPad = false 272 | j = randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))] 273 | local distable = {} 274 | for key,_ in pairs(component.list("os_magreader")) do 275 | table.insert(distable,{["uuid"]=key,["type"]="swipe"}) 276 | end 277 | for key,_ in pairs(component.list("os_biometric")) do 278 | table.insert(distable,{["uuid"]=key,["type"]="biometric"}) 279 | end 280 | for key,_ in pairs(component.list("os_rfidreader")) do 281 | table.insert(distable,{["uuid"]=key,["type"]="rfid"}) 282 | end 283 | for key,_ in pairs(component.list("os_keypad")) do 284 | hasPad = true 285 | component.proxy(key).setDisplay("inactive", 6) 286 | table.insert(distable,{["uuid"]=key,["type"]="keypad",["global"]=false,["pass"]="1111"}) 287 | end 288 | if hasPad then 289 | text = sendMsg("Keypads detected: Would you like to use a global or local password?","global passwords are set by the database. local are set and saved on this door computer","1 for global, 2 for local",1) 290 | if text == "1" then 291 | text = sendMsg("What is the key for that keypad variable?",1) 292 | else 293 | hasPad = false 294 | text = sendMsg("What is the pin for the keypad to need to allow you in?","4 or less numbers (4 recommended)",1) 295 | end 296 | for key, value in pairs(distable) do 297 | if value.type == "keypad" then 298 | distable[key].global = hasPad 299 | distable[key].pass = text 300 | end 301 | end 302 | end 303 | loopArray["reader"] = distable 304 | end 305 | loopArray["name"] = finishTable[i].name.data 306 | --Door Type/RedColor/Address/RedSide Area 307 | if finishTable[i].doorType.finished == true then 308 | loopArray["doorType"] = finishTable[i].doorType.data 309 | else 310 | text = sendMsg("Door Type? 1=redstone. 2=bundled. 3=door/rolldoor. NUMBER ONLY",1) 311 | loopArray["doorType"] = tonumber(text) 312 | end 313 | if loopArray.doorType == 2 then 314 | text = sendMsg("What color. Use the Color API wiki on the opencomputers wiki, and enter the NUMBER",1) 315 | loopArray["redColor"] = tonumber(text) 316 | loopArray["doorAddress"] = {} 317 | text = sendMsg("What side? 0=bottom, 1=top, 2=back, 3=front, 4=right, 5=left. NUMBER ONLY",1) 318 | loopArray["redSide"] = tonumber(text) 319 | if editorSettings.single == false then 320 | sendMsg("No need to input anything for door address. The setting doesn't require it :)") 321 | end 322 | elseif loopArray.doorType == 1 then 323 | loopArray["redColor"] = 0 324 | loopArray["doorAddress"] = {} 325 | text = sendMsg("No need for redColor! The settings you inputted before don't require it :)","What side? 0=bottom, 1=top, 2=back, 3=front, 4=right, 5=left. NUMBER ONLY",1) 326 | loopArray["redSide"] = tonumber(text) 327 | if editorSettings.single == false then 328 | sendMsg("No need to input anything for door address. The setting doesn't require it :)") 329 | end 330 | else 331 | loopArray["redColor"] = 0 332 | loopArray["redSide"] = 0 333 | sendMsg("no need to input anything for redColor. The setting doesn't require it :)","no need to input anything for redSide. The setting doesn't require it :)") 334 | loopArray["doorAddress"] = {} 335 | if editorSettings.single == false then 336 | text = sendMsg("What is the address for the doorcontrol/rolldoor block?", editorSettings.scanner and "Scan the blocks with tablet" or "Enter uuids as text",5) 337 | loopArray["doorAddress"] = text 338 | else 339 | loopArray["doorAddress"] = {} 340 | for key,_ in pairs(component.list("os_rolldoorcontroller")) do 341 | table.insert(loopArray["doorAddress"],key) 342 | end 343 | for key,_ in pairs(component.list("os_doorcontroller")) do 344 | table.insert(loopArray["doorAddress"],key) 345 | end 346 | end 347 | end 348 | --Toggle/Delay Area 349 | if finishTable[i].toggle.finished == true then 350 | sendMsg("Toggle has already been preset") 351 | loopArray["toggle"] = finishTable[i].toggle.data 352 | else 353 | text = sendMsg("Should the door be toggleable, or not? 0 for autoclose and 1 for toggleable",1) 354 | loopArray["toggle"] = tonumber(text) 355 | end 356 | if loopArray.toggle == 0 then 357 | if finishTable[i].delay.finished == true then 358 | sendMsg("Delay has already been preset") 359 | loopArray["delay"] = finishTable[i].delay.data 360 | else 361 | text = sendMsg("How long should the door stay open in seconds? NUMBER ONLY",1) 362 | loopArray["delay"] = tonumber(text) 363 | end 364 | else 365 | sendMsg("No need to change delay! Previous setting doesn't require it :)") 366 | loopArray["delay"] = 0 367 | end 368 | --Card Read Area (Beeg area) 369 | if finishTable[i].cardRead.finished == true then 370 | sendMsg("Door Passes have already been preset") 371 | loopArray["cardRead"] = finishTable[i].cardRead.data 372 | else 373 | if editorSettings.x == 2 then 374 | local readLoad = {} 375 | sendMsg("Remember how many of each pass you want before you start.","type something and enter to continue",1) 376 | readLoad.add = tonumber(sendMsg("How many add passes do you want to add?","remember multiple base passes can use the same add pass",1)) 377 | readLoad.base = tonumber(sendMsg("How many base passes do you want to add?",1)) 378 | readLoad.reject = tonumber(sendMsg("How many reject passes do you want to add?","These don't affect supreme passes",1)) 379 | readLoad.supreme = tonumber(sendMsg("How many supreme passes do you want to add?",1)) 380 | loopArray.cardRead = {} 381 | local nextmsg = {} 382 | nextmsg.beg, nextmsg.mid, nextmsg.back = "What should be read for "," pass number ","? 0 = staff" 383 | for i=1,#editorSettings.settings.var,1 do 384 | nextmsg.back = nextmsg.back .. ", " .. i .. " = " .. editorSettings.settings.label[i] 385 | end 386 | local passFunc = function(type,num) 387 | local newRules = {["uuid"]=uuid.next(),["request"]=type,["data"]=type == "base" and {} or false} 388 | local text = sendMsg(nextmsg.beg..type..nextmsg.mid..num..nextmsg.back,1) 389 | if tonumber(text) == 0 then 390 | newRules.call = "checkstaff" 391 | newRules.param = 0 392 | sendMsg("No need for extra parameter. This mode doesn't require it :)") 393 | else 394 | newRules["tempint"] = tonumber(text) 395 | newRules["call"] = editorSettings.settings.calls[tonumber(text)] 396 | if editorSettings.settings.type[tonumber(text)] == "string" or editorSettings.settings.type == "-string" then 397 | text = sendMsg("What is the string you would like to read? Enter text.",1) 398 | newRules["param"] = text 399 | elseif editorSettings.settings.type[tonumber(text)] == "bool" then 400 | newRules["param"] = 0 401 | sendMsg("No need for extra parameter. This mode doesn't require it :)") 402 | elseif editorSettings.settings.type[tonumber(text)] == "int" then 403 | if editorSettings.settings.above[tonumber(text)] == true then 404 | text = sendMsg("What level and above should be required?",1) 405 | else 406 | text = sendMsg("what level exactly should be required?",1) 407 | end 408 | newRules["param"] = tonumber(text) 409 | elseif editorSettings.settings.type[tonumber(text)] == "-int" then 410 | local nextmsg = "What group are you wanting to set?" 411 | for i=1,#editorSettings.settings.data[tonumber(text)],1 do 412 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.data[tonumber(text)][i] 413 | end 414 | text = sendMsg(nextmsg,1) 415 | newRules["param"] = tonumber(text) 416 | else 417 | sendMsg("error in cardRead area for num 2") 418 | newRules["param"] = 0 419 | end 420 | end 421 | return newRules 422 | end 423 | for i=1,readLoad.add,1 do 424 | local rule = passFunc("add",i) 425 | table.insert(loopArray.cardRead,rule) 426 | end 427 | local addNum = #loopArray.cardRead 428 | for i=1,readLoad.base,1 do 429 | local rule = passFunc("base",i) 430 | text = tonumber(sendMsg("How many add passes do you want to link?",1)) 431 | if text ~= 0 then 432 | local nextAdd = "Which pass do you want to add? " 433 | for j=1,addNum,1 do 434 | nextAdd = nextAdd .. ", " .. j .. " = " .. editorSettings.settings.label[loopArray.cardRead[j].tempint] 435 | end 436 | for j=1,text,1 do 437 | text = tonumber(sendMsg(nextAdd,1)) 438 | table.insert(rule.data,loopArray.cardRead[text].uuid) 439 | end 440 | end 441 | table.insert(loopArray.cardRead,rule) 442 | end 443 | for i=1,readLoad.reject,1 do 444 | local rule = passFunc("reject",i) 445 | table.insert(loopArray.cardRead,rule) 446 | end 447 | for i=1,readLoad.supreme,1 do 448 | local rule = passFunc("supreme",i) 449 | table.insert(loopArray.cardRead,rule) 450 | end 451 | else --{["uuid"]=uuid.next()["call"]=t1,["param"]=t2,["request"]="supreme",["data"]=false} 452 | local nextmsg = "What should be read? 0 = staff," 453 | for i=1,#editorSettings.settings.var,1 do 454 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.label[i] 455 | end 456 | text = sendMsg(nextmsg,1) 457 | loopArray["cardRead"] = {{["uuid"]=uuid.next(),["call"]="",["param"]=0,["request"]="supreme",["data"]=false}} 458 | if tonumber(text) == 0 then 459 | loopArray["cardRead"][1].call = "checkstaff" 460 | loopArray["cardRead"][1].param = 0 461 | sendMsg("No need to set access level. This mode doesn't require it :)") 462 | else 463 | loopArray["cardRead"][1].call = editorSettings.settings.calls[tonumber(text)] 464 | if editorSettings.settings.type[tonumber(text)] == "string" or editorSettings.settings.type[tonumber(text)] == "-string" then 465 | text = sendMsg("What is the string you would like to read? Enter text.",1) 466 | loopArray["cardRead"][1].param = text 467 | elseif editorSettings.settings.type[tonumber(text)] == "bool" then 468 | loopArray["cardRead"][1].param = 0 469 | sendMsg("No need to set access level. This mode doesn't require it :)") 470 | elseif editorSettings.settings.type[tonumber(text)] == "int" then 471 | if editorSettings.settings.above[tonumber(text)] == true then 472 | text = sendMsg("What level and above should be required?",1) 473 | else 474 | text = sendMsg("what level exactly should be required?",1) 475 | end 476 | loopArray["cardRead"][1].param = tonumber(text) 477 | elseif editorSettings.settings.type[tonumber(text)] == "-int" then 478 | local nextmsg = "What group are you wanting to set?" 479 | for i=1,#editorSettings.settings.data[tonumber(text)],1 do 480 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.data[tonumber(text)][i] 481 | end 482 | text = sendMsg(nextmsg,1) 483 | loopArray["cardRead"][1].param = tonumber(text) 484 | else 485 | sendMsg("error in cardRead area for num 2") 486 | loopArray["cardRead"][1].param = 0 487 | end 488 | end 489 | end 490 | end 491 | --Sectors Area 492 | if editorSettings.hassector then 493 | if finishTable[i].sector.finished == true then 494 | sendMsg("Sector has already been preset") 495 | loopArray["sector"] = finishTable[i].sector.data 496 | else 497 | local nextmsg = "What sector would you like this door to be part of? 0 = no sector" 498 | for i=1,#editorSettings.settings.sectors,1 do --Issue 499 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.sectors[i].name 500 | end 501 | text = tonumber(sendMsg(nextmsg,1)) 502 | if text == 0 then 503 | loopArray["sector"]=false 504 | else 505 | loopArray["sector"]=editorSettings.settings.sectors[text].uuid 506 | end 507 | end 508 | else 509 | loopArray["sector"] = false 510 | end 511 | --End of Loop 512 | settingData[j] = loopArray 513 | end 514 | 515 | text = sendMsg("All done with installer!","Would you like to start the computer now?","1 for yes, 2 for no",1) 516 | editorSettings.start = false 517 | if tonumber(text) == 1 then 518 | sendMsg("Ok, will start computer.",4) 519 | editorSettings.start = true 520 | else 521 | sendMsg("Ok, closing out.",4) 522 | end 523 | saveTable(settingData,settingFileName) 524 | if editorSettings.start == true then 525 | print("Starting...") 526 | os.execute(program) 527 | else 528 | print("Run " .. program .. " now to start door.") 529 | end 530 | os.execute("del finishSettings.txt") 531 | os.execute("del finish.lua") -------------------------------------------------------------------------------- /modules.txt: -------------------------------------------------------------------------------- 1 | {{name="Security",id=1111,version="3.0.0",database={folder="Security",main="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/security/Database%20Module/Main.lua",debug="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/2.5.0/security/Database%20Module/Main.lua",extras={}},server={folder="Security",main="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/security/Server%20Module/security.lua",debug="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/2.5.0/security/Server%20Module/security.lua",extras={}},requirements={}},{name="Sectors",id=1112,version="3.0.0",database={folder="Sectors",main="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/sectors/Database%20Module/Main.lua",debug="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/2.5.0/sectors/Database%20Module/Main.lua",extras={}},server={folder="Sectors",main="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/sectors/Server%20Module/sectors.lua",debug="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/2.5.0/sectors/Server%20Module/sectors.lua",extras={}},requirements={1111}},{name="Door Setup",id=1113,version="1.0.0",database={folder="DoorSetup",main="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/doorsetup/door.lua",extras={{name="finish.lua",url="https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/doorsetup/finish.lua"}}},requirements={1111}}} -------------------------------------------------------------------------------- /permissions.txt: -------------------------------------------------------------------------------- 1 | security.* (All things in Security module & Sectors) 2 | security.varmanagement (add/del users and add/del vars and write cards/admincard) 3 | security.sectors (All things in Sectors module) 4 | security.name (Name) 5 | security.writecard (write card) 6 | security.admincard (write admin card) 7 | security.resetuuid (reset user uuid for card) 8 | security.passediting (all passes) 9 | security.link (link button) 10 | security.block (block user) 11 | security.staff (staff pass) 12 | security.doorsetup (create a door with doorsetup module) 13 | security.mcid (link and clear a user's minecraft id) 14 | security.keypad (Manage global keypad passwords) 15 | security.(any var added by user) 16 | 17 | dev.* (all developer module features) 18 | dev.usermanagement (manage users and permissions and such.) 19 | dev.systemmanagement (manage modules and settings) 20 | 21 | Any permission written with a ~ before it will be disabled for that user 22 | (in case you want someone to, say, do all security functions except write a card, do ~security.writecard and security.*) -------------------------------------------------------------------------------- /remotecontrol/main.lua: -------------------------------------------------------------------------------- 1 | local module = {} 2 | local component = require("component") 3 | local GUI = require("GUI") 4 | local ser = require("serialization") 5 | local modem = component.modem 6 | 7 | local userTable -- Holds userTable stuff. 8 | 9 | local workspace, window, loc, database, style, compat = table.unpack({...}) --Sets up necessary variables: workspace is workspace, window is area to work in, loc is localization file, database are database commands, and style is the selected style file. 10 | 11 | module.name = "R.C." --The name that shows up on the module's button. 12 | module.table = {} --Set to the keys you want pulled from the userlist on the server, 13 | module.debug = false --The database will set to true if debug mode on database is enabled. If you want to enable certain functions in debug mode. 14 | module.config = {} --optional. Lets you add config settings which can be pulled by database.checkConfig("name"). 15 | --[[ INFO ABOUT module.config 16 | Each value of table must be this: ["name"] = {["label"] = "a label",["type"]="bool",["default"]=false} 17 | name = name that the variable is stored in. What you'll call with database.checkConfig("name") replacing "name" with the name 18 | label = What the label will be in the settings database 19 | type = The type of input it takes. bool is a button, string is a string input, int is a number (int) input 20 | default = Default value if created for first time. bool is true or false, string is string input, and int is a number. 21 | server = Whether the settings are pushed to the server as well (server-side settings) Settings are always saved database side 22 | ]] 23 | local diagPort = 180 24 | 25 | 26 | module.init = function(usTable) --Set userTable to what's received. Runs only once at the beginning 27 | userTable = usTable 28 | end 29 | 30 | module.onTouch = function() --Runs when the module's button is clicked. Set up the workspace here. 31 | --Verify their permissions 32 | if database.checkPerms("security",{"rc"},true) then 33 | window:addChild(GUI.label(2,16,3,3,style.passNameLabel,"You do not have permissions to do this")) 34 | return 35 | end 36 | --Door Setup 37 | local worked,_,_,_,_,doors = database.send(true,"rcdoors") --get doors 38 | if(worked) then --got doors 39 | local tempPasses = ser.unserialize(database.crypt(doors,true)) --decrypt and make table 40 | doors = {} 41 | for key,value in pairs(tempPasses) do --Perform loop to sort in a way which will be sent to the doors to activate them 42 | for keym,valuem in pairs(value.data) do 43 | table.insert(doors,{["call"]=value.id,["type"]=value.type,["data"]=valuem,["key"]=keym}) 44 | end 45 | end 46 | --Define Variables 47 | local doorList, listPageLabel, listUpButton, listDownButton, openFive, openTen, openThirty, toggleOpen, openNum, openNumInput 48 | local pageMult = 10 49 | local listPageNumber = 0 50 | local previousPage = 0 51 | 52 | --Functions 53 | 54 | local function doorListCallback() 55 | openFive.disabled = false 56 | openTen.disabled = false 57 | openThirty.disabled = false 58 | toggleOpen.disabled = false 59 | openNum.disabled = false 60 | openNumInput.disabled = false 61 | end 62 | 63 | local function updateList() 64 | doorList:removeChildren() 65 | if (pageMult * listPageNumber) + 1 > #doors and listPageNumber ~= 0 then 66 | listPageNumber = listPageNumber - 1 67 | end 68 | local temp = pageMult * listPageNumber 69 | for i = temp + 1, temp + pageMult, 1 do 70 | if doors[i] == nil then 71 | 72 | else 73 | doorList:addItem(doors[i].data.name).onTouch = doorListCallback 74 | end 75 | end 76 | doorList.selectedItem = 1 77 | previousPage = listPageNumber 78 | if pageMult * listPageNumber + pageMult < #doors then 79 | listUpButton.disabled = false 80 | else 81 | listUpButton.disabled = true 82 | end 83 | if listPageNumber == 0 then 84 | listDownButton.disabled = true 85 | end 86 | listDownButton.disabled = listPageNumber == 0 87 | listUpButton.disabled = #doors <= temp + pageMult 88 | openFive.disabled = false 89 | openTen.disabled = false 90 | openThirty.disabled = false 91 | toggleOpen.disabled = false 92 | openNum.disabled = false 93 | openNumInput.disabled = false 94 | end 95 | 96 | local function pageCallback(_,button) 97 | local function canFresh() 98 | updateList() 99 | doorListCallback() 100 | end 101 | if #doors ~= 0 then 102 | if button.isPos then 103 | if listPageNumber < #doors/pageMult - 1 then 104 | listPageNumber = listPageNumber + 1 105 | canFresh() 106 | end 107 | else 108 | if listPageNumber > 0 then 109 | listPageNumber = listPageNumber - 1 110 | canFresh() 111 | end 112 | end 113 | end 114 | end 115 | 116 | local function performCommand(_,button) 117 | local selected = pageMult * listPageNumber + doorList.selectedItem 118 | local send = {["id"]=doors[selected].call,["key"]=doors[selected].key,["type"]="base"} 119 | if(button.sendIt == 1) then 120 | send.type = "toggle" 121 | elseif(button.sendIt == 2) then 122 | send.type, send.delay = "delay", 5 123 | elseif (button.sendIt == 3) then 124 | send.type,send.delay = "delay", 10 125 | elseif(button.sendIt == 4) then 126 | send.type,send.delay = "delay", 30 127 | elseif(button.sendIt == 5) then 128 | if(openNumInput.text ~= "") then 129 | send.type,send.delay = "delay", tonumber(openNumInput.text) 130 | else 131 | GUI.alert("No seconds specified") 132 | return 133 | end 134 | end 135 | modem.send(send.id,diagPort,"remoteControl",ser.serialize(send)) 136 | end 137 | 138 | --Setup GUI 139 | 140 | window:addChild(GUI.panel(1,1,37,33,style.listPanel)) 141 | doorList = window:addChild(GUI.list(2, 2, 35, 31, 3, 0, style.listBackground, style.listText, style.listAltBack, style.listAltText, style.listSelectedBack, style.listSelectedText, false)) 142 | listPageLabel = window:addChild(GUI.label(2,33,3,3,style.listPageLabel,tostring(listPageNumber + 1))) 143 | listUpButton = window:addChild(GUI.button(8,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "+")) 144 | listUpButton.onTouch, listUpButton.isPos = pageCallback,true 145 | listDownButton = window:addChild(GUI.button(12,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "-")) 146 | listDownButton.onTouch, listDownButton.isPos = pageCallback,false 147 | openFive = window:addChild(GUI.button(64,14,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, "5 Seconds")) 148 | openFive.sendIt = 2 149 | openFive.onTouch = performCommand 150 | openFive.disabled = true 151 | openTen = window:addChild(GUI.button(64,16,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, "10 Seconds")) 152 | openTen.sendIt = 3 153 | openTen.onTouch = performCommand 154 | openTen.disabled = true 155 | openThirty = window:addChild(GUI.button(64,18,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, "30 Seconds")) 156 | openThirty.sendIt = 4 157 | openThirty.onTouch = performCommand 158 | openThirty.disabled = true 159 | toggleOpen = window:addChild(GUI.button(64,12,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, "Toggle Open")) 160 | toggleOpen.sendIt = 1 161 | toggleOpen.onTouch = performCommand 162 | toggleOpen.disabled = true 163 | openNumInput = window:addChild(GUI.input(64,21,16,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", loc.inputname)) 164 | openNumInput.onInputFinished = function() 165 | if openNumInput.text ~= nil and openNumInput ~= "" then 166 | local num = tonumber(openNumInput.text) 167 | if(num == nil and num > 0) then 168 | openNumInput.text = "" 169 | end 170 | end 171 | end 172 | openNumInput.disabled = true 173 | openNum = window:addChild(GUI.button(64,20,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, "# Seconds")) 174 | openNum.sendIt = 5 175 | openNum.onTouch = performCommand 176 | openNum.disabled = true 177 | updateList() 178 | else 179 | GUI.alert("No connection received") 180 | end 181 | end 182 | 183 | module.close = function() 184 | return {} --Return table of what you want the database to auto save (if enabled) of the keys used by this module 185 | end 186 | 187 | return module 188 | -------------------------------------------------------------------------------- /sectors/Database Module/Main.lua: -------------------------------------------------------------------------------- 1 | local module = {} 2 | local GUI = require("GUI") 3 | local uuid = require("uuid") 4 | 5 | local userTable 6 | 7 | local workspace, window, loc, database, style, compat = table.unpack({...}) 8 | 9 | module.name = "Sectors" 10 | module.table = {"sectors"} 11 | module.debug = false 12 | module.config = {} 13 | 14 | module.init = function(usTable) 15 | userTable = usTable 16 | end 17 | 18 | module.onTouch = function() 19 | local sectorList, sectorNameInput, newSectorButton, delSectorButton, sectorPassNew, sectorPassRemove, sectorPassEdit, sectorPassList, userPassSelfSelector, userPassDataSelector, userPassTypeSelector, userPassPrioritySelector 20 | local sectorListNum, sectorListUp, sectorListDown, sectorPassListNum, sectorPassListUp, sectorPassListDown 21 | 22 | local canPerm 23 | 24 | local pageMult = 10 25 | local listPageNumber = 0 26 | local previousPage = 0 27 | 28 | local pageMultPass = 5 29 | local listPageNumberPass = 0 30 | local previousPagePass = 0 31 | local prevPass = "string" 32 | 33 | --Sector functions 34 | 35 | local function uuidtopass(uuid) 36 | if uuid == "checkstaff" then 37 | return true, 0 38 | end 39 | for i=1,#userTable.passSettings.calls,1 do 40 | if userTable.passSettings.calls[i] == uuid then 41 | return true, i 42 | end 43 | end 44 | return false 45 | end 46 | 47 | local function refreshInput() 48 | local uuid = userPassSelfSelector.selectedItem - 1 49 | if uuid ~= 0 then 50 | if userTable.passSettings.type[uuid] == "string" or userTable.passSettings.type[uuid] == "-string" or userTable.passSettings.type[uuid] == "int" then 51 | if prevPass == "-int" then 52 | userPassDataSelector:remove() 53 | userPassDataSelector = window:addChild(GUI.input(100,22,16,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.inputtext)) 54 | end 55 | userPassDataSelector.text = "" 56 | userPassDataSelector.disabled = canPerm 57 | elseif userTable.passSettings.type[uuid] == "-int" then 58 | if prevPass ~= "-int" then 59 | userPassDataSelector:remove() 60 | userPassDataSelector = window:addChild(GUI.comboBox(100,21,30,3, style.sectorComboBack,style.sectorComboText,style.sectorComboArrowBack,style.sectorComboArrowText)) 61 | else 62 | userPassDataSelector:clear() 63 | end 64 | for _,value in pairs(userTable.passSettings.data[uuid]) do 65 | userPassDataSelector:addItem(value) 66 | end 67 | userPassDataSelector.selectedItem = 1 68 | else 69 | if prevPass == "-int" then 70 | userPassDataSelector:remove() 71 | userPassDataSelector = window:addChild(GUI.input(100,22,16,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.inputtext)) 72 | end 73 | userPassDataSelector.text = "" 74 | userPassDataSelector.disabled = true 75 | end 76 | else 77 | if prevPass == "-int" then 78 | userPassDataSelector:remove() 79 | userPassDataSelector = window:addChild(GUI.input(100,22,16,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.inputtext)) 80 | end 81 | userPassDataSelector.text = "" 82 | userPassDataSelector.disabled = true 83 | end 84 | prevPass = uuid ~= 0 and userTable.passSettings.type[uuid] or "bool" 85 | end 86 | 87 | --[[local function sectorPassCallback() Commented out because not planning on making it possible to add sectors for simplicity for meeeee 88 | local selectedId = pageMultPass * listPageNumberPass + sectorPassList.selectedItem 89 | local secSelect = pageMult * listPageNumber + sectorList.selectedItem 90 | local sectorpass = userTable.sectors[secSelect].pass[selectedId] 91 | local uuid = uuidtopass(sectorpass.uuid) 92 | userPassSelfSelector.selectedItem = uuid + 1 93 | userPassTypeSelector.selectedItem = sectorpass.lock 94 | refreshInput(uuid) 95 | end]] 96 | 97 | local function sectorListCallback() 98 | local selectedId = pageMult * listPageNumber + sectorList.selectedItem 99 | sectorNameInput.text = userTable.sectors[selectedId].name 100 | sectorPassList:removeChildren() 101 | if (pageMultPass * listPageNumberPass) + 1 > #userTable.sectors[selectedId].pass and listPageNumberPass ~= 0 then 102 | listPageNumberPass = listPageNumberPass - 1 103 | end 104 | local temp = pageMultPass * listPageNumberPass 105 | if previousPagePass ~= listPageNumberPass then 106 | sectorPassList.selectedItem = 1 107 | previousPagePass = listPageNumberPass 108 | end 109 | sectorPassListDown.disabled = listPageNumberPass == 0 110 | sectorPassListUp.disabled = #userTable.sectors[selectedId].pass <= temp + pageMultPass 111 | sectorPassListNum.text = tostring(listPageNumberPass + 1) 112 | sectorPassNew.disabled = canPerm 113 | sectorPassRemove.disabled = canPerm 114 | sectorPassEdit.disabled = canPerm 115 | for i = temp + 1, temp + pageMultPass, 1 do 116 | if (userTable.sectors[selectedId].pass[i] == nil) then 117 | if i == temp + 1 then 118 | sectorPassRemove.disabled = true 119 | sectorPassEdit.disabled = true 120 | end 121 | else 122 | local work, pass = uuidtopass(userTable.sectors[selectedId].pass[i].uuid) 123 | local lockType = {loc.sectoropen,loc.sectordislock} 124 | if pass ~= 0 then 125 | local disdata = userTable.sectors[selectedId].pass[i].data ~= nil and userTable.sectors[selectedId].pass[i].data or "0" 126 | if userTable.passSettings.type[pass] == "-int" then 127 | disdata = userTable.passSettings.data[pass][disdata] 128 | end 129 | sectorPassList:addItem(userTable.passSettings.label[pass] .. " : " .. tostring(disdata) .. " : p" .. tostring(userTable.sectors[selectedId].pass[i].priority) .. " : " .. lockType[userTable.sectors[selectedId].pass[i].lock]) 130 | else 131 | sectorPassList:addItem("Staff : 0 : p" .. tostring(userTable.sectors[selectedId].pass[i].priority) .. " : " .. lockType[userTable.sectors[selectedId].pass[i].lock]) 132 | end 133 | end 134 | end 135 | workspace:draw() 136 | end 137 | 138 | local function updateSecList() 139 | local selectedId = sectorList.selectedItem 140 | sectorList:removeChildren() 141 | if (pageMult * listPageNumber) + 1 > #userTable.sectors and listPageNumber ~= 0 then 142 | listPageNumber = listPageNumber - 1 143 | end 144 | local temp = pageMult * listPageNumber 145 | sectorListNum.text = tostring(listPageNumber + 1) 146 | for i = temp + 1, temp + pageMult, 1 do 147 | if (userTable.sectors[i] == nil) then 148 | 149 | else 150 | sectorList:addItem(userTable.sectors[i].name).onTouch = sectorListCallback 151 | end 152 | end 153 | database.save() 154 | if (previousPage == listPageNumber) then 155 | sectorList.selectedItem = selectedId 156 | else 157 | sectorList.selectedItem = 1 158 | listPageNumberPass = 0 159 | sectorListCallback() 160 | previousPage = listPageNumber 161 | end 162 | sectorListDown.disabled = listPageNumber == 0 163 | sectorListUp.disabled = #userTable.sectors <= temp + pageMult 164 | database.update() 165 | workspace:draw() 166 | end 167 | 168 | local function pageCallback(workspace,button) 169 | local function canFresh() 170 | updateSecList() 171 | sectorListCallback() 172 | end 173 | if button.isPos then 174 | if button.isListNum == 1 then 175 | if listPageNumber < #userTable.sectors/pageMult - 1 then 176 | listPageNumber = listPageNumber + 1 177 | canFresh() 178 | end 179 | else 180 | if listPageNumberPass < #userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass/pageMultPass - 1 then 181 | listPageNumberPass = listPageNumberPass + 1 182 | canFresh() 183 | end 184 | end 185 | else 186 | if button.isListNum == 1 then 187 | if listPageNumber > 0 then 188 | listPageNumber = listPageNumber - 1 189 | canFresh() 190 | end 191 | else 192 | if listPageNumberPass > 0 then 193 | listPageNumberPass = listPageNumberPass - 1 194 | canFresh() 195 | end 196 | end 197 | end 198 | end 199 | 200 | local function createSector() 201 | local addVarArray = {["name"]="new sector",["uuid"]=uuid.next(),["pass"]={}} 202 | table.insert(userTable.sectors,addVarArray) 203 | addVarArray = nil 204 | database.save() 205 | database.update() 206 | updateSecList() 207 | end 208 | local function deleteSector() 209 | local selected = pageMult * listPageNumber + sectorList.selectedItem 210 | table.remove(userTable.sectors,selected) 211 | if #userTable.sectors < pageMult * listPageNumber + 1 and listPageNumber ~= 0 then 212 | listPageNumber = listPageNumber - 1 213 | end 214 | database.save() 215 | database.update() 216 | updateSecList() 217 | end 218 | 219 | local function createSectorPass() 220 | local selected = userPassSelfSelector.selectedItem - 1 221 | local data = selected == 0 and nil or userTable.passSettings.type[selected] == "-int" and userPassDataSelector.selectedItem or userTable.passSettings.type[selected] == "bool" and nil or userTable.passSettings.type[selected] == "int" and tonumber(userPassDataSelector.text) or userPassDataSelector.text 222 | local uuid = selected == 0 and "checkstaff" or userTable.passSettings.calls[selected] 223 | table.insert(userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass,{["uuid"]=uuid,["data"]=data,["lock"]=userPassTypeSelector.selectedItem,["priority"]=userPassPrioritySelector.selectedItem}) 224 | database.save() 225 | database.update() 226 | sectorListCallback() 227 | end 228 | local function deleteSectorPass() 229 | local selected = pageMultPass * listPageNumberPass + sectorPassList.selectedItem 230 | table.remove(userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass,selected) 231 | if #userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass < pageMultPass * listPageNumberPass + 1 and listPageNumberPass ~= 0 then 232 | listPageNumberPass = listPageNumberPass - 1 233 | end 234 | database.save() 235 | database.update() 236 | sectorListCallback() 237 | end 238 | local function editSectorPass() 239 | local selected = pageMultPass * listPageNumberPass + sectorPassList.selectedItem 240 | local apples = userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass[selected] 241 | table.remove(userTable.sectors[pageMult * listPageNumber + sectorList.selectedItem].pass,selected) 242 | sectorListCallback() 243 | userPassPrioritySelector.selectedItem = apples.priority 244 | userPassTypeSelector.selectedItem = apples.lock 245 | _, apples.uuid = uuidtopass(apples.uuid) 246 | userPassSelfSelector.selectedItem = apples.uuid + 1 --issue 247 | refreshInput() 248 | if apples.uuid == 0 or userTable.passSettings.type[apples.uuid] == "bool" then 249 | 250 | elseif userTable.passSettings.type[apples.uuid] == "-int" then 251 | userPassDataSelector.selectedItem = apples.data 252 | else 253 | userPassDataSelector.text = userTable.passSettings.type[apples.uuid] == "int" and tostring(apples.data) or apples.data 254 | end 255 | end 256 | 257 | canPerm = database.checkPerms("security",{"sector"},true) 258 | 259 | --GUI Setup 260 | window:addChild(GUI.panel(1,1,37,33,style.listPanel)) 261 | sectorList = window:addChild(GUI.list(2, 2, 35, 31, 3, 0, style.listBackground, style.listText, style.listAltBack, style.listAltText, style.listSelectedBack, style.listSelectedText, false)) 262 | sectorList:addItem("HELLO") 263 | listPageNumber = 0 264 | 265 | 266 | --Sector infos newSectorButton, delSectorButton 267 | window:addChild(GUI.label(40,12,1,1,style.passNameLabel,"Sector name: ")) 268 | sectorNameInput = window:addChild(GUI.input(64,12,16,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", loc.inputname)) 269 | sectorNameInput.onInputFinished = function() 270 | local selected = pageMult * listPageNumber + sectorList.selectedItem 271 | userTable.sectors[selected].name = sectorNameInput.text 272 | updateSecList() 273 | sectorListCallback() 274 | end 275 | sectorNameInput.disabled = canPerm 276 | 277 | newSectorButton = window:addChild(GUI.button(85,12,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, loc.addvar)) 278 | newSectorButton.onTouch = createSector 279 | newSectorButton.disabled = canPerm 280 | delSectorButton = window:addChild(GUI.button(100,12,16,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, loc.delvar)) 281 | delSectorButton.onTouch = deleteSector 282 | delSectorButton.disabled = canPerm 283 | 284 | window:addChild(GUI.panel(40,14,96,1,style.bottomDivider)) 285 | window:addChild(GUI.panel(40,15,1,18,style.bottomDivider)) 286 | 287 | window:addChild(GUI.panel(42,17,37,17,style.listPanel)) 288 | sectorPassList = window:addChild(GUI.list(43, 18, 35, 15, 3, 0, style.listBackground, style.listText, style.listAltBack, style.listAltText, style.listSelectedBack, style.listSelectedText, false)) 289 | 290 | window:addChild(GUI.label(85,18,1,1,style.passNameLabel,"Select Pass : ")) 291 | userPassSelfSelector = window:addChild(GUI.comboBox(100,17,30,3, style.sectorComboBack,style.sectorComboText,style.sectorComboArrowBack,style.sectorComboArrowText)) 292 | userPassSelfSelector:addItem("staff").onTouch = refreshInput 293 | for i=1,#userTable.passSettings.var,1 do 294 | userPassSelfSelector:addItem(userTable.passSettings.label[i]).onTouch = refreshInput 295 | end 296 | userPassSelfSelector.disabled = canPerm 297 | window:addChild(GUI.label(85,22,1,1,style.passNameLabel,"Change Input: ")) 298 | userPassDataSelector = window:addChild(GUI.input(100,22,30,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", loc.inputtext)) 299 | userPassDataSelector.disabled = true 300 | refreshInput() 301 | window:addChild(GUI.label(85,26,1,1,style.passNameLabel,"Bypass Type : ")) 302 | userPassTypeSelector = window:addChild(GUI.comboBox(100,25,30,3, style.sectorComboBack,style.sectorComboText,style.sectorComboArrowBack,style.sectorComboArrowText)) 303 | userPassTypeSelector.disabled = canPerm 304 | userPassTypeSelector:addItem(loc.sectoropen) 305 | userPassTypeSelector:addItem(loc.sectordislock) 306 | window:addChild(GUI.label(85,30,1,1,style.passNameLabel,"Priority : ")) 307 | userPassPrioritySelector = window:addChild(GUI.comboBox(100,29,30,3, style.sectorComboBack,style.sectorComboText,style.sectorComboArrowBack,style.sectorComboArrowText)) 308 | userPassPrioritySelector.disabled = canPerm 309 | for i=1,5,1 do 310 | userPassPrioritySelector:addItem(tostring(i)) 311 | end 312 | sectorPassNew = window:addChild(GUI.button(85,33,14,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, loc.addvar)) 313 | sectorPassNew.onTouch = createSectorPass 314 | sectorPassNew.disabled = true 315 | sectorPassRemove = window:addChild(GUI.button(100,33,14,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, loc.delvar)) 316 | sectorPassRemove.onTouch = deleteSectorPass 317 | sectorPassRemove.disabled = true 318 | sectorPassEdit = window:addChild(GUI.button(115,33,14,1, style.sectorButton,style.sectorText,style.sectorSelectButton,style.sectorSelectText, loc.editvar)) 319 | sectorPassEdit.onTouch = editSectorPass 320 | sectorPassEdit.disabled = true 321 | --List Buttons Setup 322 | sectorListNum = window:addChild(GUI.label(2,33,3,3,style.listPageLabel,tostring(listPageNumber + 1))) 323 | sectorListUp = window:addChild(GUI.button(8,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "+")) 324 | sectorListUp.onTouch, sectorListUp.isPos, sectorListUp.isListNum = pageCallback,true,1 325 | sectorListDown = window:addChild(GUI.button(12,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "-")) 326 | sectorListDown.onTouch, sectorListDown.isPos, sectorListDown.isListNum = pageCallback,false,1 327 | 328 | sectorPassListNum = window:addChild(GUI.label(43,33,3,3,style.listPageLabel,tostring(listPageNumberPass + 1))) 329 | sectorPassListUp = window:addChild(GUI.button(51,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "+")) 330 | sectorPassListUp.onTouch, sectorPassListUp.isPos, sectorPassListUp.isListNum = pageCallback,true,2 331 | sectorPassListDown = window:addChild(GUI.button(55,33,3,1, style.listPageButton, style.listPageText, style.listPageSelectButton, style.listPageSelectText, "-")) 332 | sectorPassListDown.onTouch, sectorPassListDown.isPos, sectorPassListDown.isListNum = pageCallback,false,2 333 | 334 | updateSecList() 335 | end 336 | 337 | module.close = function() 338 | return {["sectors"]={}} 339 | end 340 | 341 | return module -------------------------------------------------------------------------------- /sectors/Server Module/sectors.lua: -------------------------------------------------------------------------------- 1 | local userTable = {} 2 | local doorTable = {} 3 | local server = {} 4 | local modemPort = 199 5 | 6 | local component = require("component") 7 | local modem = component.modem 8 | local ser = require("serialization") 9 | local uuid = require("uuid") 10 | 11 | local module = {} 12 | module.name = "sectors" 13 | module.commands = {"sectorupdate","doorsecupdate"} --removed doorSector so it isn't received from outside of the server via modems 14 | module.skipcrypt = {} 15 | module.table = {["sectors"] = {{["name"]="Placeholder Sector",["uuid"]=uuid.next(),["type"]=1,["pass"]={}}}} 16 | module.table.sectorStatus = {[module.table.sectors[1].uuid]=1} 17 | module.debug = false 18 | module.version = "4.0.3" 19 | module.id = 1112 20 | 21 | local function checkMCID(id) --Pulled from Security module 22 | for _, value in pairs(userTable.passes) do 23 | if value.mcid == id then 24 | return true, value.uuid, value.name 25 | end 26 | end 27 | return false 28 | end 29 | 30 | function module.init(setit ,doors, serverCommands) --Called when server is first started. Passes userTable and doorTable. 31 | userTable = setit 32 | doorTable = doors 33 | server = serverCommands 34 | if module.debug then server.print("Received " .. #userTable.sectors .. " Sectors\n") end 35 | end 36 | 37 | function module.setup() --Called when userlist is updated or server is first started 38 | if module.debug then server.print("Received " .. #userTable.sectors .. " Sectors\n") end 39 | for key,_ in pairs(userTable.sectorStatus) do 40 | local good = false 41 | for i=1,#userTable.sectors,1 do 42 | if userTable.sectors[i].uuid == key then 43 | good = true 44 | break 45 | end 46 | end 47 | if good == false then 48 | userTable.sectorStatus[key] = nil 49 | end 50 | end 51 | for i=1,#userTable.sectors,1 do 52 | if userTable.sectorStatus[userTable.sectors[i].uuid] == nil then 53 | userTable.sectorStatus[userTable.sectors[i].uuid] = 1 54 | end 55 | end 56 | server.send(false,"getSectorList",ser.serialize({["sectors"]=userTable.sectors,["sectorStatus"]=userTable.sectorStatus})) 57 | end 58 | 59 | function module.message(command,datar) --Called when a command goes past all default commands and into modules. 60 | local data 61 | if datar ~= nil then 62 | data = ser.unserialize(datar) 63 | end 64 | if command == "sectorupdate" then 65 | local st, name = false, "ERROR" 66 | if data[2] > 0 and data[2] <= 3 then 67 | for _,value in pairs(userTable.sectors) do 68 | if value.uuid == data[1] then 69 | st = true 70 | name = value.name 71 | end 72 | end 73 | end 74 | if st then 75 | userTable.sectorStatus[data[1]] = data[2] 76 | local me = {"disabled","lockdown","open"} 77 | return true,{{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]="Sector ",["color"]=nil,["line"]=false},{["text"]=name,["color"]=0x00FF00,["line"]=false},{["text"]="Status set to ",["color"]=nil,["line"]=true},{["text"]=me[data[2]],["color"]=nil,["line"]=false}},true,false,"checkSector",ser.serialize(userTable.sectorStatus) 78 | else 79 | 80 | end 81 | elseif command == "doorsector" then 82 | if data.isBio then 83 | local e,good,nome = checkMCID(data.uuid) 84 | if e then 85 | data.uuid = good 86 | data.name = nome 87 | else 88 | return true,{{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]="User" .. data.uuid .. " not linked to biometrics",["color"]=0x994049}},false,true,server.crypt("false") 89 | end 90 | end 91 | for i=1,#userTable.sectors,1 do 92 | if userTable.sectors[i].uuid == data.sector then 93 | if userTable.sectorStatus[userTable.sectors[i].uuid] == 1 then 94 | return true,nil,false,true,"true" 95 | else 96 | local passed = false 97 | local user = false 98 | for j=1,#userTable.passes,1 do 99 | if string.sub(userTable.passes[j].uuid,1,-14) == data.uuid or userTable.passes[j].uuid == data.uuid then 100 | user = j 101 | break 102 | end 103 | end 104 | if user == false then 105 | return true, {{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]="Sector check failed: User Not Found",["color"]=nil,["line"]=false}}, false, true, "false" 106 | end 107 | local printText = "User " .. data.name .. " failed sector check of " .. userTable.sectors[i].name 108 | for p=1,5,1 do 109 | for _,value in pairs(userTable.sectors[i].pass) do 110 | if value.priority == p then 111 | if value.uuid ~= "checkstaff" then 112 | for j=1,#userTable.passSettings.calls,1 do 113 | if userTable.passSettings.calls[j] == value.uuid then 114 | local check = function(rule) 115 | if userTable.passSettings.type[j] == "string" then 116 | return userTable.passes[user][userTable.passSettings.var[j]] == rule 117 | elseif userTable.passSettings.type[j] == "-string" then 118 | for z=1,#userTable.passes[user][userTable.passSettings.var[j]],1 do 119 | if userTable.passes[user][userTable.passSettings.var[j]][z] == rule then 120 | return true 121 | end 122 | end 123 | return false 124 | elseif userTable.passSettings.type[j] == "int" or userTable.passSettings.type[j] == "-int" then 125 | if userTable.passSettings.above[j] == false or userTable.passSettings.type[j] == "-int" then 126 | return userTable.passes[user][userTable.passSettings.var[j]] == tonumber(rule) 127 | else 128 | return userTable.passes[user][userTable.passSettings.var[j]] >= tonumber(rule) 129 | end 130 | elseif userTable.passSettings.type[j] == "bool" then 131 | return userTable.passes[user][userTable.passSettings.var[j]] 132 | end 133 | end 134 | passed = check(value.data) 135 | break 136 | end 137 | end 138 | else 139 | if userTable.passes[user].staff then 140 | passed = true 141 | end 142 | end 143 | if passed then 144 | if userTable.sectorStatus[userTable.sectors[i].uuid] == 3 and value.lock == 1 then 145 | printText = "Cannot bypass open sector " .. userTable.sectors[i].name 146 | end 147 | if value.lock == 1 then 148 | return true,nil,nil,true,"openbypass" 149 | else 150 | if data.isRFID then 151 | return true, nil, nil, true, "false" 152 | else 153 | return true, {{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]="User " .. data.name .. " requested a bypass of " .. userTable.sectors[i].name,["color"]=0xFF0000,["line"]=false}},false,true,"lockbypass" 154 | end 155 | end 156 | end 157 | end 158 | end 159 | end 160 | return true, {{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]=printText,["color"]=nil,["line"]=false}},false,true,"false" 161 | end 162 | end 163 | end 164 | elseif command == "doorsecupdate" then 165 | for i=1,#userTable.sectors,1 do 166 | if userTable.sectors[i].uuid == datar then 167 | userTable.sectorStatus[userTable.sectors[i].uuid] = 1 168 | return true,{{["text"]="Sectors: ",["color"]=0x9924C0},{["text"]="Sector Lockdown lifted of " .. userTable.sectors[i].name,["color"]=nil,["line"]=false}},true,false,"checkSector",ser.serialize(userTable.sectorStatus) 169 | end 170 | end 171 | else 172 | 173 | end 174 | return false 175 | end 176 | 177 | function module.piggyback(command,data) --Called after a command is passed. Passed to all modules which return nothing. 178 | 179 | end 180 | 181 | return module -------------------------------------------------------------------------------- /sectors/sectorcontrol.lua: -------------------------------------------------------------------------------- 1 | local version = "4.0.3" 2 | 3 | local sector = {} 4 | local sectorStatus = {} 5 | local sectorSettings = {} 6 | 7 | local modemPort = 1000 8 | local syncPort = 199 9 | 10 | local component = require("component") 11 | local gpu = component.gpu 12 | local event = require("event") 13 | local ser = require("serialization") 14 | local term = require("term") 15 | local thread = require("thread") 16 | local process = require("process") 17 | local uuid = require("uuid") 18 | local computer = component.computer 19 | local keyboard = require("keyboard") 20 | 21 | local redstone = component.redstone 22 | local modem = component.modem 23 | 24 | local query 25 | 26 | local testR = true 27 | local lengthNum = 0 28 | local pageNum = 1 29 | local listNum = 1 30 | 31 | local redColorTypes = {"white","orange","magenta","light blue","yellow","lime","pink","gray","silver","cyan","purple","blue","brown","green","red","black"} 32 | local redSideTypes = {"bottom","top","back","front","right","left"} 33 | 34 | local updatePulse = false 35 | 36 | --------Table To File 37 | 38 | local function saveTable( tbl,filename ) 39 | local tableFile = assert(io.open(filename, "w")) 40 | tableFile:write(ser.serialize(tbl)) 41 | tableFile:close() 42 | end 43 | 44 | local function loadTable( sfile ) 45 | local tableFile = io.open(sfile) 46 | if tableFile ~= nil then 47 | return ser.unserialize(tableFile:read("*all")) 48 | else 49 | return nil 50 | end 51 | end 52 | 53 | --------Base Functions 54 | 55 | local function convert( chars, dist, inv ) 56 | return string.char( ( string.byte( chars ) - 32 + ( inv and -dist or dist ) ) % 95 + 32 ) 57 | end 58 | 59 | local function crypt(str,k,inv) 60 | local enc= ""; 61 | for i=1,#str do 62 | if(#str-k[5] >= i or not inv)then 63 | for inc=0,3 do 64 | if(i%4 == inc)then 65 | enc = enc .. convert(string.sub(str,i,i),k[inc+1],inv); 66 | break; 67 | end 68 | end 69 | end 70 | end 71 | if(not inv)then 72 | for i=1,k[5] do 73 | enc = enc .. string.char(math.random(32,126)); 74 | end 75 | end 76 | return enc; 77 | end 78 | 79 | local function splitString(str, sep) 80 | local sep, fields = sep or ":", {} 81 | local pattern = string.format("([^%s]+)", sep) 82 | str:gsub(pattern, function(c) fields[#fields+1] = c end) 83 | return fields 84 | end 85 | 86 | local function deepcopy(orig) 87 | local orig_type = type(orig) 88 | local copy 89 | if orig_type == 'table' then 90 | copy = {} 91 | for orig_key, orig_value in next, orig, nil do 92 | copy[deepcopy(orig_key)] = deepcopy(orig_value) 93 | end 94 | setmetatable(copy, deepcopy(getmetatable(orig))) 95 | else -- number, string, boolean, etc 96 | copy = orig 97 | end 98 | return copy 99 | end 100 | 101 | local function setGui(pos, text, wrap, color) 102 | term.setCursor(1,pos) 103 | term.clearLine() 104 | if color then gpu.setForeground(color) else gpu.setForeground(0xFFFFFF) end 105 | if wrap then print(text) else term.write(text) end 106 | end 107 | 108 | local function pageChange(dir,pos,length,call,...) 109 | if dir == "hor" then 110 | if type(pos) == "boolean" then 111 | if pos then 112 | if pageNum < length then 113 | pageNum = pageNum + 1 114 | end 115 | else 116 | if pageNum > 1 then 117 | pageNum = pageNum - 1 118 | end 119 | end 120 | else 121 | pageNum = pos 122 | end 123 | elseif dir == "ver" then 124 | if type(pos) == "boolean" then 125 | if pos then 126 | if listNum < length + 1 then 127 | listNum = listNum + 1 128 | end 129 | else 130 | if listNum > 1 then 131 | listNum = listNum - 1 132 | end 133 | end 134 | else 135 | listNum = pos 136 | end 137 | elseif dir == "setup" then 138 | pageNum = pos 139 | listNum = 1 140 | end 141 | call(...) 142 | end 143 | 144 | -- removed AutoUpdate function due to being unnecessary to the checking of if a change was detected 145 | 146 | --------Called Functions 147 | 148 | local function colorSearch(color,side) 149 | local c,s = -1,-1 150 | if type(color) == "number" then 151 | c = color 152 | else 153 | for i=1,#redColorTypes,1 do 154 | if redColorTypes[i] == color then 155 | c = i - 1 156 | end 157 | end 158 | end 159 | for i=1,#redSideTypes,1 do 160 | if type(side) == "number" then 161 | s = side 162 | else 163 | if redSideTypes[i] == side then 164 | s = i - 1 165 | end 166 | end 167 | end 168 | return c,s 169 | end 170 | 171 | local function redlinkcheck(color,side) 172 | for key,value in pairs(sectorSettings) do 173 | if key ~= "cryptKey" and key ~= "port" then --We don't want cryptKey or port being used 174 | if value.open.color == color and value.open.side == side then 175 | sectorSettings[key].open.color = -1 176 | sectorSettings[key].open.side = -1 177 | end 178 | if value.lock.color == color and value.lock.side == side then 179 | sectorSettings[key].lock.side = -1 180 | sectorSettings[key].lock.color = -1 181 | end 182 | if value.disable.color == color and value.disable.side == side then 183 | sectorSettings[key].disable.side = -1 184 | sectorSettings[key].disable.color = -1 185 | end 186 | end 187 | end 188 | end 189 | 190 | local function arrangeSectors(query) 191 | sector = {} 192 | local amt = (#query) * 3 193 | local count = 1 194 | local save = false 195 | for i=1,math.ceil(amt/9),1 do 196 | sector[i] = {} 197 | for j=1,3,1 do 198 | if query[count] ~= nil then 199 | sector[i][j] = deepcopy(query[count]) 200 | if sectorSettings[query[count].uuid] == nil then 201 | sectorSettings[query[count].uuid] = {["open"]={["side"]=-1,["color"]=-1},["lock"]={["side"]=-1,["color"]=-1},["disable"]={["side"]=-1,["color"]=-1}} 202 | save = true 203 | end 204 | count = count + 1 205 | end 206 | end 207 | end 208 | for key,value in pairs(sectorSettings) do 209 | local here = false 210 | if key == "cryptKey" or key == "port" then 211 | here = true 212 | else 213 | for i=1,#query,1 do 214 | if query[i].uuid == key then 215 | here = true 216 | break 217 | end 218 | end 219 | end 220 | if here == false then 221 | sectorSettings[key] = nil 222 | save = true 223 | end 224 | end 225 | if save then 226 | saveTable(sectorSettings,"sectorsetup.txt") 227 | end 228 | end 229 | 230 | local function sectorGui(editmode) 231 | setGui(1,"Sector Control Program") 232 | if #sector == 0 then 233 | setGui(2,"Create a sector to begin") 234 | else 235 | setGui(2,"Page " .. pageNum .. "/" .. #sector) 236 | setGui(3,"") 237 | setGui(4,"------------------------------") 238 | local pre, count = "> ",1 239 | if (#sector[pageNum] * 3) < listNum then 240 | listNum = (#sector[pageNum] * 3) 241 | end 242 | if listNum == count then 243 | pre = "> " 244 | else 245 | pre = " " 246 | end 247 | for i=1,#sector[pageNum],1 do 248 | local secKeys = {["disable"] = "Clear sector ",["lock"] = "Lockdown sector ",["open"] = "Open sector "} 249 | for j=1,3,1 do 250 | local key = "" 251 | if j == 1 then 252 | key = "open" 253 | elseif j == 2 then 254 | key = "lock" 255 | else 256 | key = "disable" 257 | end 258 | if listNum == count then 259 | pre = "> " 260 | else 261 | pre = " " 262 | end 263 | setGui(count + 4,sectorSettings[sector[pageNum][i].uuid][key].side ~= -1 and pre .. value .. sector[pageNum][i].name .. ": " .. redSideTypes[sectorSettings[sector[pageNum][i].uuid][key].side + 1] .. " : " .. redColorTypes[sectorSettings[sector[pageNum][i].uuid][key].color + 1] or pre .. value .. sector[pageNum][i].name .. ": " .. "unlinked : unlinked") 264 | count = count + 1 265 | end 266 | end 267 | count = count + 4 268 | setGui(count,"------------------------------") 269 | end 270 | end 271 | 272 | --------Main Program 273 | 274 | term.clear() 275 | local fill = io.open("redstonelinks.txt", "r") 276 | if fill~=nil then 277 | io.close(fill) 278 | else 279 | modem.open(syncPort) 280 | modem.broadcast(syncPort,"syncport") 281 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 282 | modem.close(syncPort) 283 | if e then 284 | modemPort = tonumber(msg) 285 | else 286 | print("What port is the server running off of?") 287 | local text = term.read() 288 | modemPort = tonumber(text:sub(1,-2)) 289 | term.clear() 290 | end 291 | 292 | saveTable({["cryptKey"]={1,2,3,4,5},["port"]=modemPort},"redstonelinks.txt") 293 | print("Crypt key is set to default (1,2,3,4,5)") 294 | end 295 | 296 | sectorSettings = loadTable("redstonelinks.txt") 297 | 298 | if sectorSettings.cryptKey == nil then 299 | sectorSettings.cryptKey = {1,2,3,4,5} 300 | print("Crypt key is set to default (1,2,3,4,5)") 301 | modem.open(syncPort) 302 | modem.broadcast(syncPort,"syncport") 303 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 304 | modem.close(syncPort) 305 | if e then 306 | modemPort = tonumber(msg) 307 | else 308 | print("What port is the server running off of?") 309 | local text = term.read() 310 | modemPort = tonumber(text:sub(1,-2)) 311 | term.clear() 312 | end 313 | sectorSettings.port = modemPort 314 | saveTable(sectorSettings,"redstonelinks.txt") 315 | end 316 | if sectorSettings.default ~= nil then 317 | sectorSettings.default = nil 318 | for key, value in pairs(sectorSettings) do 319 | if key ~= "cryptKey" and key ~= "port" then 320 | value.disable = {["side"]=-1,["color"]=-1} 321 | end 322 | end 323 | end 324 | 325 | modemPort = sectorSettings.port 326 | 327 | print("Sending query to server...") 328 | modem.open(modemPort) 329 | modem.broadcast(modemPort,"getquery",ser.serialize({"sectors"})) --TODO: Remove all sectorStatus calls 330 | local e,_,_,_,_,msg = event.pull(3,"modem_message") 331 | modem.close(modemPort) 332 | if e == nil then 333 | print("No query received. Assuming old server system is in place and will not work") 334 | os.exit() 335 | else 336 | print("Query received") 337 | msg = crypt(msg,sectorSettings.cryptKey,true) 338 | query = ser.unserialize(msg).data.sectors 339 | end 340 | modem.open(modemPort) 341 | 342 | arrangeSectors(query) 343 | 344 | --[[thread.create(function() --Unneeded function. 345 | while true do 346 | local ev, p1, p2, p3, p4, p5 = event.pull("key_down") 347 | local char = tonumber(keyboard.keys[p3]) 348 | if char ~= nil then 349 | if char > 0 then 350 | if char <= lengthNum then 351 | event.push("numInput",char) 352 | lengthNum = 0 353 | end 354 | end 355 | end 356 | end 357 | end)]] 358 | 359 | local editmode = false 360 | 361 | pageChange("setup",1,#sector, sectorGui, editmode) 362 | 363 | while true do 364 | local ev,num,side,key,value,command,msg = event.pullMultiple("modem_message","redstone_changed","key_down") 365 | if #sector ~= 0 then 366 | if ev == "modem_message" then 367 | if command == "getSectorList" then 368 | query = ser.unserialize(msg).sectors 369 | arrangeSectors(query) 370 | pageChange("setup",1,#sector, sectorGui, editmode) 371 | end 372 | elseif ev == "key_down" then 373 | if editmode == false then 374 | local char = keyboard.keys[key] 375 | if char == "left" then 376 | term.clear() 377 | pageChange("hor",false,#sector, sectorGui, editmode) 378 | os.sleep(0.5) 379 | elseif char == "right" then 380 | term.clear() 381 | pageChange("hor",true,#sector, sectorGui, editmode) 382 | os.sleep(0.5) 383 | elseif char == "up" then 384 | term.clear() 385 | pageChange("ver",false,(#sector[pageNum]*2) + 1, sectorGui, editmode) 386 | os.sleep(0.5) 387 | elseif char == "down" then 388 | term.clear() 389 | pageChange("ver",true,(#sector[pageNum]*2) + 1, sectorGui, editmode) 390 | os.sleep(0.5) 391 | elseif char == "enter" then 392 | setGui(20,"Which side should redstone input from?") 393 | term.setCursor(1,21) 394 | term.clearLine() 395 | local side = term.read():sub(1,-2) 396 | if tonumber(side) ~= nil then 397 | side = tonumber(side) 398 | end 399 | setGui(20,"Which color should be checked?") 400 | term.setCursor(1,21) 401 | term.clearLine() 402 | local color = term.read():sub(1,-2) 403 | if tonumber(color) ~= nil then 404 | color = tonumber(color) 405 | end 406 | color, side = colorSearch(color,side) 407 | if color ~= -1 and side ~= -1 then 408 | redlinkcheck(color,side) 409 | if (listNum)%3 == 0 then 410 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].disable.color = color 411 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].disable.side = side 412 | elseif (listNum)%3 == 2 then 413 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].lock.color = color 414 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].lock.side = side 415 | else 416 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].open.color = color 417 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].open.side = side 418 | end 419 | end 420 | saveTable(sectorSettings,"redstonelinks.txt") 421 | pageChange("hor",pageNum,#sector, sectorGui, editmode) 422 | os.sleep(0.5) 423 | elseif char == "back" then 424 | if (listNum)%3 == 0 then 425 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].disable.color = -1 426 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].disable.side = -1 427 | elseif (listNum)%3 == 2 then 428 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].lock.color = -1 429 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].lock.side = -1 430 | else 431 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].open.color = -1 432 | sectorSettings[sector[pageNum][math.ceil((listNum)/3)].uuid].open.side = -1 433 | end 434 | pageChange("hor",pageNum,#sector, sectorGui, editmode) 435 | os.sleep(0.5) 436 | end 437 | end 438 | elseif ev == "redstone_changed" then 439 | local officialChange = {false} --If the change in redstone is something saved to redstonelinks.txtr 440 | if key == 0 and value > 0 then 441 | for i=1,#query,1 do 442 | if sectorSettings[query[i].uuid].open.side == side and sectorSettings[query[i].uuid].open.color == command then 443 | officialChange[1] = true 444 | officialChange[2] = query[i].uuid 445 | officialChange[3] = side 446 | officialChange[4] = command 447 | officialChange[5] = 3 448 | break 449 | end 450 | if sectorSettings[query[i].uuid].lock.side == side and sectorSettings[query[i].uuid].lock.color == command then 451 | officialChange[1] = true 452 | officialChange[2] = query[i].uuid 453 | officialChange[3] = side 454 | officialChange[4] = command 455 | officialChange[5] = 2 456 | break 457 | end 458 | if sectorSettings[query[i].uuid].disable.side == side and sectorSettings[query[i].uuid].disable.color == command then 459 | officialChange[1] = true 460 | officialChange[2] = query[i].uuid 461 | officialChange[3] = side 462 | officialChange[4] = command 463 | officialChange[5] = 1 464 | break 465 | end 466 | --[[if sectorStatus[query[i].uuid] ~= current then --a change was detected 467 | officialChange = true 468 | end]] 469 | end 470 | end 471 | if officialChange[1] then 472 | modem.broadcast(modemPort,"sectorupdate",crypt(ser.serialize({officialChange[2],officialChange[5]}),sectorSettings.cryptKey)) 473 | end 474 | end 475 | else 476 | os.sleep(1) 477 | end 478 | end 479 | -------------------------------------------------------------------------------- /sectors/sectorcontrolgui.lua: -------------------------------------------------------------------------------- 1 | local version = "4.0.2" 2 | 3 | local sector = {} 4 | local sectorStatus = {} 5 | local sectorSettings = {} 6 | 7 | local modemPort = 1000 8 | local syncPort = 199 9 | 10 | local component = require("component") 11 | local gpu = component.gpu 12 | local event = require("event") 13 | local ser = require("serialization") 14 | local term = require("term") 15 | local thread = require("thread") 16 | local process = require("process") 17 | local uuid = require("uuid") 18 | local computer = component.computer 19 | local keyboard = require("keyboard") 20 | 21 | --local redstone = component.redstone 22 | local modem = component.modem 23 | 24 | local query 25 | 26 | local testR = true 27 | local lengthNum = 0 28 | local pageNum = 1 29 | local listNum = 1 30 | local secid 31 | 32 | local redColorTypes = {"white","orange","magenta","light blue","yellow","lime","pink","gray","silver","cyan","purple","blue","brown","green","red","black"} 33 | local redSideTypes = {"bottom","top","back","front","right","left"} 34 | 35 | local updatePulse = false 36 | 37 | --------Table To File 38 | 39 | local function saveTable( tbl,filename ) 40 | local tableFile = assert(io.open(filename, "w")) 41 | tableFile:write(ser.serialize(tbl)) 42 | tableFile:close() 43 | end 44 | 45 | local function loadTable( sfile ) 46 | local tableFile = io.open(sfile) 47 | if tableFile ~= nil then 48 | return ser.unserialize(tableFile:read("*all")) 49 | else 50 | return nil 51 | end 52 | end 53 | 54 | --------Base Functions 55 | 56 | local function convert( chars, dist, inv ) 57 | return string.char( ( string.byte( chars ) - 32 + ( inv and -dist or dist ) ) % 95 + 32 ) 58 | end 59 | 60 | local function crypt(str,k,inv) 61 | local enc= ""; 62 | for i=1,#str do 63 | if(#str-k[5] >= i or not inv)then 64 | for inc=0,3 do 65 | if(i%4 == inc)then 66 | enc = enc .. convert(string.sub(str,i,i),k[inc+1],inv); 67 | break; 68 | end 69 | end 70 | end 71 | end 72 | if(not inv)then 73 | for i=1,k[5] do 74 | enc = enc .. string.char(math.random(32,126)); 75 | end 76 | end 77 | return enc; 78 | end 79 | 80 | local function deepcopy(orig) 81 | local orig_type = type(orig) 82 | local copy 83 | if orig_type == 'table' then 84 | copy = {} 85 | for orig_key, orig_value in next, orig, nil do 86 | copy[deepcopy(orig_key)] = deepcopy(orig_value) 87 | end 88 | setmetatable(copy, deepcopy(getmetatable(orig))) 89 | else -- number, string, boolean, etc 90 | copy = orig 91 | end 92 | return copy 93 | end 94 | 95 | local function setGui(pos, text, wrap, color) 96 | term.setCursor(1,pos) 97 | term.clearLine() 98 | if color then gpu.setForeground(color) else gpu.setForeground(0xFFFFFF) end 99 | if wrap then print(text) else term.write(text) end 100 | end 101 | 102 | local function pageChange(dir,pos,length,call,...) 103 | if dir == "hor" then 104 | if pos then 105 | if pageNum < length then 106 | pageNum = pageNum + 1 107 | end 108 | else 109 | if pageNum > 1 then 110 | pageNum = pageNum - 1 111 | end 112 | end 113 | elseif dir == "ver" then 114 | if pos then 115 | if listNum < length + 1 then 116 | listNum = listNum + 1 117 | end 118 | else 119 | if listNum > 1 then 120 | listNum = listNum - 1 121 | end 122 | end 123 | elseif dir == "setup" then 124 | pageNum = pos 125 | listNum = 1 126 | end 127 | call(...) 128 | end 129 | 130 | -- removed AutoUpdate function due to being unnecessary to the checking of if a change was detected 131 | 132 | --------Called Functions 133 | 134 | local function arrangeSectors(query) 135 | sector = {} 136 | local amt = (#query) * 3 137 | local count = 1 138 | local save = false 139 | for i=1,math.ceil(amt/9),1 do 140 | sector[i] = {} 141 | for j=1,3,1 do 142 | if query[count] ~= nil then 143 | sector[i][j] = deepcopy(query[count]) 144 | if sectorSettings[query[count].uuid] == nil then 145 | sectorSettings[query[count].uuid] = {status=1} 146 | save = true 147 | end 148 | count = count + 1 149 | end 150 | end 151 | end 152 | for key,value in pairs(sectorSettings) do 153 | local here = false 154 | if key == "cryptKey" or key == "port" then 155 | here = true 156 | else 157 | for i=1,#query,1 do 158 | if query[i].uuid == key then 159 | here = true 160 | break 161 | end 162 | end 163 | end 164 | if here == false then 165 | sectorSettings[key] = nil 166 | save = true 167 | end 168 | end 169 | if save then 170 | saveTable(sectorSettings,"redstonelinks.txt") 171 | end 172 | end 173 | 174 | local function sectorGui(editmode) 175 | setGui(1,"Sector Control Program") 176 | local aft = " " 177 | if #sector == 0 then 178 | setGui(2,"Create a sector to begin") 179 | else 180 | setGui(2,"Page " .. pageNum .. "/" .. #sector) 181 | setGui(3,"") 182 | setGui(4,"------------------------------") 183 | local pre, count = "> ",1 184 | if (#sector[pageNum] * 3) < listNum then 185 | listNum = (#sector[pageNum] * 3) 186 | end 187 | if listNum == count then 188 | pre = "> " 189 | else 190 | pre = " " 191 | end 192 | for i=1,#sector[pageNum],1 do 193 | local secKeys = {[2] = "Clear",[1] = "Lockdown",[3] = "Open"} 194 | for key,value in ipairs(secKeys) do 195 | if listNum == count then 196 | pre = "> " 197 | else 198 | pre = " " 199 | end 200 | setGui(count + 4, pre .. sector[pageNum][i].name .. " : " .. value) 201 | count = count + 1 202 | end 203 | end 204 | count = count + 4 205 | setGui(count,"------------------------------") 206 | end 207 | end 208 | 209 | --------Main Program 210 | 211 | term.clear() 212 | local fill = io.open("redstonelinks.txt", "r") 213 | if fill~=nil then 214 | io.close(fill) 215 | else 216 | modem.open(syncPort) 217 | modem.broadcast(syncPort,"syncport") 218 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 219 | modem.close(syncPort) 220 | if e then 221 | modemPort = tonumber(msg) 222 | else 223 | print("What port is the server running off of?") 224 | local text = term.read() 225 | modemPort = tonumber(text:sub(1,-2)) 226 | term.clear() 227 | end 228 | 229 | saveTable({["cryptKey"]={1,2,3,4,5},["port"]=modemPort},"redstonelinks.txt") 230 | print("Crypt key is set to default (1,2,3,4,5)") 231 | end 232 | 233 | sectorSettings = loadTable("redstonelinks.txt") 234 | 235 | if sectorSettings.cryptKey == nil then 236 | sectorSettings.cryptKey = {1,2,3,4,5} 237 | print("Crypt key is set to default (1,2,3,4,5)") 238 | modem.open(syncPort) 239 | modem.broadcast(syncPort,"syncport") 240 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 241 | modem.close(syncPort) 242 | if e then 243 | modemPort = tonumber(msg) 244 | else 245 | print("What port is the server running off of?") 246 | local text = term.read() 247 | modemPort = tonumber(text:sub(1,-2)) 248 | term.clear() 249 | end 250 | sectorSettings.port = modemPort 251 | saveTable(sectorSettings,"redstonelinks.txt") 252 | end 253 | if sectorSettings.default ~= nil then 254 | sectorSettings.default = nil 255 | for key, value in pairs(sectorSettings) do 256 | if key ~= "cryptKey" and key ~= "port" then 257 | value.disable = {["side"]=-1,["color"]=-1} 258 | end 259 | end 260 | end 261 | 262 | modemPort = sectorSettings.port 263 | 264 | print("Sending query to server...") 265 | modem.open(modemPort) 266 | modem.broadcast(modemPort,"getquery",ser.serialize({"sectors"})) --TODO: Remove all sectorStatus calls 267 | local e,_,_,_,_,msg = event.pull(3,"modem_message") 268 | modem.close(modemPort) 269 | if e == nil then 270 | print("No query received. Assuming old server system is in place and will not work") 271 | os.exit() 272 | else 273 | print("Query received") 274 | msg = crypt(msg,sectorSettings.cryptKey,true) 275 | query = ser.unserialize(msg).data.sectors 276 | end 277 | modem.open(modemPort) 278 | 279 | arrangeSectors(query) 280 | 281 | --[[thread.create(function() --Unneeded function. 282 | while true do 283 | local ev, p1, p2, p3, p4, p5 = event.pull("key_down") 284 | local char = tonumber(keyboard.keys[p3]) 285 | if char ~= nil then 286 | if char > 0 then 287 | if char <= lengthNum then 288 | event.push("numInput",char) 289 | lengthNum = 0 290 | end 291 | end 292 | end 293 | end 294 | end)]] 295 | 296 | local editmode = false 297 | 298 | pageChange("setup",1,#sector, sectorGui, editmode) 299 | 300 | while true do 301 | local ev,num,side,key,value,command,msg = event.pullMultiple("modem_message","redstone_changed","key_down") 302 | local state = 1 303 | editmode = false 304 | if #sector ~= 0 then 305 | if ev == "modem_message" then 306 | if command == "getSectorList" then 307 | query = ser.unserialize(msg).sectors 308 | arrangeSectors(query) 309 | end 310 | elseif ev == "key_down" then 311 | if editmode == false then 312 | local char = keyboard.keys[key] 313 | if char == "left" then 314 | term.clear() 315 | pageChange("hor",false,#sector, sectorGui, editmode) 316 | os.sleep(0.1) 317 | elseif char == "right" then 318 | term.clear() 319 | pageChange("hor",true,#sector, sectorGui, editmode) 320 | os.sleep(0.1) 321 | elseif char == "up" then 322 | term.clear() 323 | pageChange("ver",false,(#sector[pageNum]*3), sectorGui, editmode) 324 | os.sleep(0.1) 325 | elseif char == "down" then 326 | term.clear() 327 | pageChange("ver",true,(#sector[pageNum]*3), sectorGui, editmode) 328 | os.sleep(0.1) 329 | elseif char == "enter" then 330 | if listNum == 3 or listNum == 6 or listNum == 9 then state = 3 elseif listNum == 1 or listNum == 4 or listNum == 7 then state = 2 else state = 1 end 331 | if listNum <= 3 then 332 | if pageNum == 1 then 333 | secid = query[1] 334 | else 335 | secid = query[1+((pageNum-1)*3)] 336 | end 337 | elseif listNum <= 6 then 338 | if pageNum == 1 then 339 | secid = query[2] 340 | else 341 | secid = query[2+((pageNum-1)*3)] 342 | end 343 | else 344 | if pageNum == 1 then 345 | secid = query[3] 346 | else 347 | secid = query[3+((pageNum-1)*3)] 348 | end 349 | end 350 | modem.broadcast(modemPort,"sectorupdate",crypt(ser.serialize({secid.uuid,state}),sectorSettings.cryptKey)) 351 | os.sleep(0.1) 352 | end 353 | end 354 | end 355 | 356 | else 357 | os.sleep(1) 358 | end 359 | end 360 | -------------------------------------------------------------------------------- /security/Database Module/Main.lua: -------------------------------------------------------------------------------- 1 | local module = {} 2 | local component = require("component") 3 | local ser = require("serialization") 4 | local GUI = require("GUI") 5 | local scanner --if biometric reader is connected this isn't nil 6 | local writer --Card reader 7 | 8 | local handler --Holds the handler for cardinsert and cardremoval events in cardwriter 9 | 10 | local permissions = {} --Holds current user's permissions whos signed in 11 | 12 | local userTable 13 | 14 | local workspace, window, loc, database, style, compat = table.unpack({...}) 15 | local system, fs, event 16 | if compat == nil then 17 | system = require("System") --Set it to the MineOS 18 | fs = require("Filesystem") 19 | event = require("event") 20 | else 21 | system = compat.system 22 | fs = compat.fs 23 | event = compat.event 24 | end 25 | 26 | module.name = "Security" 27 | module.table = {"passes","passSettings","securityKeypads"} --passes is all card accounts; passSettings are the modular passes people can create 28 | module.debug = false 29 | module.config = {["secAPI"] = {["label"] = "Security API",["type"]="bool",["default"]=true,["server"]=true},["quickMCLink"] = {["label"] = "Allow quikidlink?",["type"]="bool",["default"]=false,["server"]=true}} --secAPI allows getVar and setVar commands by securityAPI; quikIDLink allows use of quikidlink program to link user with seperate bio reader 30 | 31 | module.init = function(usTable) 32 | userTable = usTable 33 | end 34 | 35 | if component.isAvailable("os_cardwriter") then --see if it exists, otherwise close/crash program. 36 | writer = component.os_cardwriter 37 | else 38 | GUI.alert(loc.cardwriteralert) 39 | return 40 | end 41 | if component.isAvailable("os_biometric") then --see if it exists, otherwise you can't link user biometrics 42 | scanner = component.os_biometric 43 | end 44 | 45 | module.onTouch = function() 46 | local tabWindow, tabs, cardStatusLabel, selected 47 | local userEdit, passEdit 48 | do --keep it contained to remove memory after done 49 | local result, reason = loadfile(fs.path(system.getCurrentScript()) .. "Modules/modid" .. tostring(module.id) .. "/pass.lua") 50 | if result then 51 | passEdit = result 52 | else 53 | GUI.alert("Failed to load file pass.lua: " .. tostring(reason)) 54 | end 55 | result, reason = loadfile(fs.path(system.getCurrentScript()) .. "Modules/modid" .. tostring(module.id) .. "/user.lua") 56 | if result then 57 | userEdit = result 58 | else 59 | GUI.alert("Failed to load file user.lua: " .. tostring(reason)) 60 | end 61 | end 62 | 63 | local function migrateTab(_, button) 64 | if not button.doTheMove then 65 | tabWindow:removeChildren() 66 | end 67 | if selected ~= button.myId then 68 | local success, result = pcall(button.toRun, workspace, tabWindow, loc, database, style, permissions, userTable) 69 | if not success then 70 | GUI.alert("Failed to run file: " .. tostring(result)) 71 | end 72 | workspace:draw() 73 | selected = button.myId 74 | end 75 | end 76 | 77 | --Database name and stuff and CardWriter 78 | 79 | local function eventCallback(ev, id) --changing text of label if user inserts or removes all cards from cardwriter 80 | if ev == "cardInsert" then 81 | cardStatusLabel.text = loc.cardpresent 82 | elseif ev == "cardRemove" then 83 | cardStatusLabel.text = loc.cardabsent 84 | end 85 | end 86 | 87 | window:addChild(GUI.panel(123,1,12,3,style.cardStatusPanel)) 88 | cardStatusLabel = window:addChild(GUI.label(124, 2, 10,1,style.cardStatusLabel,loc.cardabsent)) 89 | handler = event.addhandler(eventCallback) --create callback to the handler to check for cardinsert and cardremoval 90 | 91 | tabWindow = window:addChild(GUI.container(1,4,window.width,window.height - 3)) 92 | tabs = window:addChild(GUI.list(1, 1, 75, 3, 2, 0, style.listBackground, style.listText, style.listAltBack, style.listAltText, style.listSelectedBack, style.listSelectedText, true)) 93 | tabs:setDirection(GUI.DIRECTION_HORIZONTAL) 94 | tabs:setAlignment(GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP) 95 | local meh = tabs:addItem("Cards") 96 | meh.onTouch = migrateTab 97 | meh.myId = 1 98 | meh.toRun = userEdit 99 | meh = tabs:addItem("Passes / Keypad") 100 | meh.onTouch = migrateTab 101 | meh.myId = 2 102 | meh.toRun = passEdit 103 | meh.disabled = database.checkPerms("security",{"varmanagement","keypad"},true) 104 | 105 | tabs.selected = 1 106 | migrateTab(nil, {["doTheMove"]=true,["myId"]=1,["toRun"]=userEdit}) 107 | end 108 | 109 | module.close = function() --when user switches modules 110 | event.removehandler(handler) --don't keep looking for event 111 | return {"passes","passSettings"} --returns what I want updated (if autoupdate enabled) 112 | end 113 | 114 | return module 115 | -------------------------------------------------------------------------------- /security/Database Module/Pass.lua: -------------------------------------------------------------------------------- 1 | --A second file I created to be able to store all the pass editing in a seperate file 2 | local workspace, window, loc, database, style, permissions, userTable = table.unpack({...}) 3 | 4 | local component = require("component") 5 | local ser = require("serialization") 6 | local GUI = require("GUI") 7 | local uuid = require("uuid") 8 | local modem = component.modem 9 | 10 | local modemPort = 199 11 | 12 | --Variable declarations for keypad stuff 13 | local padBox, padLabel, padPass, padNew, padNewKey, padDel 14 | local canPad = database.checkPerms("security",{"varmanagement","keypad"},true) --whether they have keypad perms 15 | local canPass = database.checkPerms("security",{"varmanagement"},true) 16 | 17 | local function split(s, delimiter) --splits string to table. "e,f,g" to {"e","f","g"} 18 | local result = {}; 19 | for match in (s..delimiter):gmatch("(.-)"..delimiter) do 20 | table.insert(result, match); 21 | end 22 | return result; 23 | end 24 | 25 | local function keypadCallback(_,button) 26 | if padBox:count() > 0 then 27 | local selected = padBox.selectedItem 28 | if button == nil then 29 | button = padBox:getItem(selected) 30 | end 31 | padLabel.text = userTable.securityKeypads[button.key].label 32 | padPass.text = canPad and "****" or userTable.securityKeypads[button.key].pass 33 | padLabel.disabled = canPad 34 | padPass.disabled = canPad 35 | end 36 | end 37 | 38 | local function updateKeyList() 39 | database.save() 40 | local selected = padBox.selectedItem 41 | if padBox:count() > 0 then 42 | padBox:clear() 43 | end 44 | for key,value in pairs(userTable.securityKeypads) do 45 | local meh = padBox:addItem(key) 46 | meh.key = key 47 | meh.onTouch = keypadCallback 48 | end 49 | if padBox:count() < selected then 50 | selected = selected - 1 51 | end 52 | padDel.disabled = true 53 | if padBox:count() ~= 0 then 54 | padDel.disabled = false 55 | padBox.selectedItem = selected 56 | end 57 | database.update({"securityKeypads"}) 58 | end 59 | 60 | local function padNewF() 61 | if padNewKey.text ~= "" then 62 | userTable.securityKeypads[padNewKey.text] = {["pass"]="1234",["label"]=padNewKey.text} 63 | padNewKey.text = "" 64 | updateKeyList() 65 | end 66 | end 67 | 68 | local function padDelF() 69 | local selected = padBox.selectedItem 70 | local sel = padBox:getItem(selected) 71 | userTable.securityKeypads[sel.key] = nil 72 | padLabel.disabled = true 73 | padPass.disabled = true 74 | updateKeyList() 75 | end 76 | 77 | local function passLabelCallback() 78 | local selected = padBox:getItem(padBox.selectedItem) 79 | userTable.securityKeypads[selected.key].label = padLabel.text 80 | end 81 | 82 | local function passInputCallback() 83 | local selected = padBox:getItem(padBox.selectedItem) 84 | if tonumber(padPass.text) ~= nil and tonumber(padPass.text) >= 1000 and tonumber(padPass.text) <= 9999 then 85 | userTable.securityKeypads[selected.key].pass = padPass.text 86 | else 87 | padPass.text = userTable.securityKeypads[selected.key].pass 88 | end 89 | end 90 | 91 | --Variable declarations for Variable pass stuff 92 | local addVarButton, delVarButton, editVarButton, updateVarButton, clearVarButton, varList, varLabel, varDesc 93 | local varKeyInput, varLabelInput, varTypeSelect, addVarArray, extraVar, extraVar2 --NOTE: Updatevarbutton works in both add and edit mode 94 | local varMode = "none" --Indicates the mode, so pressing add button knows what to do when pressed. add means that a new one is added to the list. edit means var will be edited. none means nothing will happen (just in case) 95 | 96 | local function passComboPress() 97 | local describe = {["string"]="Regular String",["-string"]="Multi String",["int"]="Level",["-int"]="Group",["bool"]="Bool"} 98 | local selected = varList.selectedItem 99 | varLabel.text = "Label: " .. userTable.passSettings.label[selected] 100 | varDesc.text = "Desc: " .. describe[userTable.passSettings.type[selected]] 101 | if userTable.passSettings.type[selected] == "string" or userTable.passSettings.type[selected] == "-string" then 102 | varDesc.text = varDesc.text .. " | " .. (userTable.passSettings.data[selected] == 1 and "Editable" or userTable.passSettings.data[selected] == 2 and "Uneditable" or "Hidden") 103 | elseif userTable.passSettings.type[selected] == "int" then 104 | varDesc.text = varDesc.text .. " | " .. (userTable.passSettings.above[selected] and "Checks above" or "Checks exact") 105 | elseif userTable.passSettings.type[selected] == "-int" then 106 | varDesc.text = varDesc.text .. " | " .. tostring(#userTable.passSettings.data[selected]) .. " groups" 107 | end 108 | editVarButton.disabled = userTable.passSettings.type[selected] == "bool" and true or false 109 | delVarButton.disabled = false 110 | end 111 | 112 | local function updatePassCombo() 113 | if varList:count() > 0 then 114 | varList:clear() 115 | end 116 | for i=1,#userTable.passSettings.var,1 do 117 | local k = varList:addItem(userTable.passSettings.var[i]) 118 | k.onTouch = passComboPress 119 | end 120 | varLabel.text = "Label: NAN" 121 | varDesc.text = "Desc: NAN" 122 | editVarButton.disabled = true 123 | delVarButton.disabled = true 124 | end 125 | 126 | local function checkTypeCallback() --Used when creating a var and choosing the type of var, or if editing 127 | local typeArray = {"string","-string","int","-int","bool"} 128 | local selected = varTypeSelect.selectedItem 129 | if varMode == "add" then --if add, it sets it all to default 130 | addVarArray.above = false 131 | addVarArray.data = false 132 | addVarArray.type = typeArray[selected] 133 | end 134 | if extraVar ~= nil then --if already populated, remove first so it can be readded 135 | extraVar:remove() 136 | extraVar = nil 137 | end 138 | --Merged edit and add mode checks 139 | if selected == 3 then --int (number) 140 | extraVar = window:addChild(GUI.button(36,19,32,1, style.containerButton,style.containerText,style.containerSelectButton,style.containerSelectText, loc.newvarcheckabove)) 141 | extraVar.onTouch = function() --a button to determine whether to check above or not. Checkabove means if needed 1 and they have 3, it lets them in. If false, 3 doesn't work 142 | addVarArray.above = extraVar.pressed 143 | end 144 | extraVar.switchMode = true 145 | if varMode == "edit" then 146 | extraVar.pressed = addVarArray.above 147 | else 148 | addVarArray.data = false 149 | end 150 | elseif selected == 4 then -- -int (groups) 151 | extraVar = window:addChild(GUI.input(36,19,32,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.newvargroup)) 152 | extraVar.onInputFinished = function() --Input the groups into a textbox splitting with a comma 153 | addVarArray.data = split(extraVar.text,",") 154 | end 155 | if varMode == "edit" then 156 | local isme = addVarArray.data[1] 157 | for i=2,#addVarArray.data,1 do --combine back into a string to be rejoined after saving 158 | isme = isme .. "," .. addVarArray.data[i] 159 | end 160 | extraVar.text = isme 161 | else 162 | addVarArray.data = "" 163 | end 164 | elseif selected == 1 or selected == 2 then --string or -string 165 | extraVar = window:addChild(GUI.comboBox(36,19,32,1,style.containerComboBack,style.containerComboText,style.containerComboArrowBack,style.containerComboArrowText)) 166 | local sub = function() 167 | addVarArray.data = extraVar.selectedItem 168 | end --you choose whether they can edit it, only view it, or can't see it (only changed by setVar and getVar) 169 | extraVar:addItem("Editable").onTouch = sub 170 | extraVar:addItem("Uneditable").onTouch = sub 171 | extraVar:addItem("Hidden").onTouch = sub 172 | if varMode == "edit" then 173 | extraVar.selectedItem = addVarArray.data 174 | else 175 | addVarArray.data = 1 176 | end 177 | else --bool (no config and shouldn't be able to edit at all) 178 | extraVar = window:addChild(GUI.label(36,19,3,3,style.passNameLabel,"NAN")) 179 | if varMode == "add" then 180 | addVarArray.data = false 181 | end 182 | end 183 | end 184 | 185 | local function clearVarF() --Clear current stuff on creation area 186 | varKeyInput.text = "" 187 | varKeyInput.disabled = true 188 | varLabelInput.text = "" 189 | varLabelInput.disabled = true 190 | varTypeSelect.selectedItem = 5 191 | varTypeSelect.disabled = true 192 | addVarArray = nil 193 | if extraVar ~= nil then 194 | extraVar:remove() 195 | extraVar = window:addChild(GUI.label(36,19,3,3,style.passNameLabel,"NAN")) 196 | end 197 | updateVarButton.disabled = true 198 | clearVarButton.disabled = true 199 | varMode = "none" 200 | end 201 | 202 | local function addVarF() --Prep creation area for adding a var 203 | if varMode == "none" then 204 | varKeyInput.disabled = false 205 | varLabelInput.disabled = false 206 | varTypeSelect.disabled = false 207 | varTypeSelect.selectedItem = 5 208 | addVarArray = {["var"]="",["label"]="",["calls"]=uuid.next(),["type"]="bool",["above"]=false,["data"]=false} 209 | extraVar2 = nil 210 | updateVarButton.disabled = false 211 | clearVarButton.disabled = false 212 | varMode = "add" 213 | else 214 | GUI.alert("Please clear current changes in var edit mode before adding a var") 215 | end 216 | end 217 | 218 | local function editVarF() --Prep creation area for editing a var 219 | if varMode == "none" then 220 | local selected = varList.selectedItem 221 | addVarArray = {["var"]=userTable.passSettings.var[selected],["label"]=userTable.passSettings.label[selected],["type"]=userTable.passSettings.type[selected],["above"]=userTable.passSettings.above[selected],["data"]=userTable.passSettings.data[selected]} 222 | varKeyInput.disabled = true 223 | varKeyInput.text = addVarArray.var 224 | varLabelInput.disabled = false 225 | varLabelInput.text = addVarArray.label 226 | varTypeSelect.disabled = true 227 | varTypeSelect.selectedItem = addVarArray.type == "string" and 1 or addVarArray.type == "-string" and 2 or addVarArray.type == "int" and 3 or addVarArray.type == "-int" and 4 or 5 228 | extraVar2 = nil 229 | updateVarButton.disabled = false 230 | clearVarButton.disabled = false 231 | varMode = "edit" 232 | checkTypeCallback() 233 | else 234 | GUI.alert("Please clear current changes in var edit mode before editing a var") 235 | end 236 | end 237 | 238 | local function delVarF() --delete a created var 239 | local selected = varList.selectedItem 240 | table.remove(userTable.passSettings.data,selected) 241 | table.remove(userTable.passSettings.label,selected) 242 | table.remove(userTable.passSettings.calls,selected) 243 | table.remove(userTable.passSettings.type,selected) 244 | table.remove(userTable.passSettings.above,selected) 245 | for i=1,#userTable.passes,1 do 246 | userTable.passes[i][userTable.passSettings.var[selected]] = nil 247 | end 248 | table.remove(userTable.passSettings.var,selected) 249 | database.save() 250 | database.update({"passes","passSettings"}) 251 | updatePassCombo() 252 | end 253 | 254 | local searchBase = {"name","blocked","staff","uuid","link","mcid"} 255 | 256 | local function updateVarF() --Either add or change (depending on add or edit mode) a var 257 | if varMode == "add" then 258 | if addVarArray.var ~= "" and addVarArray.label ~= "" then 259 | local skipAll = false 260 | for _, value in pairs(searchBase) do 261 | if value == addVarArray.var then 262 | skipAll = true 263 | break 264 | end 265 | end 266 | if not skipAll then 267 | for _, value in pairs(userTable.passSettings.var) do 268 | if value == addVarArray.var then 269 | skipAll = true 270 | break 271 | end 272 | end 273 | end 274 | if not skipAll then 275 | for i=1,#userTable.passes,1 do 276 | if addVarArray.type == "string" then 277 | userTable.passes[i][addVarArray.var] = "none" 278 | elseif addVarArray.type == "-string" then 279 | userTable.passes[i][addVarArray.var] = {} 280 | elseif addVarArray.type == "int" or addVarArray.type == "-int" then 281 | userTable.passes[i][addVarArray.var] = 0 282 | elseif addVarArray.type == "bool" then 283 | userTable.passes[i][addVarArray.var] = false 284 | else 285 | GUI.alert(loc.addvaralert) 286 | return 287 | end 288 | end 289 | table.insert(userTable.passSettings.var,addVarArray.var) 290 | table.insert(userTable.passSettings.label,addVarArray.label) 291 | table.insert(userTable.passSettings.calls,addVarArray.calls) 292 | table.insert(userTable.passSettings.type,addVarArray.type) 293 | table.insert(userTable.passSettings.above,addVarArray.above) 294 | table.insert(userTable.passSettings.data,addVarArray.data) 295 | database.save() 296 | database.update({"passes","passSettings"}) 297 | clearVarF() 298 | updatePassCombo() 299 | else 300 | GUI.alert("Var key conflicts with another one already created. Please change it.") 301 | end 302 | else 303 | GUI.alert("Please add a var key or label before updating") 304 | end 305 | elseif varMode == "edit" then 306 | local selected = 1 307 | for _,value in pairs(userTable.passSettings.var) do 308 | if value == addVarArray.var then 309 | break 310 | else 311 | selected = selected + 1 312 | end 313 | end 314 | if selected <= #userTable.passSettings.var then 315 | if userTable.passSettings.type[selected] == "int" then 316 | userTable.passSettings.above[selected] = addVarArray.above 317 | elseif userTable.passSettings.type[selected] == "-int" or userTable.passSettings.type[selected] == "string" or userTable.passSettings.type[selected] == "-string" then 318 | userTable.passSettings.data[selected] = addVarArray.data 319 | end 320 | userTable.passSettings.label[selected] = addVarArray.label 321 | database.save() 322 | database.update({"passes","passSettings"}) 323 | clearVarF() 324 | updatePassCombo() 325 | else 326 | GUI.alert("Var not found in the list. Was it deleted?") 327 | end 328 | end 329 | end 330 | 331 | local function onVarKeyInput() 332 | addVarArray.var = varKeyInput.text 333 | end 334 | 335 | local function onVarLabelInput() 336 | addVarArray.label = varLabelInput.text 337 | end 338 | 339 | --Create keypad stuff 340 | window:addChild(GUI.label(1,1,3,3,style.passNameLabel,"Global Keypads")) 341 | padBox = window:addChild(GUI.comboBox(1,3,20,1,style.containerComboBack,style.containerComboText,style.containerComboArrowBack,style.containerComboArrowText)) 342 | padDel = window:addChild(GUI.button(22,3,10,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.delete)) 343 | padDel.onTouch = padDelF 344 | padDel.disabled = true 345 | window:addChild(GUI.label(1,5,3,3,style.passNameLabel,"Label")) 346 | padLabel = window:addChild(GUI.input(1,6,15,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", loc.inputname)) 347 | padLabel.onInputFinished = passLabelCallback 348 | padLabel.disabled = true 349 | window:addChild(GUI.label(17,5,3,3,style.passNameLabel,"Pin / Password")) 350 | padPass = window:addChild(GUI.input(17,6,15,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", loc.inputpass)) 351 | padPass.onInputFinished = passInputCallback 352 | padPass.disabled = true 353 | padNew = window:addChild(GUI.button(22,8,7,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.new)) 354 | padNew.onTouch = padNewF 355 | padNew.disabled = canPad 356 | padNewKey = window:addChild(GUI.input(1,8,20,1, style.passInputBack,style.passInputText,style.passInputPlaceholder,style.passInputFocusBack,style.passInputFocusText, "", "input key")) 357 | padNewKey.disabled = canPad 358 | window:addChild(GUI.panel(34,2,1,28,style.bottomDivider)) --Create pass creation stuff 359 | window:addChild(GUI.label(36,1,3,3,style.passNameLabel,"Pass Management")) 360 | varList = window:addChild(GUI.comboBox(36,3,32,1,style.containerComboBack,style.containerComboText,style.containerComboArrowBack,style.containerComboArrowText)) 361 | varList.disabled = canPass 362 | varLabel = window:addChild(GUI.label(36,5,3,3,style.passNameLabel,"Label: NAN")) 363 | varDesc = window:addChild(GUI.label(36,7,3,3,style.passNameLabel,"Desc: NAN")) 364 | addVarButton = window:addChild(GUI.button(36,9,10,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.addvar)) 365 | addVarButton.onTouch = addVarF 366 | addVarButton.disabled = canPass 367 | editVarButton = window:addChild(GUI.button(47,9,10,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.editvar)) 368 | editVarButton.onTouch = editVarF 369 | editVarButton.disabled = true 370 | delVarButton = window:addChild(GUI.button(58,9,10,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.delvar)) 371 | delVarButton.onTouch = delVarF 372 | delVarButton.disabled = true 373 | window:addChild(GUI.panel(36,11,32,1,style.bottomDivider)) 374 | varKeyInput = window:addChild(GUI.input(36,13,32,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.newvarkey)) 375 | varKeyInput.onInputFinished = onVarKeyInput 376 | varKeyInput.disabled = true 377 | varLabelInput = window:addChild(GUI.input(36,15,32,1, style.containerInputBack,style.containerInputText,style.containerInputPlaceholder,style.containerInputFocusBack,style.containerInputFocusText, "", loc.newvarlabel)) 378 | varLabelInput.onInputFinished = onVarLabelInput 379 | varLabelInput.disabled = true 380 | varTypeSelect = window:addChild(GUI.comboBox(36,17,32,1, style.containerComboBack,style.containerComboText,style.containerComboArrowBack,style.containerComboArrowText)) 381 | local lik = varTypeSelect:addItem("String") 382 | lik.onTouch = checkTypeCallback --every time one is selected it refreshes the extra setting needed for certain choices 383 | lik = varTypeSelect:addItem("Multi-String") 384 | lik.onTouch = checkTypeCallback 385 | lik = varTypeSelect:addItem("Level (Int)") 386 | lik.onTouch = checkTypeCallback 387 | lik = varTypeSelect:addItem("Group") 388 | lik.onTouch = checkTypeCallback 389 | lik = varTypeSelect:addItem("Pass (true/false)") 390 | lik.onTouch = checkTypeCallback 391 | varTypeSelect.selectedItem = 5 392 | varTypeSelect.disabled = true 393 | extraVar = window:addChild(GUI.label(36,19,3,3,style.passNameLabel,"NAN")) 394 | updateVarButton = window:addChild(GUI.button(36,21,20,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, loc.update)) 395 | updateVarButton.onTouch = updateVarF 396 | updateVarButton.disabled = true 397 | clearVarButton = window:addChild(GUI.button(36,23,20,1, style.passButton, style.passText, style.passSelectButton, style.passSelectText, "clear")) 398 | clearVarButton.onTouch = clearVarF 399 | clearVarButton.disabled = true 400 | 401 | updateKeyList() 402 | updatePassCombo() -------------------------------------------------------------------------------- /security/Server Module/security.lua: -------------------------------------------------------------------------------- 1 | local userTable = {} 2 | local doorTable = {} 3 | local server = {} 4 | local modemPort = 199 5 | 6 | local component = require("component") 7 | local modem = component.modem 8 | local ser = require("serialization") 9 | 10 | local module = {} 11 | module.name = "passes" 12 | module.commands = {"rcdoors","checkLinked","getvar","setvar","checkRules","linkMCID","checkKeypad"} 13 | module.skipcrypt = {} 14 | module.table = {["passes"]={},["passSettings"]={["var"]={"level"},["label"]={"Level"},["calls"]={"checkLevel"},["type"]={"int"},["above"]={true},["data"]={false}},["securityKeypads"] = {["testone"]={["pass"]="1234",["label"]="Test One"}}} 15 | module.debug = false 16 | module.version = "4.0.3" 17 | module.id = 1111 18 | 19 | local function getPassID(command,rules) 20 | local bill 21 | if rules ~= nil then 22 | for i=1,#rules,1 do 23 | if rules[i].uuid == command then 24 | command = rules[i].call 25 | bill = i 26 | break 27 | end 28 | end 29 | end 30 | for i=1,#userTable.passSettings.calls,1 do 31 | if command == userTable.passSettings.calls[i] then 32 | return true, i, bill 33 | end 34 | end 35 | return command == "checkstaff" and true or false, command == "checkstaff" and 0 or false 36 | end 37 | 38 | local function getVar(var,user) 39 | for key, value in pairs(userTable.passes) do 40 | if string.sub(value.uuid,1,-14) == user or value.uuid == user then 41 | return value[var] 42 | end 43 | end 44 | return "Nil "..var 45 | end 46 | 47 | local function checkVar(rule,user,index) 48 | if index ~= 0 then 49 | if userTable.passSettings.type[index] == "string" then 50 | return user[userTable.passSettings.var[index]] == rule.param 51 | elseif userTable.passSettings.type[index] == "-string" then 52 | for i=1,#user[userTable.passSettings.var[index]],1 do 53 | if user[userTable.passSettings.var[index]][i] == rule.param then 54 | return true 55 | end 56 | end 57 | return false 58 | elseif userTable.passSettings.type[index] == "int" or userTable.passSettings.type[index] == "-int" then 59 | if userTable.passSettings.above[index] == false or userTable.passSettings.type[index] == "-int" then 60 | return user[userTable.passSettings.var[index]] == rule.param 61 | else 62 | return user[userTable.passSettings.var[index]] >= rule.param 63 | end 64 | elseif userTable.passSettings.type[index] == "bool" then 65 | return user[userTable.passSettings.var[index]] 66 | end 67 | else 68 | return user.staff 69 | end 70 | return false 71 | end 72 | --return true, not value.blocked, value[var], value.staff 73 | local function checkAdvVar(user,rules) --{["uuid"]=uuid.next()["call"]=t1,["param"]=t2,["request"]="supreme",["data"]=false} 74 | local label,color = "will be set",0x000000 75 | local foundOne = false 76 | for key, value in pairs(userTable.passes) do 77 | if string.sub(value.uuid,1,-14) == user or value.uuid == user then 78 | foundOne = true 79 | local skipBase = false 80 | for i=1,#rules,1 do 81 | if rules[i].request == "reject" then 82 | local e, call = getPassID(rules[i].call) 83 | if e then 84 | local good = checkVar(rules[i],value,call) 85 | if good then 86 | label,color = call ~= 0 and "Denied: var " .. userTable.passSettings.label[call] .. " is rejected" or "Denied: var staff" .. " is rejected", 0xFF0000 87 | skipBase = true 88 | break 89 | end 90 | end 91 | end 92 | end 93 | if skipBase == false then 94 | for i=1,#rules,1 do 95 | if rules[i].request == "base" then 96 | local e, call = getPassID(rules[i].call) 97 | if e then 98 | local good = checkVar(rules[i],value,call) 99 | if good then 100 | label,color = call ~= 0 and "Accepted by base var " .. userTable.passSettings.label[call] or "Accepted by base var" .. "staff", 0x00B600 101 | local isGood = true 102 | for j=1,#rules[i].data,1 do 103 | local bill 104 | e, call, bill = getPassID(rules[i].data[j],rules) 105 | if e then 106 | good = checkVar(rules[bill],value,call) 107 | if good == false then 108 | isGood = false 109 | label,color = "Denied: did not meet base requirements", 0xFF0000 110 | break 111 | end 112 | end 113 | end 114 | if isGood then 115 | return true, not value.blocked, true, value.staff,label,color 116 | end 117 | end 118 | end 119 | end 120 | end 121 | end 122 | for i=1,#rules,1 do 123 | if rules[i].request == "supreme" then 124 | local e,call = getPassID(rules[i].call) 125 | if e then 126 | local good = checkVar(rules[i],value,call) 127 | if good then 128 | label,color = call ~= 0 and "Accepted by supreme var " .. userTable.passSettings.label[call] or "Accepted by supreme var " .. "staff", 0x00FF00 129 | return true, not value.blocked, true, value.staff,label,color 130 | end 131 | end 132 | end 133 | end 134 | if foundOne then 135 | if label == "will be set" then 136 | label,color = "Denied: does not have any required passes",0xFF0000 137 | end 138 | return true, not value.blocked, false, value.staff,label,color 139 | end 140 | end 141 | end 142 | return false 143 | end 144 | 145 | local function getDoorInfo(type,id,key) 146 | local arrange 147 | if type == "doorsystem" or type == "customdoor" then 148 | for i=1,#doorTable,1 do --doorTable[i] = {type="single or multi",id="computer's modem uuid",data={door's setting table}} 149 | if doorTable[i].id == id then 150 | if type == "customdoor" then 151 | return{["read"]=doorTable[i].data.cardRead,["name"]=doorTable[i].data.name} 152 | else 153 | if doorTable[i].data[key]~=nil then 154 | return {["read"]=doorTable[i].data[key].cardRead,["name"]=doorTable[i].data[key].name} 155 | end 156 | end 157 | end 158 | end 159 | end 160 | return nil, arrange 161 | end 162 | 163 | local function checkLink(user) 164 | for _, value in pairs(userTable.passes) do 165 | if value.link == user then 166 | return true, not value.blocked, value.name 167 | end 168 | end 169 | return false 170 | end 171 | 172 | local function checkMCID(id) 173 | for _, value in pairs(userTable.passes) do 174 | if value.mcid == id then 175 | return true, value.uuid, value.name 176 | end 177 | end 178 | return false 179 | end 180 | 181 | function module.init(setit ,doors, serverCommands) --Called when server is first started 182 | userTable = setit 183 | doorTable = doors 184 | server = serverCommands 185 | if module.debug then server.print("Received Stuff for passes!") end 186 | if userTable.passes ~= nil and userTable.passes[1] ~= nil and userTable.passes[1].mcid == nil then --make sure old systems migrate successfully 187 | for _,value in pairs(userTable.passes) do 188 | value.mcid = "nil" 189 | end 190 | end 191 | end 192 | 193 | function module.setup() --Called when userlist is updated or server is first started 194 | if module.debug then server.print("Received Stuff for passes!") end 195 | end 196 | 197 | function module.message(command,datar,from) --Called when a command goes past all default commands and into modules. 198 | local data 199 | if datar ~= nil then 200 | data = ser.unserialize(datar) 201 | end 202 | local thisUserName = false 203 | if command == "setvar" or command == "getvar" or command == "checkRules" then 204 | thisUserName = getVar("name",data.uuid) 205 | end 206 | if command == "rcdoors" then 207 | local sendTable = {} 208 | for _,value in pairs(doorTable) do 209 | local datar 210 | if value.type == "doorsystem" then 211 | datar = {} 212 | for key,pal in pairs(value.data) do 213 | datar[key] = {["name"]=pal.name} 214 | end 215 | table.insert(sendTable,{["id"]=value.id,["type"]=value.type,["data"]=datar}) 216 | end 217 | end 218 | return true,{{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Sending remote control table",["color"]=0xFFFFFF}},false,true,server.crypt(ser.serialize(sendTable)) 219 | elseif command == "checkLinked" then 220 | local cu, isBlocked, thisName = checkLink(data) 221 | local dis = {} 222 | if cu == true then 223 | if isBlocked == false then 224 | dis["status"] = false 225 | dis["reason"] = 2 226 | data = server.crypt(ser.serialize(dis)) 227 | return true,{{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Checking if device is linked to a user: ",["color"]=0xFFFF80},{["text"]=" user " .. thisName .. "is blocked",["color"]=0xFF0000,["line"]=true}},false,true,data 228 | else 229 | dis["status"] = true 230 | dis["name"] = thisName 231 | data = server.crypt(ser.serialize(dis)) 232 | return true,{{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Checking if device is linked to a user: ",["color"]=0xFFFF80},{["text"]=" tablet is connected to " .. thisName,["color"]=0x00FF00,["line"]=true}},false,true,data 233 | end 234 | else 235 | dis["status"] = false 236 | dis["reason"] = 1 237 | data = server.crypt(ser.serialize(dis)) 238 | return true,{{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Checking if device is linked to a user: ",["color"]=0xFFFF80},{["text"]=" tablet not linked",["color"]=0x990000,["line"]=true}},false,true,data 239 | end--IMPORTANT: Hello 240 | elseif command == "getvar" then 241 | if (server.configCheck("secAPI")) then 242 | local worked = false 243 | for _, value in pairs(userTable.passes) do 244 | if string.sub(value.uuid,1,-14) == data.uuid or value.uuid == data.uuid then 245 | worked = true 246 | local mee = type(value[data.var]) == "table" and ser.serialize(value[data.var]) or value[data.var] 247 | return true,nil,false,true,server.crypt(mee) 248 | end 249 | end 250 | else 251 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="SecAPI getvar requested when disabled by database",["color"]=0xFF0000}}, false, true, server.crypt({}) 252 | end 253 | elseif command == "setvar" then 254 | if (server.configCheck("secAPI")) then 255 | local worked = false 256 | local counter = 1 257 | for _, value in pairs(userTable.passes) do 258 | if string.sub(value.uuid,1,-14) == data.uuid or value.uuid == data.uuid then 259 | worked = true 260 | if type(userTable.passes[counter][data.var]) == type(data.data) then 261 | userTable.passes[counter][data.var] = data.data 262 | end 263 | return true,nil,true,true,server.crypt("true") 264 | else 265 | counter = counter + 1 266 | end 267 | end 268 | else 269 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="SecAPI getvar requested when disabled by database",["color"]=0xFF0000}}, false, true, server.crypt({}) 270 | end 271 | elseif command == "linkMCID" then 272 | if (server.configCheck("quickMCLink")) then 273 | local worked = false 274 | local counter = 1 275 | for _, value in pairs(userTable.passes) do 276 | if string.sub(value.uuid,1,-14) == data.uuid or value.uuid == data.uuid then 277 | worked = true 278 | if value.mcid == "nil" and not value.blocked then --make sure an account isn't linked AND they are not blocked. 279 | value.mcid = data.mcid 280 | return true, nil, true, true, server.crypt("true") 281 | else 282 | return true, nil, false, true, server.crypt("false") 283 | end 284 | else 285 | counter = counter + 1 286 | end 287 | end 288 | else 289 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Quick Linking MCID's has been disabled by database",["color"]=0xFF0000}}, false, true, server.crypt("false") 290 | end 291 | elseif command == "checkKeypad" then --theoretically should be goody goody two shoes :D (maybe) 292 | for key, value in pairs(doorTable) do 293 | if value.id == from then 294 | for _, value2 in pairs(value.data[data.key].reader) do 295 | if value2.uuid == data.uuid then 296 | if value2.global == false then --Local pass 297 | if value2.pass == data.pass then 298 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Correct password for " .. value.data[data.key].name,["color"]=0x00FF00}}, false, true, server.crypt("true") 299 | else 300 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Incorrect password for " .. value.data[data.key].name,["color"]=0xFF0000}}, false, true, server.crypt("false") 301 | end 302 | else --Check the global one 303 | if userTable.securityKeypads[value2.pass].pass == data.pass then 304 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Correct password for " .. value.data[data.key].name,["color"]=0x00FF00}}, false, true, server.crypt("true") 305 | else 306 | return true, {{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="Incorrect password for " .. value.data[data.key].name,["color"]=0xFF0000}}, false, true, server.crypt("false") 307 | end 308 | end 309 | end 310 | end 311 | end 312 | end 313 | return true, {{["text"]="Passes: ",["color"]=0xFF0000},{["text"]="Door was not found",["color"]=0xFF0000}}, false, true, server.crypt("false") 314 | elseif command == "checkRules" then 315 | local currentDoor = getDoorInfo(data.type,from,data.key) 316 | local enter = true 317 | if data.isBio then 318 | local e,good,nome = checkMCID(data.uuid) 319 | if e then 320 | data.uuid = good 321 | thisUserName = nome 322 | else 323 | return true,{{["text"]="Passes: ",["color"]=0x9924C0},{["text"]="User" .. data.uuid .. " not linked to biometrics",["color"]=0x994049}},false,true,server.crypt("false") 324 | end 325 | end 326 | if data.sector ~= false then 327 | local a,c,_,_,b = server.modulemsg("doorsector",ser.serialize(data)) 328 | if a then 329 | if b ~= "true" and b ~= "openbypass" then 330 | enter = false 331 | if b == "false" then 332 | return true,c,false,true,server.crypt("false") 333 | elseif b == "lockbypass" then 334 | return true,c,false,true,server.crypt("bypass") 335 | end 336 | end 337 | end 338 | end 339 | if enter then 340 | local chatTable = {{["text"]="Passes: ",["color"]=0x9924C0}} 341 | table.insert(chatTable,{["text"]="Checking user " .. thisUserName .. "'s credentials on " .. currentDoor.name .. ":",["color"]=0xFFFF80,["line"]=false}) 342 | local cu, isBlocked, varCheck, isStaff,label,color = checkAdvVar(data.uuid,currentDoor.read) 343 | if cu then 344 | if isBlocked then 345 | if varCheck then 346 | data = server.crypt("true") 347 | table.insert(chatTable,{["text"]=label,["color"]=color,["line"]=true}) 348 | else 349 | if isStaff then 350 | data = server.crypt("true") 351 | table.insert(chatTable,{["text"]="access granted due to staff",["color"]=0xFF00FF,["line"]=true}) 352 | else 353 | data = server.crypt("false") 354 | table.insert(chatTable,{["text"]=label,["color"]=color,["line"]=true}) 355 | end 356 | end 357 | else 358 | data = server.crypt("false") 359 | table.insert(chatTable,{["text"]="user is blocked",["color"]=0xFF0000,["line"]=true}) 360 | end 361 | else 362 | data = server.crypt("false") 363 | table.insert(chatTable,{["text"]="user not found",["color"]=0x990000,["line"]=true}) 364 | end 365 | return true,chatTable,false,true,data 366 | end 367 | end 368 | return false 369 | end 370 | function module.piggyback(command,data) --Called after a command is passed. Passed to all modules which return nothing. 371 | if command == "setdevice" then 372 | data = ser.unserialize(data) 373 | if data.type == "doorsystem" or data.type == "customdoor" then 374 | server.send(true,server.crypt(ser.serialize({["settings"]=userTable.passSettings,["sectors"]=userTable.sectors}))) 375 | end 376 | end 377 | return 378 | end 379 | 380 | return module -------------------------------------------------------------------------------- /security/autoinstaller.lua: -------------------------------------------------------------------------------- 1 | local component = require("component") 2 | local term = require("term") 3 | local io = require("io") 4 | local ser = require("serialization") 5 | local fs = require("filesystem") 6 | local shell = require("shell") 7 | local event = require("event") 8 | local uuid = require("uuid") 9 | local thread = require("thread") 10 | local modem = component.modem 11 | local link 12 | local modemPort = 1000 13 | local syncPort = 199 14 | local diagPort = 180 15 | 16 | local midPoint = "main" 17 | 18 | local program = "ctrl.lua" 19 | local settingFileName = "doorSettings.txt" 20 | local configFileName = "extraConfig.txt" 21 | local doorCode = "https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/" .. midPoint .. "/security/doorControl.lua" 22 | --local versionHolderCode = "https://raw.githubusercontent.com/cadergator10/opencomputer-security-system/main/src/versionHolder.txt" 23 | 24 | local settingData = {} 25 | local randomNameArray = {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "a", "s", "d", "f", "g", "h", "j", "k", "l", "z", "x", "c", "v", "b", "n", "m"} 26 | local commandArray = {"getInput","analyzer","clearTerm","terminate","advanalyzer"} 27 | 28 | local query = {["num"]=0} 29 | local editorSettings = {} --Types of variables used in runInstall: type = door type (single or multi) required, num = old or new type (1 or 2) required, times = times to loop through (only edited before entering runInstall if adding more doors to multi) conditional, version = server version "not used yet", accelerate = if using seperate door setup tablet required, scanner = only used if accelerate true and if tablet has analyzer required, key = key of multidoor if editing door depends, edit = if editing. false if new door. required 30 | 31 | local function saveTable(table, location) 32 | --saves a table to a file 33 | local tableFile = assert(io.open(location, "w")) 34 | tableFile:write(ser.serialize(table)) 35 | tableFile:close() 36 | end 37 | local function loadTable(location) 38 | --returns a table stored in a file. 39 | local tableFile = assert(io.open(location)) 40 | return ser.unserialize(tableFile:read("*all")) 41 | end 42 | 43 | local function send(label,port,linker,...) 44 | if linker and link ~= nil then 45 | link.send(modem.address,...) 46 | return 47 | end 48 | if label then 49 | modem.send(label,port,...) 50 | else 51 | modem.broadcast(port,...) 52 | end 53 | end 54 | 55 | local function sendMsg(...) 56 | local arg = table.pack(...) 57 | for i=1,#arg,1 do 58 | local argType = type(arg[i]) 59 | if editorSettings.accelerate == true then 60 | if argType == "string" then 61 | send(editorSettings.from,editorSettings.port,false,"print",arg[i]) 62 | elseif argType == "number" then 63 | send(editorSettings.from,editorSettings.port,false,commandArray[arg[i]]) 64 | if arg[i] < 3 then 65 | local e, _, _, _, _, text = event.pull("modem_message") 66 | return text 67 | end 68 | if arg[i] == 4 then 69 | print("terminated connection") 70 | end 71 | if arg[i] == 5 then 72 | local wait = true 73 | local distable = {} 74 | while wait do 75 | local e, _, _, _, _, text = event.pull("modem_message") 76 | if text == "finished" then 77 | return distable 78 | else 79 | table.insert(distable,text) 80 | end 81 | end 82 | end 83 | else 84 | send(editorSettings.from,editorSettings.port,false,"print","potential error in code for sendMsg") 85 | end 86 | else 87 | if argType == "string" then 88 | print(arg[i]) 89 | elseif argType == "number" then 90 | if arg[i] == 1 then 91 | local text = term.read() 92 | return text:sub(1,-2) 93 | elseif arg[i] == 2 then 94 | return "nil" 95 | elseif arg[i] == 3 then 96 | term.clear() 97 | elseif arg[i] == 4 then 98 | print("Finished editing.") 99 | elseif arg[i] == 5 then 100 | local wait = true 101 | local distable = {} 102 | while wait do 103 | local text = term.read() 104 | text = text:sub(1,-2) 105 | if text == "" then 106 | return distable 107 | else 108 | table.insert(distable,text) 109 | end 110 | end 111 | else 112 | print("potential error in code for sendMsg") 113 | end 114 | end 115 | end 116 | end 117 | return true 118 | end 119 | 120 | local function runInstall() 121 | local tmpTable = {} 122 | local times = 1 123 | local text = "" 124 | editorSettings.x = tonumber(sendMsg("Would you like to use the simple pass setup or new advanced one?","1 for simple, 2 for advanced",1)) 125 | sendMsg(3) 126 | if editorSettings.single == false then 127 | if editorSettings.times ~= nil then 128 | tmpTable = editorSettings.data 129 | times = editorSettings.times 130 | elseif editorSettings.key ~= nil then 131 | times = 1 132 | tmpTable = editorSettings.data 133 | else 134 | text = sendMsg("Read the text carefully. Some of the inputs REQUIRE NUMBERS ONLY! Some require text.","The redSide is always 2, or back of the computer.","How many different doors are there?",1) 135 | times = tonumber(text) 136 | end 137 | else 138 | times = 1 139 | end 140 | 141 | local config = {} 142 | if editorSettings.edit then 143 | config = loadTable(configFileName) 144 | end 145 | config.type = editorSettings.type 146 | config.num = editorSettings.num 147 | config.version = editorSettings.version 148 | if editorSettings.edit == false or editorSettings.edit == nil then 149 | text = sendMsg("Do you want to use the default cryptKey of {1,2,3,4,5}?","1 for yes, 2 for no",1) 150 | if tonumber(text) == 2 then 151 | config.cryptKey = {} 152 | sendMsg("there are 5 parameters, each requiring a number. Recommend doing 1 digit numbers cause I got no idea how this works lol") 153 | for i=1,5,1 do 154 | text = sendMsg("enter param " .. i,1) 155 | config.cryptKey[i] = tonumber(text) 156 | end 157 | else 158 | config.cryptKey = {1,2,3,4,5} 159 | end 160 | config.port = modemPort 161 | end 162 | saveTable(config,configFileName) 163 | 164 | for i=1,times,1 do 165 | local loopArray = {} 166 | sendMsg(3) 167 | local j 168 | if editorSettings.single == false then 169 | sendMsg("Door # " .. i .. " is being edited:") 170 | if editorSettings.key == nil then 171 | local keepLoop = true 172 | while keepLoop do 173 | j = randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))] 174 | keepLoop = false 175 | for key,value in pairs(tmpTable) do 176 | if key == j then 177 | keepLoop = true 178 | end 179 | end 180 | end 181 | else 182 | j = editorSettings.key 183 | end 184 | text = sendMsg("Magnetic card reader?",editorSettings.scanner and "Scan the magnetic card reader with your tablet." or "Enter the uuid of the device in TEXT. When finished, don't type anything and just press enter",5) 185 | loopArray["reader"] = {} 186 | local hasPad = false 187 | for _, value in pairs(text) do 188 | local thisType = component.type(value) 189 | if thisType == "os_magreader" then 190 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="swipe"}) 191 | elseif thisType == "os_biometric" then 192 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="biometric"}) 193 | elseif thisType == "os_rfidreader" then 194 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="rfid"}) 195 | elseif thisType == "os_keypad" then 196 | hasPad = true 197 | component.proxy(value).setDisplay("inactive", 6) 198 | table.insert(loopArray["reader"],{["uuid"]=value,["type"]="keypad",["global"]=false,["pass"]="1111"}) 199 | end 200 | end 201 | if hasPad then 202 | text = sendMsg("Keypads detected: Would you like to use a global or local password?","global passwords are set by the database. local are set and saved on this door computer","1 for global, 2 for local",1) 203 | if text == "1" then 204 | text = sendMsg("What is the key for that keypad variable?",1) 205 | else 206 | hasPad = false 207 | text = sendMsg("What is the pin for the keypad to need to allow you in?","4 or less numbers (4 recommended)",1) 208 | end 209 | for key, value in pairs(loopArray["reader"]) do 210 | if value.type == "keypad" then 211 | loopArray["reader"][key].global = hasPad 212 | loopArray["reader"][key].pass = text 213 | end 214 | end 215 | end 216 | else 217 | j = randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))]..randomNameArray[math.floor(math.random(1,26))] 218 | local distable = {} 219 | local hasPad = false 220 | for key,_ in pairs(component.list("os_magreader")) do 221 | table.insert(distable,{["uuid"]=key,["type"]="swipe"}) 222 | end 223 | for key,_ in pairs(component.list("os_biometric")) do 224 | table.insert(distable,{["uuid"]=key,["type"]="biometric"}) 225 | end 226 | for key,_ in pairs(component.list("os_rfidreader")) do 227 | table.insert(distable,{["uuid"]=key,["type"]="rfid"}) 228 | end 229 | for key,_ in pairs(component.list("os_keypad")) do 230 | hasPad = true 231 | component.proxy(key).setDisplay("inactive", 6) 232 | table.insert(distable,{["uuid"]=key,["type"]="keypad",["global"]=false,["pass"]="1111"}) 233 | end 234 | if hasPad then 235 | text = sendMsg("Keypads detected: Would you like to use a global or local password?","global passwords are set by the database. local are set and saved on this door computer","1 for global, 2 for local",1) 236 | if text == "1" then 237 | text = sendMsg("What is the key for that keypad variable?",1) 238 | else 239 | hasPad = false 240 | text = sendMsg("What is the pin for the keypad to need to allow you in?","4 or less numbers (4 recommended)",1) 241 | end 242 | for key, value in pairs(distable) do 243 | if value.type == "keypad" then 244 | distable[key].global = hasPad 245 | distable[key].pass = text 246 | end 247 | end 248 | end 249 | loopArray["reader"] = distable 250 | end 251 | text = sendMsg("What do you want to nickname this door?",1) 252 | loopArray["name"] = text 253 | text = sendMsg("Door Type? 1=redstone 2=bundled. 3=door/rolldoor controller. NUMBER ONLY",1) 254 | loopArray["doorType"] = tonumber(text) 255 | if loopArray.doorType == 2 then 256 | text = sendMsg("What color. Use the Color API wiki on the opencomputers wiki, and enter the NUMBER",1) 257 | loopArray["redColor"] = tonumber(text) 258 | loopArray["doorAddress"] = {""} 259 | text = sendMsg("What side? 0=bottom, 1=top, 2=back, 3=front, 4=right, 5=left. NUMBER ONLY",1) 260 | loopArray["redSide"] = tonumber(text) 261 | if editorSettings.single == false then 262 | sendMsg("No need to input anything for door address. The setting doesn't require it :)") 263 | end 264 | elseif loopArray.doorType == 1 then 265 | loopArray["redColor"] = 0 266 | loopArray["doorAddress"] = {""} 267 | text = sendMsg("No need for redColor! The settings you inputted before don't require it :)","What side? 0=bottom, 1=top, 2=back, 3=front, 4=right, 5=left. NUMBER ONLY",1) 268 | loopArray["redSide"] = tonumber(text) 269 | if editorSettings.single == false then 270 | sendMsg("No need to input anything for door address. The setting doesn't require it :)") 271 | end 272 | else 273 | loopArray["redColor"] = 0 274 | loopArray["redSide"] = 0 275 | sendMsg("no need to input anything for redColor. The setting doesn't require it :)","no need to input anything for redSide. The setting doesn't require it :)") 276 | if editorSettings.single == false then 277 | text = sendMsg("What is the address for the door/rolldoor controller blocks?", editorSettings.scanner and "Scan the blocks with tablet then click screen when done" or "Enter uuids as text then enter with no text and enter",5) 278 | loopArray["doorAddress"] = text 279 | else 280 | loopArray["doorAddress"] = {} 281 | for key,_ in pairs(component.list("os_doorcontroller")) do 282 | table.insert(loopArray["doorAddress"],key) 283 | end 284 | for key,_ in pairs(component.list("os_rolldoorcontroller")) do 285 | table.insert(loopArray["doorAddress"],key) 286 | end 287 | end 288 | end 289 | text = sendMsg("Should the door be toggleable, or not? 0 for autoclose and 1 for toggleable",1) 290 | loopArray["toggle"] = tonumber(text) 291 | if loopArray.toggle == 0 then 292 | text = sendMsg("How long should the door stay open in seconds? NUMBER ONLY",1) 293 | loopArray["delay"] = tonumber(text) 294 | else 295 | sendMsg("No need to change delay! Previous setting doesn't require it :)") 296 | loopArray["delay"] = 0 297 | end 298 | if editorSettings.x == 2 then 299 | local readLoad = {} 300 | sendMsg("Remember how many of each pass you want before you start.","type something and enter to continue",1) 301 | readLoad.add = tonumber(sendMsg("How many add passes do you want to add?","remember multiple base passes can use the same add pass",1)) 302 | readLoad.base = tonumber(sendMsg("How many base passes do you want to add?",1)) 303 | readLoad.reject = tonumber(sendMsg("How many reject passes do you want to add?","These don't affect supreme passes",1)) 304 | readLoad.supreme = tonumber(sendMsg("How many supreme passes do you want to add?",1)) 305 | loopArray.cardRead = {} 306 | local nextmsg = {} 307 | nextmsg.beg, nextmsg.mid, nextmsg.back = "What should be read for "," pass number ","? 0 = staff" 308 | for i=1,#editorSettings.settings.var,1 do 309 | nextmsg.back = nextmsg.back .. ", " .. i .. " = " .. editorSettings.settings.label[i] 310 | end 311 | local passFunc = function(type,num) 312 | local newRules = {["uuid"]=uuid.next(),["request"]=type,["data"]=type == "base" and {} or false} 313 | local text = sendMsg(nextmsg.beg..type..nextmsg.mid..num..nextmsg.back,1) 314 | if tonumber(text) == 0 then 315 | newRules.call = "checkstaff" 316 | newRules.param = 0 317 | sendMsg("No need for extra parameter. This mode doesn't require it :)") 318 | else 319 | newRules["tempint"] = tonumber(text) 320 | newRules["call"] = editorSettings.settings.calls[tonumber(text)] 321 | if editorSettings.settings.type[tonumber(text)] == "string" or editorSettings.settings.type == "-string" then 322 | text = sendMsg("What is the string you would like to read? Enter text.",1) 323 | newRules["param"] = text 324 | elseif editorSettings.settings.type[tonumber(text)] == "bool" then 325 | newRules["param"] = 0 326 | sendMsg("No need for extra parameter. This mode doesn't require it :)") 327 | elseif editorSettings.settings.type[tonumber(text)] == "int" then 328 | if editorSettings.settings.above[tonumber(text)] == true then 329 | text = sendMsg("What level and above should be required?",1) 330 | else 331 | text = sendMsg("what level exactly should be required?",1) 332 | end 333 | newRules["param"] = tonumber(text) 334 | elseif editorSettings.settings.type[tonumber(text)] == "-int" then 335 | local nextmsg = "What group are you wanting to set?" 336 | for i=1,#editorSettings.settings.data[tonumber(text)],1 do 337 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.data[tonumber(text)][i] 338 | end 339 | text = sendMsg(nextmsg,1) 340 | newRules["param"] = tonumber(text) 341 | else 342 | sendMsg("error in cardRead area for num 2") 343 | newRules["param"] = 0 344 | end 345 | end 346 | return newRules 347 | end 348 | for i=1,readLoad.add,1 do 349 | local rule = passFunc("add",i) 350 | table.insert(loopArray.cardRead,rule) 351 | end 352 | local addNum = #loopArray.cardRead 353 | for i=1,readLoad.base,1 do 354 | local rule = passFunc("base",i) 355 | text = tonumber(sendMsg("How many add passes do you want to link?",1)) 356 | if text ~= 0 then 357 | local nextAdd = "Which pass do you want to add? " 358 | for j=1,addNum,1 do 359 | nextAdd = nextAdd .. ", " .. j .. " = " .. editorSettings.settings.label[loopArray.cardRead[j].tempint] 360 | end 361 | for j=1,text,1 do 362 | text = tonumber(sendMsg(nextAdd,1)) 363 | table.insert(rule.data,loopArray.cardRead[text].uuid) 364 | end 365 | end 366 | table.insert(loopArray.cardRead,rule) 367 | end 368 | for i=1,readLoad.reject,1 do 369 | local rule = passFunc("reject",i) 370 | table.insert(loopArray.cardRead,rule) 371 | end 372 | for i=1,readLoad.supreme,1 do 373 | local rule = passFunc("supreme",i) 374 | table.insert(loopArray.cardRead,rule) 375 | end 376 | else --{["uuid"]=uuid.next()["call"]=t1,["param"]=t2,["request"]="supreme",["data"]=false} 377 | local nextmsg = "What should be read? 0 = staff," 378 | for i=1,#editorSettings.settings.var,1 do 379 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.label[i] 380 | end 381 | text = sendMsg(nextmsg,1) 382 | loopArray["cardRead"] = {{["uuid"]=uuid.next(),["call"]="",["param"]=0,["request"]="supreme",["data"]=false}} 383 | if tonumber(text) == 0 then 384 | loopArray["cardRead"][1].call = "checkstaff" 385 | loopArray["cardRead"][1].param = 0 386 | sendMsg("No need to set access level. This mode doesn't require it :)") 387 | else 388 | loopArray["cardRead"][1].call = editorSettings.settings.calls[tonumber(text)] 389 | if editorSettings.settings.type[tonumber(text)] == "string" or editorSettings.settings.type[tonumber(text)] == "-string" then 390 | text = sendMsg("What is the string you would like to read? Enter text.",1) 391 | loopArray["cardRead"][1].param = text 392 | elseif editorSettings.settings.type[tonumber(text)] == "bool" then 393 | loopArray["cardRead"][1].param = 0 394 | sendMsg("No need to set access level. This mode doesn't require it :)") 395 | elseif editorSettings.settings.type[tonumber(text)] == "int" then 396 | if editorSettings.settings.above[tonumber(text)] == true then 397 | text = sendMsg("What level and above should be required?",1) 398 | else 399 | text = sendMsg("what level exactly should be required?",1) 400 | end 401 | loopArray["cardRead"][1].param = tonumber(text) 402 | elseif editorSettings.settings.type[tonumber(text)] == "-int" then 403 | local nextmsg = "What group are you wanting to set?" 404 | for i=1,#editorSettings.settings.data[tonumber(text)],1 do 405 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.data[tonumber(text)][i] 406 | end 407 | text = sendMsg(nextmsg,1) 408 | loopArray["cardRead"][1].param = tonumber(text) 409 | else 410 | sendMsg("error in cardRead area for num 2") 411 | loopArray["cardRead"][1].param = 0 412 | end 413 | end 414 | end --Sectors beginning 415 | if editorSettings.hassector then 416 | local nextmsg = "What sector would you like this door to be part of? 0 = no sector" 417 | for i=1,#editorSettings.settings.sectors,1 do --Issue 418 | nextmsg = nextmsg .. ", " .. i .. " = " .. editorSettings.settings.sectors[i].name 419 | end 420 | text = tonumber(sendMsg(nextmsg,1)) 421 | if text == 0 then 422 | loopArray["sector"]=false 423 | else 424 | loopArray["sector"]=editorSettings.settings.sectors[text].uuid 425 | end 426 | else 427 | loopArray["sector"] = false 428 | end 429 | tmpTable[j] = loopArray 430 | end 431 | text = sendMsg("All done with installer!","Would you like to start the computer now?","1 for yes, 2 for no",1) 432 | editorSettings.start = false 433 | if tonumber(text) == 1 then 434 | sendMsg("Ok, will start computer.",4) 435 | editorSettings.start = true 436 | else 437 | sendMsg("Ok, closing out.",4) 438 | end 439 | return tmpTable 440 | end 441 | 442 | local function oldFiles() 443 | term.clear() 444 | local config = loadTable(configFileName) 445 | if config == nil then 446 | sendMsg("Error reading config file. Is this an up to date version?","It is recommended to wipe and reinstall at this point",4) 447 | end 448 | editorSettings.type = config.type 449 | editorSettings.single = false 450 | local text = sendMsg("Old files detected. Please select an option:","1 = wipe all files","2 = update door","3 = change cryptKey","4 = change port",1) 451 | if tonumber(text) == 1 then 452 | term.clear() 453 | sendMsg("Deleting all files...") 454 | local path = shell.getWorkingDirectory() 455 | fs.remove(path .. "/" .. program) 456 | fs.remove(path .. "/" .. settingFileName) 457 | if config ~= nil then fs.remove(path .. "/" .. configFileName) end 458 | local fill = io.open(settingFileName) 459 | if fill~=nil then 460 | sendMsg("an error occured and some files may not have deleted.",4) 461 | fill:close() 462 | else 463 | sendMsg("all done!",4) 464 | end 465 | elseif tonumber(text) == 2 then 466 | text = sendMsg("Are you sure you want to do this? New updates sometimes require manual changing of config.","1 for continue, 2 for cancel",1) 467 | if tonumber(text) == 1 then 468 | os.execute("wget -f " .. doorCode .. " " .. program) 469 | end 470 | text = sendMsg("all done! is set to " .. ser.serialize(config.cryptKey),"Would you like to start the computer now?","1 for yes, 2 for no",1) 471 | if tonumber(text) == 1 then 472 | sendMsg("Starting...",4) 473 | os.execute(program) 474 | else 475 | sendMsg("Ok, closing out.",4) 476 | end 477 | elseif tonumber(text) == 3 then 478 | sendMsg("there are 5 parameters, each requiring a number. Recommend doing 1 digit numbers cause I got no idea how this works lol") 479 | for i=1,5,1 do 480 | text = sendMsg("enter param " .. i,1) 481 | config.cryptKey[i] = tonumber(text) 482 | end 483 | saveTable(config,configFileName) 484 | text = sendMsg("all done! is set to " .. ser.serialize(config.cryptKey),"Would you like to start the computer now?","1 for yes, 2 for no",1) 485 | if tonumber(text) == 1 then 486 | sendMsg("Starting...",4) 487 | os.execute(program) 488 | else 489 | sendMsg("Ok, closing out.",4) 490 | end 491 | elseif tonumber(text) == 4 then 492 | config.port = modemPort 493 | sendMsg("Port changed to " .. modemPort) 494 | saveTable(config,configFileName) 495 | end 496 | config = nil 497 | end 498 | 499 | modem.close() 500 | term.clear() 501 | 502 | if component.isAvailable("tunnel") then 503 | link = component.tunnel 504 | end 505 | 506 | modem.open(syncPort) 507 | modem.broadcast(syncPort,"syncport") 508 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 509 | modem.close(syncPort) 510 | if e then 511 | modemPort = tonumber(msg) 512 | else 513 | print("What port is the server running off of?") 514 | local text = term.read() 515 | modemPort = tonumber(text:sub(1,-2)) 516 | term.clear() 517 | end 518 | 519 | print("Sending query to server...") 520 | if link == nil then 521 | modem.open(modemPort) 522 | end 523 | send(nil,modemPort,true,"getquery",ser.serialize({"passSettings","sectors","&&&crypt"})) 524 | local e,_,from,port,_,msg = event.pull(3,"modem_message") 525 | if e == nil then 526 | print("No query received. Assuming old server system is in place and will not work.") 527 | os.exit() 528 | end 529 | print("Query received") 530 | query = ser.unserialize(msg) 531 | if query.num ~= 3 then 532 | print("Security server is not valid. Must be 3.0.0 and up") 533 | os.exit() 534 | end 535 | editorSettings.x = 2 536 | editorSettings.num = query.num 537 | editorSettings.version = query.version 538 | editorSettings.hassector = query.data.sectors ~= nil 539 | editorSettings.settings = query.data.passSettings 540 | editorSettings.settings.sectors = query.data.sectors 541 | editorSettings.scanner = false 542 | editorSettings.accelerate = false 543 | editorSettings.single = false 544 | term.clear() 545 | local text = sendMsg("Would you like to use an external device for accelerated setup?","This makes it easier to set up doors without having to move from the door to the pc constantly.","It requires a diagnostic tablet (found on github)","1 for yes, 2 for no",1) 546 | if tonumber(text) == 1 then 547 | modem.open(diagPort) 548 | modem.close(modemPort) 549 | sendMsg("Start up accelerated door setup on your diagnostic tablet","in 60 seconds with no changes the program will close") 550 | 551 | local time = 0 552 | local timer = function(seconds) 553 | time = seconds 554 | for i=1,seconds, 1 do 555 | os.sleep(1) 556 | time = time - 1 557 | end 558 | end 559 | local waiter = true 560 | local e, _, from, port, _, msg, barcode, t 561 | t = thread.create(timer) --setup incorrect 562 | while waiter do 563 | e, _, from, port, _, msg, barcode = event.pull(time, "modem_message") 564 | if e then 565 | if msg == "accsetup" then 566 | waiter = false 567 | end 568 | else 569 | waiter = false 570 | end 571 | end 572 | 573 | if e then 574 | modem.open(modemPort) 575 | t:kill() 576 | send(from,port,false,"connected") 577 | term.clear() 578 | sendMsg("Connection successful! All prompts will be on the tablet now on.") 579 | os.sleep(1) 580 | editorSettings.scanner = barcode 581 | editorSettings.accelerate = true 582 | editorSettings.from = from 583 | editorSettings.port = port 584 | else 585 | modem.close(diagPort) 586 | print("Setup cancelled") 587 | os.exit() 588 | end 589 | else 590 | sendMsg("Normal setup initiating.") 591 | end 592 | term.clear() 593 | sendMsg("Checking files...") 594 | local text 595 | local fill = io.open(program,"r") 596 | if fill~=nil then 597 | fill:close() 598 | oldFiles() 599 | else 600 | term.clear() 601 | editorSettings.type = "doorsystem" 602 | os.execute("wget -f " .. doorCode .. " " .. program) 603 | text = sendMsg("Would you like to use the simplified single door or multi-door?","true for single door of false for regular, multidoor setup",1) 604 | editorSettings.single = text == "true" and true or false 605 | settingData = runInstall() 606 | saveTable(settingData,settingFileName) 607 | if editorSettings.start == true then 608 | print("Starting...") 609 | os.execute(program) 610 | else 611 | print("Run " .. program .. " now to start door.") 612 | end 613 | end 614 | -------------------------------------------------------------------------------- /security/quikidlink.lua: -------------------------------------------------------------------------------- 1 | --A program that allows users to link their card to their MC User (if there is not one linked already) 2 | local apiCode = "https://raw.githubusercontent.com/cadergator10/Opencomputers-servertine/main/serpAPI.lua" --Shouldn't need the modified SecurityAPI version due to it implementing custom features. 3 | local component = require("component") 4 | local term = require("term") 5 | local io = require("io") 6 | local ser = require("serialization") 7 | local fs = require("filesystem") 8 | local event = require("event") 9 | local api = require("serpAPI.lua") 10 | 11 | term.clear() 12 | if api == nil then --Checkong for SerpAPI program. If it doesn't exist, download it. 13 | print("No API installed. Downloading") 14 | os.execute("wget -f " .. apiCode .. " " .. "serpAPI") 15 | api = require("serpAPI.lua") --Attempt to get again. Experimental (dont know if it will work) 16 | end 17 | 18 | api.setup({["type"]="quikidlink"},{}) --Prepare table to submit to server. Setting the type in case I want to do something on the server and such 19 | 20 | for key,_ in pairs(component.list("os_magreader")) do --Prepare light on magreader to signal stuff 21 | component.proxy(key).swipeIndicator(false) 22 | component.proxy(key).setLightState(3) --3 is red and yellow, meaning swipe card 23 | end 24 | 25 | while true do 26 | term.clear() 27 | print("Quick Minecraft UUID Link") 28 | print("---------------------------------------------------------------------------") 29 | print("Please swipe the card you want to link your ID to") 30 | local ev, address, _, str = event.pull("magData") --wait for a card swipe 31 | component.proxy(address).setLightState(2) --2 is yellow, meaning waiting. Doing stuff 32 | local _, data = api.crypt(str, true) --decrypt card's data 33 | data = ser.unserialize(data) --unserialize card data 34 | if ev and data ~= nil then --Read the data successfully and decrypted 35 | print("Welcome " .. data.name) 36 | print("Please click the biometric reader to link player") 37 | component.proxy(address).setLightState(6) --6 is green and yellow, meaning click bioreader 38 | local e, ad, msg = event.pull(7,"bioReader") --wait for bioreader click or timeout 39 | component.proxy(address).setLightState(2) --2 is yellow. Waiting for message back 40 | if e then --clicked bioreader 41 | print("Waiting for response from server...") 42 | data = api.crypt(ser.serialize({["uuid"]=data.uuid,["mcid"]=msg})) --encrypting data and sending to server to check if user exists and they don't have a mcid linked yet 43 | e, msg = api.send(true,"linkMCID",data) 44 | if e then --Received message back 45 | _, msg = api.crypt(msg,true) 46 | if msg == "true" then --Linked user successfully 47 | print("Link success! All biometric reader doors should work for you now") 48 | component.proxy(address).setLightState(4) --4 is green, meaning success 49 | else --Failed for some reason 50 | print("Link failed: Either card already is linked, account no longer exists, or card is blocked") 51 | component.proxy(address).setLightState(1) --1 is red, meaning failed in this case. 52 | end 53 | else --No message received 54 | print("Server failed to respond. Has it crashed or is it off?") 55 | component.proxy(address).setLightState(7) --7 is all lights, indicating error (server down or crash?) 56 | end 57 | else --Didn't click bio reader in time 58 | print("Biometric timeout") 59 | component.proxy(address).setLightState(1) --1 is red, indicating a timeout for the bioreader and no link 60 | end 61 | else --Card wasn't able to be read 62 | print("Failed to read card") 63 | component.proxy(address).setLightState(1) --1 is red, indicating in this case that either nothing was received (ev) or card was nil (no data on card or incorrect crypted data) 64 | end 65 | os.sleep(3) 66 | component.proxy(address).setLightState(3) --reset it to swipe card mode 67 | end -------------------------------------------------------------------------------- /security/securityAPI.lua: -------------------------------------------------------------------------------- 1 | local version = "4.0.3" 2 | --testR = true 3 | 4 | local security = {} 5 | 6 | local cardRead = {}; 7 | 8 | local adminCard = "admincard" 9 | 10 | local modemPort = 1000 11 | local syncPort = 199 12 | local diagPort = 180 13 | local dbPort = 144 14 | 15 | local component = require("component") 16 | local gpu = component.gpu 17 | local event = require("event") 18 | local ser = require("serialization") 19 | local term = require("term") 20 | local thread = require("thread") 21 | local process = require("process") 22 | local uuid = require("uuid") 23 | local computer = component.computer 24 | 25 | local magReader = component.os_magreader 26 | local modem = component.modem 27 | local link 28 | 29 | local baseVariables = {"name","uuid","date","link","blocked","staff"} 30 | local varSettings = {} 31 | 32 | local query 33 | 34 | local settingData = {} 35 | local extraConfig = {} 36 | 37 | --------TableToFile 38 | 39 | local function saveTable( tbl,filename ) 40 | local tableFile = assert(io.open(filename, "w")) 41 | tableFile:write(ser.serialize(tbl)) 42 | tableFile:close() 43 | end 44 | 45 | local function loadTable( sfile ) 46 | local tableFile = io.open(sfile) 47 | if tableFile ~= nil then 48 | return ser.unserialize(tableFile:read("*all")) 49 | else 50 | return nil 51 | end 52 | end 53 | 54 | --------Base Functions 55 | 56 | local function convert( chars, dist, inv ) 57 | return string.char( ( string.byte( chars ) - 32 + ( inv and -dist or dist ) ) % 95 + 32 ) 58 | end 59 | 60 | local function crypt(str,k,inv) 61 | local enc= ""; 62 | for i=1,#str do 63 | if(#str-k[5] >= i or not inv)then 64 | for inc=0,3 do 65 | if(i%4 == inc)then 66 | enc = enc .. convert(string.sub(str,i,i),k[inc+1],inv); 67 | break; 68 | end 69 | end 70 | end 71 | end 72 | if(not inv)then 73 | for i=1,k[5] do 74 | enc = enc .. string.char(math.random(32,126)); 75 | end 76 | end 77 | return enc; 78 | end 79 | 80 | local function splitString(str, sep) 81 | local sep, fields = sep or ":", {} 82 | local pattern = string.format("([^%s]+)", sep) 83 | str:gsub(pattern, function(c) fields[#fields+1] = c end) 84 | return fields 85 | end 86 | 87 | local function send(label,port,linker,...) --Pingme 88 | if linker and link ~= nil then 89 | link.send(modem.address,...) 90 | return 91 | end 92 | if label then 93 | modem.send(label,port,...) 94 | else 95 | modem.broadcast(port,...) 96 | end 97 | end 98 | 99 | --------Called Functions 100 | 101 | local function update(_, localAddress, remoteAddress, port, distance, msg, data) 102 | if msg == "deviceCheck" then 103 | send(nil, modemPort,true,"true") 104 | end 105 | end 106 | 107 | function security.setup() 108 | local e 109 | local fill = io.open("extraConfig.txt", "r") 110 | if fill ~= nil then 111 | io.close(fill) 112 | else 113 | local config = {} 114 | config.cryptKey = {} 115 | term.clear() 116 | print("First Time Config Setup: Would you like to use default cryptKey? 1 for yes, 2 for no") 117 | local text = term.read() 118 | if tonumber(text) == 2 then 119 | print("there are 5 parameters, each requiring a number. Recommend doing 1 digit numbers") 120 | for i=1,5,1 do 121 | print("enter param " .. i) 122 | text = term.read() 123 | config.cryptKey[i] = tonumber(text) 124 | end 125 | else 126 | config.cryptKey = {1,2,3,4,5} 127 | end 128 | config.type = "single" 129 | config.num = 3 130 | config.version = version 131 | modem.open(syncPort) 132 | modem.broadcast(syncPort,"syncport") 133 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 134 | modem.close(syncPort) 135 | if e then 136 | config.port = tonumber(msg) 137 | else 138 | print("What port is the server running off of?") 139 | local text = term.read() 140 | config.port = tonumber(text:sub(1,-2)) 141 | term.clear() 142 | end 143 | saveTable(config,"extraConfig.txt") 144 | end 145 | extraConfig = loadTable("extraConfig.txt") 146 | modemPort = extraConfig.port 147 | if component.isAvailable("tunnel") then 148 | link = component.tunnel 149 | modem.close(modemPort) 150 | else 151 | modem.open(modemPort) 152 | end 153 | send(nil,modemPort,true,"getquery",ser.serialize({"passSettings"})) 154 | e,_,_,_,_,query = event.pull(3,"modem_message") 155 | if e == nil then 156 | print("Failed query. Is the server on?") 157 | os.exit() 158 | end 159 | query = ser.unserialize(crypt(query,extraConfig.cryptKey,true)) 160 | if query.num ~= 3 then 161 | print("Server is not 3.0.0 and up") 162 | os.exit() 163 | end 164 | fill = io.open("securitySettings.txt") 165 | if fill ~= nil then 166 | io.close(fill) 167 | else 168 | term.clear() 169 | settingData = {} 170 | print("First time pass setup") 171 | print("Would you like to use the simple pass setup or new advanced one? 1 for simple, 2 for advanced") 172 | local text = term.read() 173 | settingData.name = "Test Security API" 174 | if tonumber(text) == 1 then 175 | local nextmsg = "What should be read? 0 = staff," 176 | for i=1,#query.data.passSettings.var,1 do 177 | nextmsg = nextmsg .. ", " .. i .. " = " .. query.data.passSettings.label[i] 178 | end 179 | print(nextmsg) 180 | text = term.read() 181 | settingData.cardRead = {{["uuid"]=uuid.next(),["call"]="",["param"]=0,["request"]="supreme",["data"]=false}} 182 | if tonumber(text) == 0 then 183 | settingData.cardRead[1].call = "checkstaff" 184 | settingData.cardRead[1].param = 0 185 | print("No need to set access level. This mode doesn't require it :)") 186 | else 187 | settingData.cardRead[1].call = query.data.passSettings.calls[tonumber(text)] 188 | if query.data.passSettings.type[tonumber(text)] == "string" or query.data.passSettings.type[tonumber(text)] == "-string" then 189 | print("What is the string you would like to read? Enter text.") 190 | text = term.read() 191 | settingData.cardRead[1].param = text:sub(1,-2) 192 | elseif query.data.passSettings.type[tonumber(text)] == "bool" then 193 | settingData.cardRead[1].param = 0 194 | print("No need to set access level. This mode doesn't require it :)") 195 | elseif query.data.passSettings.type[tonumber(text)] == "int" then 196 | if query.data.passSettings.above[tonumber(text)] == true then 197 | print("What level and above should be required?") 198 | else 199 | print("what level exactly should be required?") 200 | end 201 | text = term.read() 202 | settingData.cardRead[1].param = tonumber(text) 203 | elseif query.data.passSettings.type[tonumber(text)] == "-int" then 204 | local nextmsg = "What group are you wanting to set?" 205 | for i=1,#query.data.passSettings.data[tonumber(text)],1 do 206 | nextmsg = nextmsg .. ", " .. i .. " = " .. query.data.passSettings.data[tonumber(text)][i] 207 | end 208 | print(nextmsg) 209 | text = term.read() 210 | settingData.cardRead[1].param = tonumber(text) 211 | else 212 | print("error in cardRead area for num 2") 213 | settingData.cardRead[1].param = 0 214 | end 215 | end 216 | else 217 | local readLoad = {} 218 | print("Remember how many of each pass you want before you start.","Press enter to continue") 219 | term.read() 220 | print("How many add passes do you want to add?","remember multiple base passes can use the same add pass") 221 | readLoad.add = tonumber(term.read()) 222 | print("How many base passes do you want to add?") 223 | readLoad.base = tonumber(term.read()) 224 | print("How many reject passes do you want to add?","These don't affect supreme passes") 225 | readLoad.reject = tonumber(term.read()) 226 | print("How many supreme passes do you want to add?") 227 | readLoad.supreme = tonumber(term.read()) 228 | settingData.cardRead = {} 229 | local nextmsg = {} 230 | nextmsg.beg, nextmsg.mid, nextmsg.back = "What should be read for "," pass number ","? 0 = staff" 231 | for i=1,#query.data.passSettings.var,1 do 232 | nextmsg.back = nextmsg.back .. ", " .. i .. " = " .. query.data.passSettings.label[i] 233 | end 234 | local passFunc = function(type,num) 235 | local newRules = {["uuid"]=uuid.next(),["request"]=type,["data"]=type == "base" and {} or false} 236 | print(nextmsg.beg..type..nextmsg.mid..num..nextmsg.back) 237 | text = term.read() 238 | if tonumber(text) == 0 then 239 | newRules.call = "checkstaff" 240 | newRules.param = 0 241 | print("No need for extra parameter. This mode doesn't require it :)") 242 | else 243 | newRules["tempint"] = tonumber(text) 244 | newRules["call"] = query.data.passSettings.calls[tonumber(text)] 245 | if query.data.passSettings.type[tonumber(text)] == "string" or query.data.passSettings.type[tonumber(text)] == "-string" then 246 | print("What is the string you would like to read? Enter text.") 247 | text = term.read() 248 | newRules["param"] = text:sub(1,-2) 249 | elseif query.data.passSettings.type[tonumber(text)] == "bool" then 250 | newRules["param"] = 0 251 | print("No need for extra parameter. This mode doesn't require it :)") 252 | elseif query.data.passSettings.type[tonumber(text)] == "int" then 253 | if query.data.passSettings.above[tonumber(text)] == true then 254 | print("What level and above should be required?") 255 | else 256 | print("what level exactly should be required?") 257 | end 258 | text = term.read() 259 | newRules["param"] = tonumber(text) 260 | elseif query.data.passSettings.type[tonumber(text)] == "-int" then 261 | local nextmsg = "What group are you wanting to set?" 262 | for i=1,#query.data.passSettings.data[tonumber(text)],1 do 263 | nextmsg = nextmsg .. ", " .. i .. " = " .. query.data.passSettings.data[tonumber(text)][i] 264 | end 265 | print(nextmsg) 266 | text = term.read() 267 | newRules["param"] = tonumber(text) 268 | else 269 | print("error in cardRead area for num 2") 270 | newRules["param"] = 0 271 | end 272 | end 273 | return newRules 274 | end 275 | for i=1,readLoad.add,1 do 276 | local rule = passFunc("add",i) 277 | table.insert(settingData.cardRead,rule) 278 | end 279 | local addNum = #settingData.cardRead 280 | for i=1,readLoad.base,1 do 281 | local rule = passFunc("base",i) 282 | print("How many add passes do you want to link?") 283 | text = tonumber(term.read()) 284 | if text ~= 0 then 285 | local nextAdd = "Which pass do you want to add? " 286 | for j=1,addNum,1 do 287 | nextAdd = nextAdd .. ", " .. j .. " = " .. query.data.passSettings.label[settingData.cardRead[j].tempint] 288 | end 289 | for j=1,text,1 do 290 | print(nextAdd) 291 | text = tonumber(term.read()) 292 | table.insert(rule.data,settingData.cardRead[text].uuid) 293 | end 294 | end 295 | table.insert(settingData.cardRead,rule) 296 | end 297 | for i=1,readLoad.reject,1 do 298 | local rule = passFunc("reject",i) 299 | table.insert(settingData.cardRead,rule) 300 | end 301 | for i=1,readLoad.supreme,1 do 302 | local rule = passFunc("supreme",i) 303 | table.insert(settingData.cardRead,rule) 304 | end 305 | end 306 | saveTable(settingData,"securitySettings.txt") 307 | end 308 | term.clear() 309 | settingData = loadTable("securitySettings.txt") 310 | fill = {} 311 | fill["type"] = "customdoor" 312 | fill["data"] = settingData 313 | send(nil,modemPort,true,"setdevice",crypt(ser.serialize(fill),extraConfig.cryptKey)) 314 | local got, _, _, _, _, fill = event.pull(2, "modem_message") 315 | if got then 316 | varSettings = ser.unserialize(crypt(fill,extraConfig.cryptKey,true)) 317 | else 318 | print("Failed to receive confirmation from server") 319 | os.exit() 320 | end 321 | got = nil 322 | event.listen("modem_message", update) 323 | process.info().data.signal = function(...) 324 | print("caught hard interrupt") 325 | event.ignore("modem_message", update) 326 | os.exit() 327 | end 328 | end 329 | 330 | function security.checkPass(str,loc) 331 | local data = crypt(str,extraConfig.cryptKey,true) 332 | local tmpTable = ser.unserialize(data) 333 | tmpTable["type"] = "customdoor" 334 | data = crypt(ser.serialize(tmpTable), extraConfig.cryptKey) 335 | if loc ~= nil then 336 | send(loc,modemPort,true,"checkRules",data,true) 337 | else 338 | send(nil,modemPort,true,"checkRules",data,true) 339 | end 340 | local e, _, from, port, _, msg = event.pull(3, "modem_message") 341 | if e then 342 | data = crypt(msg, extraConfig.cryptKey, true) 343 | if data == "true" then 344 | return true, true 345 | else 346 | return true, false 347 | end 348 | else 349 | return false, "timed out" 350 | end 351 | end 352 | 353 | function security.getVar(str,var,loc) 354 | local data = crypt(str,extraConfig.cryptKey,true) 355 | data = ser.unserialize(data) 356 | if type(var) == "boolean" or var == nil then 357 | var = settingData.cardRead[1].call 358 | for i=1,#query.data.passSettings.calls, 1 do 359 | if var == query.data.passSettings.calls[i] then 360 | var = query.data.passSettings.var[i] 361 | break 362 | end 363 | end 364 | end 365 | data.var = var 366 | data = crypt(ser.serialize(data),extraConfig.cryptKey) 367 | if loc ~= nil then 368 | send(loc,modemPort,true,"getvar",data) 369 | else 370 | send(nil,modemPort,true,"getvar",data) 371 | end 372 | local e, _, from, port, _, msg = event.pull(3, "modem_message") 373 | if e then 374 | data = crypt(msg, extraConfig.cryptKey, true) 375 | 376 | return true, ser.unserialize(data) or data 377 | else 378 | return false, "timed out or user not found" 379 | end 380 | end 381 | function security.setVar(str,var,it,loc) 382 | local data = crypt(str,extraConfig.cryptKey,true) 383 | data = ser.unserialize(data) 384 | if type(var) == "boolean" or var == nil then 385 | var = settingData.cardRead[1].call 386 | for i=1,#query.data.passSettings.calls, 1 do 387 | if var == query.data.passSettings.calls[i] then 388 | var = query.data.passSettings.var[i] 389 | break 390 | end 391 | end 392 | end 393 | data.var = var 394 | data.data = it 395 | data = crypt(ser.serialize(data),extraConfig.cryptKey) 396 | if loc ~= nil then 397 | send(loc,modemPort,true,"setvar",data) 398 | else 399 | send(nil,modemPort,true,"setvar",data) 400 | end 401 | local e, _, from, port, _, msg = event.pull(3, "modem_message") 402 | if e then 403 | return true, "no error" 404 | else 405 | return false, "timed out" 406 | end 407 | end 408 | 409 | local function checkLink() --ported directly from my single program using this. Should work as I haven't modified it since 410 | print("retrieving config") 411 | local fill = io.open("linkConfig.txt", "r") 412 | if fill~=nil then 413 | print("previous config detected") 414 | io.close(fill) 415 | else 416 | print("no config detected. Making new one") 417 | settingData = {} 418 | settingData["code"] = uuid.next() 419 | saveTable(settingData,"linkConfig.txt") 420 | end 421 | settingData = loadTable("linkConfig.txt") 422 | print("loaded config. Connecting to account...") 423 | modem.open(modemPort) 424 | local str = crypt(settingData["code"],extraConfig.cryptKey) 425 | send(nil,modemPort,true,"checkLinked",str) 426 | local e, _, from, port, _, msg = event.pull(1, "modem_message") 427 | modem.close(modemPort) 428 | if e then 429 | str = crypt(msg, extraConfig.cryptKey, true) 430 | local da = ser.unserialize(str) 431 | if da["status"] == true then 432 | print("successfully connected") 433 | return "true",da["name"],settingData.code 434 | else 435 | if da["reason"] == 1 then 436 | print("No account linked. When you are ready, click the screen") 437 | event.pull("touch") 438 | term.write("wait...") 439 | modem.open(dbPort) 440 | local newUUID = uuid.next() 441 | send(nil,dbPort,false,crypt(newUUID,extraConfig.cryptKey)) 442 | e, _, from, port, _, msg = event.pull(3, "modem_message") 443 | modem.close(dbPort) 444 | if e then 445 | local nm = crypt(msg,extraConfig.cryptKey,true) 446 | term.write(" linked to " .. nm .. "\n") 447 | settingData["code"] = newUUID 448 | saveTable(settingData,"linkConfig.txt") 449 | return true,nm, settingData.code 450 | else 451 | term.write(" linking failed\n") 452 | return "false","nil", settingData.code 453 | end 454 | elseif da["reason"] == 2 then 455 | print("Your account is blocked") 456 | return "false","nil", settingData.code 457 | else 458 | print("unknown error") 459 | return "false","nil", settingData.code 460 | end 461 | end 462 | else 463 | print("server timeout") 464 | return "false" 465 | end 466 | end 467 | 468 | function security.link() --If using linking, do this rather than security.setup() 469 | local e 470 | local fill = io.open("extraConfig.txt", "r") 471 | if fill ~= nil then 472 | io.close(fill) 473 | else 474 | local config = {} 475 | config.cryptKey = {} 476 | term.clear() 477 | print("First Time Config Setup: Would you like to use default cryptKey? 1 for yes, 2 for no") 478 | local text = term.read() 479 | if tonumber(text) == 2 then 480 | print("there are 5 parameters, each requiring a number. Recommend doing 1 digit numbers") 481 | for i=1,5,1 do 482 | print("enter param " .. i) 483 | text = term.read() 484 | config.cryptKey[i] = tonumber(text) 485 | end 486 | else 487 | config.cryptKey = {1,2,3,4,5} 488 | end 489 | config.type = "link" 490 | config.num = 3 491 | config.version = version 492 | modem.open(syncPort) 493 | modem.broadcast(syncPort,"syncport") 494 | local e,_,_,_,_,msg = event.pull(1,"modem_message") 495 | modem.close(syncPort) 496 | if e then 497 | config.port = tonumber(msg) 498 | else 499 | print("What port is the server running off of?") 500 | local text = term.read() 501 | config.port = tonumber(text:sub(1,-2)) 502 | term.clear() 503 | end 504 | saveTable(config,"extraConfig.txt") 505 | end 506 | extraConfig = loadTable("extraConfig.txt") 507 | modemPort = extraConfig.port 508 | if component.isAvailable("tunnel") then 509 | link = component.tunnel 510 | modem.close(modemPort) 511 | else 512 | modem.open(modemPort) 513 | end 514 | send(nil,modemPort,true,"getquery",ser.serialize({"passSettings"})) 515 | e,_,_,_,_,query = event.pull(3,"modem_message") 516 | if e == nil then 517 | print("Failed query. Is the server on?") 518 | os.exit() 519 | end 520 | query = ser.unserialize(crypt(query,extraConfig.cryptKey,true)) 521 | if query.num ~= 3 then 522 | print("Server is not 3.0.0 and up") 523 | os.exit() 524 | end 525 | local worked, user = checkLink() 526 | 527 | end 528 | 529 | function security.crypt(str,reverse) 530 | return true,crypt(str,extraConfig.cryptKey,reverse) 531 | end 532 | 533 | function security.save(table,location) 534 | saveTable(table,location) 535 | end 536 | function security.load(location) 537 | return loadTable(location) 538 | end 539 | 540 | function security.send(wait,...) 541 | send(nil,modemPort,true,...) 542 | if wait then 543 | local e, _, _, _, _, msg,msg2 = event.pull(3, "modem_message") 544 | if e then 545 | return true,msg,msg2 546 | else 547 | return false,"timed out" 548 | end 549 | else 550 | return true,"no return requested" 551 | end 552 | return false, "unknown error" 553 | end 554 | 555 | return security 556 | 557 | -------------------------------------------------------------------------------- /whattodo.txt: -------------------------------------------------------------------------------- 1 | Instructions on what I gotta check out and maybe add 2 | 3 | Definitely Servertine (this): 4 | 2. DoorSetup allow runtime door editing on currently running doors. (maybe an added perk of choosing door systems through naming multidoors) 5 | 5. SectorControl module for Servertine (an optional manual changing utility) 6 | 8. Database remote control module 7 | 8 | Debug and Test 9 | RFID Reader 10 | Linking and User ID 11 | KeyPad, RFID Reader, and Biometric Reader. 12 | 13 | done 14 | groups (-int) get dropdown rather than int changer with +- (DONE) 15 | Text Box for level in security module (no +- buttons alone, quick change) (DONE) 16 | CryptKey ALL THE FEATURES I CAN to prevent security holes (DONE) 17 | Save changes done on DoorSetup to prevent data loss upon leaving the module (DONE) 18 | Make SectorControl utilize runtime changes (3 wires per sector: 1 to turn off lockdown, another to enable, and another to lock open) (DONE) 19 | 20 | 21 | DO: 22 | 4. Update workspace when pressing the two buttons (update gui) --------------------------------------------------------------------------------