Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ WiRe Server ]]--
- --[[ by Dog ]]--
- --[[ aka HydrantHunter ]]--
- --[[ Wi = Wireless ]]--
- --[[ Re = Redstone ]]--
- --[[ pastebin hqpRw4Jy ]]--
- local WiReSver = "2.0.05"
- --[[
- Tested with/requires:
- - Minecraft 1.6.4+
- - ComputerCraft 1.63+
- - A Computer (standard or advanced) with a modem and one (1) advanced monitor array
- - One (1) or more WiRe Clients running on one computer (standard or advanced) each with a modem
- Special thanks to: SquidDev (AES encryption/decryption)
- Alex Kloss (base64 encoder/decoder)
- ]]--
- --# CONFIGURATION
- --# Default Settings
- local termX, termY = term.getSize()
- local thisCC = tostring(os.getComputerID())
- local config = "/data/WiReServerCfg"
- local ccSettings = {
- name = "WiReServer"; --# this server's name
- note = "short note"; --# short note/description
- color = "Silver"; --# network group
- getGPSFix = true; --# get a GPS fix on startup
- newColors = true; --# using new color names
- }
- local tArgs, modemSides, allClients, quietClients, loc = { ... }, { }, { }, { }, { }
- local pageNum, numPages, modemCount = 1, 1, 0
- local ccSuccess, kernelState, ccUpdate, help = false, false, false, false
- local network, client, thisCommand, pollTimer, mon, monX, monY, monSide, monControls, termScreenStatic, updateScreens, netReceive
- --# Terminal Colors
- local white = colors.white
- local black = colors.black
- local silver = colors.lightGray
- local gray = colors.gray
- local brown = colors.brown
- local yellow = colors.yellow
- local orange = colors.orange
- local red = colors.red
- local magenta = colors.magenta
- local purple = colors.purple
- local blue = colors.blue
- local sky = colors.lightBlue
- local cyan = colors.cyan
- local lime = colors.lime
- local green = colors.green
- if not term.isColor() then
- silver = colors.white
- gray = colors.black
- brown = colors.white
- yellow = colors.white
- orange = colors.white
- red = colors.white
- magenta = colors.white
- purple = colors.white
- green = colors.white
- blue = colors.black
- sky = colors.white
- cyan = colors.white
- lime = colors.white
- green = colors.white
- end
- --# Monitor colors
- local mwhite = colors.white
- local mblack = colors.black
- local msilver = colors.lightGray
- local mgray = colors.gray
- local mbrown = colors.brown
- local myellow = colors.yellow
- local morange = colors.orange
- local mred = colors.red
- local mmagenta = colors.magenta
- local mpurple = colors.purple
- local mblue = colors.blue
- local msky = colors.lightBlue
- local mcyan = colors.cyan
- local mlime = colors.lime
- local mgreen = colors.green
- --# Color tables
- local colorBurst = {
- Purple = { purple, mpurple, mwhite };
- Magenta = { magenta, mmagenta, mwhite };
- Blue = { term.isColor() and blue or white, mblue, mwhite };
- Sky = { sky, msky, mblack };
- Cyan = { cyan, mcyan, mblack };
- Green = { green, mgreen, mwhite };
- Lime = { lime, mlime, mblack };
- Red = { red, mred, mwhite };
- Orange = { orange, morange, mblack };
- Yellow = { yellow, myellow, mblack };
- Brown = { brown, mbrown, mwhite };
- Silver = { silver, msilver, mblack };
- Gray = { term.isColor() and gray or white, mgray, mwhite };
- White = { white, mwhite, mblack };
- Black = { white, mblack, mwhite };
- }
- local validStates = {
- OPEN = { morange, orange, "CLOSED" };
- CLOSED = { mgreen, green, "OPEN" };
- ON = { mgreen, green, "OFF" };
- OFF = { morange, orange, "ON" };
- LOCKED = { mred, red, "" };
- UNLOCK = { mgreen, green, "" };
- OFFLINE = { mred, red, "" };
- WiReQRY = { myellow, yellow, "" };
- init = { myellow, yellow, "" };
- Noise = { mred, red, "" };
- }
- --# END CONFIGURATION
- -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
- -- licensed under the terms of the LGPL2
- -- http://lua-users.org/wiki/BaseSixtyFour
- -- character table string
- local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- -- encoding
- function encode(data)
- return ((data:gsub('.', function(x)
- local r,b='',x:byte()
- for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
- return r;
- end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
- if (#x < 6) then return '' end
- local c=0
- for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
- return b:sub(c+1,c+1)
- end)..({ '', '==', '=' })[#data%3+1])
- end
- -- decoding
- function decode(data)
- data = string.gsub(data, '[^'..b..'=]', '')
- return (data:gsub('.', function(x)
- if (x == '=') then return '' end
- local r,f='',(b:find(x)-1)
- for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
- return r;
- end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
- if (#x ~= 8) then return '' end
- local c=0
- for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
- return string.char(c)
- end))
- end
- -- AES Lua implementation by SquidDev
- -- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
- local encrypt, decrypt
- do
- local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
- local bit=_W(function(_ENV, ...)
- --[[
- This bit API is designed to cope with unsigned integers instead of normal integers
- To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
- These are written in long form because no constant folding.
- ]]
- local floor = math.floor
- local lshift, rshift
- rshift = function(a,disp)
- return floor(a % 4294967296 / 2^disp)
- end
- lshift = function(a,disp)
- return (a * 2^disp) % 4294967296
- end
- return {
- -- bit operations
- bnot = bit32 and bit32.bnot or bit.bnot,
- band = bit32 and bit32.band or bit.band,
- bor = bit32 and bit32.bor or bit.bor,
- bxor = bit32 and bit32.bxor or bit.bxor,
- rshift = rshift,
- lshift = lshift,
- }
- end)
- local gf=_W(function(_ENV, ...)
- -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
- local bxor = bit32 and bit32.bxor or bit.bxor
- local lshift = bit.lshift
- -- private data of gf
- local n = 0x100
- local ord = 0xff
- local irrPolynom = 0x11b
- local exp = {}
- local log = {}
- --
- -- add two polynoms (its simply xor)
- --
- local function add(operand1, operand2)
- return bxor(operand1,operand2)
- end
- --
- -- subtract two polynoms (same as addition)
- --
- local function sub(operand1, operand2)
- return bxor(operand1,operand2)
- end
- --
- -- inverts element
- -- a^(-1) = g^(order - log(a))
- --
- local function invert(operand)
- -- special case for 1
- if (operand == 1) then
- return 1
- end
- -- normal invert
- local exponent = ord - log[operand]
- return exp[exponent]
- end
- --
- -- multiply two elements using a logarithm table
- -- a*b = g^(log(a)+log(b))
- --
- local function mul(operand1, operand2)
- if (operand1 == 0 or operand2 == 0) then
- return 0
- end
- local exponent = log[operand1] + log[operand2]
- if (exponent >= ord) then
- exponent = exponent - ord
- end
- return exp[exponent]
- end
- --
- -- divide two elements
- -- a/b = g^(log(a)-log(b))
- --
- local function div(operand1, operand2)
- if (operand1 == 0) then
- return 0
- end
- -- TODO: exception if operand2 == 0
- local exponent = log[operand1] - log[operand2]
- if (exponent < 0) then
- exponent = exponent + ord
- end
- return exp[exponent]
- end
- --
- -- print logarithmic table
- --
- local function printLog()
- for i = 1, n do
- print("log(", i-1, ")=", log[i-1])
- end
- end
- --
- -- print exponentiation table
- --
- local function printExp()
- for i = 1, n do
- print("exp(", i-1, ")=", exp[i-1])
- end
- end
- --
- -- calculate logarithmic and exponentiation table
- --
- local function initMulTable()
- local a = 1
- for i = 0,ord-1 do
- exp[i] = a
- log[a] = i
- -- multiply with generator x+1 -> left shift + 1
- a = bxor(lshift(a, 1), a)
- -- if a gets larger than order, reduce modulo irreducible polynom
- if a > ord then
- a = sub(a, irrPolynom)
- end
- end
- end
- initMulTable()
- return {
- add = add,
- sub = sub,
- invert = invert,
- mul = mul,
- div = div,
- printLog = printLog,
- printExp = printExp,
- }
- end)
- util=_W(function(_ENV, ...)
- -- Cache some bit operators
- local bxor = bit.bxor
- local rshift = bit.rshift
- local band = bit.band
- local lshift = bit.lshift
- local sleepCheckIn
- --
- -- calculate the parity of one byte
- --
- local function byteParity(byte)
- byte = bxor(byte, rshift(byte, 4))
- byte = bxor(byte, rshift(byte, 2))
- byte = bxor(byte, rshift(byte, 1))
- return band(byte, 1)
- end
- --
- -- get byte at position index
- --
- local function getByte(number, index)
- return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
- end
- --
- -- put number into int at position index
- --
- local function putByte(number, index)
- return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
- end
- --
- -- convert byte array to int array
- --
- local function bytesToInts(bytes, start, n)
- local ints = {}
- for i = 0, n - 1 do
- ints[i + 1] =
- putByte(bytes[start + (i*4)], 3) +
- putByte(bytes[start + (i*4) + 1], 2) +
- putByte(bytes[start + (i*4) + 2], 1) +
- putByte(bytes[start + (i*4) + 3], 0)
- if n % 10000 == 0 then sleepCheckIn() end
- end
- return ints
- end
- --
- -- convert int array to byte array
- --
- local function intsToBytes(ints, output, outputOffset, n)
- n = n or #ints
- for i = 0, n - 1 do
- for j = 0,3 do
- output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
- end
- if n % 10000 == 0 then sleepCheckIn() end
- end
- return output
- end
- --
- -- convert bytes to hexString
- --
- local function bytesToHex(bytes)
- local hexBytes = ""
- for i,byte in ipairs(bytes) do
- hexBytes = hexBytes .. string.format("%02x ", byte)
- end
- return hexBytes
- end
- local function hexToBytes(bytes)
- local out = {}
- for i = 1, #bytes, 2 do
- out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
- end
- return out
- end
- --
- -- convert data to hex string
- --
- local function toHexString(data)
- local type = type(data)
- if (type == "number") then
- return string.format("%08x",data)
- elseif (type == "table") then
- return bytesToHex(data)
- elseif (type == "string") then
- local bytes = {string.byte(data, 1, #data)}
- return bytesToHex(bytes)
- else
- return data
- end
- end
- local function padByteString(data)
- local dataLength = #data
- local random1 = math.random(0,255)
- local random2 = math.random(0,255)
- local prefix = string.char(random1,
- random2,
- random1,
- random2,
- getByte(dataLength, 3),
- getByte(dataLength, 2),
- getByte(dataLength, 1),
- getByte(dataLength, 0)
- )
- data = prefix .. data
- local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
- for i=1,paddingLength do
- padding = padding .. string.char(math.random(0,255))
- end
- return data .. padding
- end
- local function properlyDecrypted(data)
- local random = {string.byte(data,1,4)}
- if (random[1] == random[3] and random[2] == random[4]) then
- return true
- end
- return false
- end
- local function unpadByteString(data)
- if (not properlyDecrypted(data)) then
- return nil
- end
- local dataLength = putByte(string.byte(data,5), 3)
- + putByte(string.byte(data,6), 2)
- + putByte(string.byte(data,7), 1)
- + putByte(string.byte(data,8), 0)
- return string.sub(data,9,8+dataLength)
- end
- local function xorIV(data, iv)
- for i = 1,16 do
- data[i] = bxor(data[i], iv[i])
- end
- end
- local function increment(data)
- local i = 16
- while true do
- local value = data[i] + 1
- if value >= 256 then
- data[i] = value - 256
- i = (i - 2) % 16 + 1
- else
- data[i] = value
- break
- end
- end
- end
- -- Called every encryption cycle
- local push, pull, time = os.queueEvent, coroutine.yield, os.time
- local oldTime = time()
- local function sleepCheckIn()
- local newTime = time()
- if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
- oldTime = newTime
- push("sleep")
- pull("sleep")
- end
- end
- local function getRandomData(bytes)
- local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
- local result = {}
- for i=1,bytes do
- insert(result, random(0,255))
- if i % 10240 == 0 then sleep() end
- end
- return result
- end
- local function getRandomString(bytes)
- local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
- local result = {}
- for i=1,bytes do
- insert(result, char(random(0,255)))
- if i % 10240 == 0 then sleep() end
- end
- return table.concat(result)
- end
- return {
- byteParity = byteParity,
- getByte = getByte,
- putByte = putByte,
- bytesToInts = bytesToInts,
- intsToBytes = intsToBytes,
- bytesToHex = bytesToHex,
- hexToBytes = hexToBytes,
- toHexString = toHexString,
- padByteString = padByteString,
- properlyDecrypted = properlyDecrypted,
- unpadByteString = unpadByteString,
- xorIV = xorIV,
- increment = increment,
- sleepCheckIn = sleepCheckIn,
- getRandomData = getRandomData,
- getRandomString = getRandomString,
- }
- end)
- aes=_W(function(_ENV, ...)
- -- Implementation of AES with nearly pure lua
- -- AES with lua is slow, really slow :-)
- local putByte = util.putByte
- local getByte = util.getByte
- -- some constants
- local ROUNDS = 'rounds'
- local KEY_TYPE = "type"
- local ENCRYPTION_KEY=1
- local DECRYPTION_KEY=2
- -- aes SBOX
- local SBox = {}
- local iSBox = {}
- -- aes tables
- local table0 = {}
- local table1 = {}
- local table2 = {}
- local table3 = {}
- local tableInv0 = {}
- local tableInv1 = {}
- local tableInv2 = {}
- local tableInv3 = {}
- -- round constants
- local rCon = {
- 0x01000000,
- 0x02000000,
- 0x04000000,
- 0x08000000,
- 0x10000000,
- 0x20000000,
- 0x40000000,
- 0x80000000,
- 0x1b000000,
- 0x36000000,
- 0x6c000000,
- 0xd8000000,
- 0xab000000,
- 0x4d000000,
- 0x9a000000,
- 0x2f000000,
- }
- --
- -- affine transformation for calculating the S-Box of AES
- --
- local function affinMap(byte)
- mask = 0xf8
- result = 0
- for i = 1,8 do
- result = bit.lshift(result,1)
- parity = util.byteParity(bit.band(byte,mask))
- result = result + parity
- -- simulate roll
- lastbit = bit.band(mask, 1)
- mask = bit.band(bit.rshift(mask, 1),0xff)
- mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
- end
- return bit.bxor(result, 0x63)
- end
- --
- -- calculate S-Box and inverse S-Box of AES
- -- apply affine transformation to inverse in finite field 2^8
- --
- local function calcSBox()
- for i = 0, 255 do
- inverse = i ~= 0 and gf.invert(i) or i
- mapped = affinMap(inverse)
- SBox[i] = mapped
- iSBox[mapped] = i
- end
- end
- --
- -- Calculate round tables
- -- round tables are used to calculate shiftRow, MixColumn and SubBytes
- -- with 4 table lookups and 4 xor operations.
- --
- local function calcRoundTables()
- for x = 0,255 do
- byte = SBox[x]
- table0[x] = putByte(gf.mul(0x03, byte), 0)
- + putByte( byte , 1)
- + putByte( byte , 2)
- + putByte(gf.mul(0x02, byte), 3)
- table1[x] = putByte( byte , 0)
- + putByte( byte , 1)
- + putByte(gf.mul(0x02, byte), 2)
- + putByte(gf.mul(0x03, byte), 3)
- table2[x] = putByte( byte , 0)
- + putByte(gf.mul(0x02, byte), 1)
- + putByte(gf.mul(0x03, byte), 2)
- + putByte( byte , 3)
- table3[x] = putByte(gf.mul(0x02, byte), 0)
- + putByte(gf.mul(0x03, byte), 1)
- + putByte( byte , 2)
- + putByte( byte , 3)
- end
- end
- --
- -- Calculate inverse round tables
- -- does the inverse of the normal roundtables for the equivalent
- -- decryption algorithm.
- --
- local function calcInvRoundTables()
- for x = 0,255 do
- byte = iSBox[x]
- tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
- + putByte(gf.mul(0x0d, byte), 1)
- + putByte(gf.mul(0x09, byte), 2)
- + putByte(gf.mul(0x0e, byte), 3)
- tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
- + putByte(gf.mul(0x09, byte), 1)
- + putByte(gf.mul(0x0e, byte), 2)
- + putByte(gf.mul(0x0b, byte), 3)
- tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
- + putByte(gf.mul(0x0e, byte), 1)
- + putByte(gf.mul(0x0b, byte), 2)
- + putByte(gf.mul(0x0d, byte), 3)
- tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
- + putByte(gf.mul(0x0b, byte), 1)
- + putByte(gf.mul(0x0d, byte), 2)
- + putByte(gf.mul(0x09, byte), 3)
- end
- end
- --
- -- rotate word: 0xaabbccdd gets 0xbbccddaa
- -- used for key schedule
- --
- local function rotWord(word)
- local tmp = bit.band(word,0xff000000)
- return (bit.lshift(word,8) + bit.rshift(tmp,24))
- end
- --
- -- replace all bytes in a word with the SBox.
- -- used for key schedule
- --
- local function subWord(word)
- return putByte(SBox[getByte(word,0)],0)
- + putByte(SBox[getByte(word,1)],1)
- + putByte(SBox[getByte(word,2)],2)
- + putByte(SBox[getByte(word,3)],3)
- end
- --
- -- generate key schedule for aes encryption
- --
- -- returns table with all round keys and
- -- the necessary number of rounds saved in [ROUNDS]
- --
- local function expandEncryptionKey(key)
- local keySchedule = {}
- local keyWords = math.floor(#key / 4)
- if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
- error("Invalid key size: " .. tostring(keyWords))
- return nil
- end
- keySchedule[ROUNDS] = keyWords + 6
- keySchedule[KEY_TYPE] = ENCRYPTION_KEY
- for i = 0,keyWords - 1 do
- keySchedule[i] = putByte(key[i*4+1], 3)
- + putByte(key[i*4+2], 2)
- + putByte(key[i*4+3], 1)
- + putByte(key[i*4+4], 0)
- end
- for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
- local tmp = keySchedule[i-1]
- if ( i % keyWords == 0) then
- tmp = rotWord(tmp)
- tmp = subWord(tmp)
- local index = math.floor(i/keyWords)
- tmp = bit.bxor(tmp,rCon[index])
- elseif (keyWords > 6 and i % keyWords == 4) then
- tmp = subWord(tmp)
- end
- keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
- end
- return keySchedule
- end
- --
- -- Inverse mix column
- -- used for key schedule of decryption key
- --
- local function invMixColumnOld(word)
- local b0 = getByte(word,3)
- local b1 = getByte(word,2)
- local b2 = getByte(word,1)
- local b3 = getByte(word,0)
- return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
- gf.mul(0x0d, b2)),
- gf.mul(0x09, b3)),
- gf.mul(0x0e, b0)),3)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
- gf.mul(0x0d, b3)),
- gf.mul(0x09, b0)),
- gf.mul(0x0e, b1)),2)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
- gf.mul(0x0d, b0)),
- gf.mul(0x09, b1)),
- gf.mul(0x0e, b2)),1)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
- gf.mul(0x0d, b1)),
- gf.mul(0x09, b2)),
- gf.mul(0x0e, b3)),0)
- end
- --
- -- Optimized inverse mix column
- -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
- -- TODO: make it work
- --
- local function invMixColumn(word)
- local b0 = getByte(word,3)
- local b1 = getByte(word,2)
- local b2 = getByte(word,1)
- local b3 = getByte(word,0)
- local t = bit.bxor(b3,b2)
- local u = bit.bxor(b1,b0)
- local v = bit.bxor(t,u)
- v = bit.bxor(v,gf.mul(0x08,v))
- w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
- v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
- return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
- + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t )), 1)
- + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
- + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u )), 3)
- end
- --
- -- generate key schedule for aes decryption
- --
- -- uses key schedule for aes encryption and transforms each
- -- key by inverse mix column.
- --
- local function expandDecryptionKey(key)
- local keySchedule = expandEncryptionKey(key)
- if (keySchedule == nil) then
- return nil
- end
- keySchedule[KEY_TYPE] = DECRYPTION_KEY
- for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
- keySchedule[i] = invMixColumnOld(keySchedule[i])
- end
- return keySchedule
- end
- --
- -- xor round key to state
- --
- local function addRoundKey(state, key, round)
- for i = 0, 3 do
- state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
- end
- end
- --
- -- do encryption round (ShiftRow, SubBytes, MixColumn together)
- --
- local function doRound(origState, dstState)
- dstState[1] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[1],3)],
- table1[getByte(origState[2],2)]),
- table2[getByte(origState[3],1)]),
- table3[getByte(origState[4],0)])
- dstState[2] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[2],3)],
- table1[getByte(origState[3],2)]),
- table2[getByte(origState[4],1)]),
- table3[getByte(origState[1],0)])
- dstState[3] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[3],3)],
- table1[getByte(origState[4],2)]),
- table2[getByte(origState[1],1)]),
- table3[getByte(origState[2],0)])
- dstState[4] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[4],3)],
- table1[getByte(origState[1],2)]),
- table2[getByte(origState[2],1)]),
- table3[getByte(origState[3],0)])
- end
- --
- -- do last encryption round (ShiftRow and SubBytes)
- --
- local function doLastRound(origState, dstState)
- dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
- + putByte(SBox[getByte(origState[2],2)], 2)
- + putByte(SBox[getByte(origState[3],1)], 1)
- + putByte(SBox[getByte(origState[4],0)], 0)
- dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
- + putByte(SBox[getByte(origState[3],2)], 2)
- + putByte(SBox[getByte(origState[4],1)], 1)
- + putByte(SBox[getByte(origState[1],0)], 0)
- dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
- + putByte(SBox[getByte(origState[4],2)], 2)
- + putByte(SBox[getByte(origState[1],1)], 1)
- + putByte(SBox[getByte(origState[2],0)], 0)
- dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
- + putByte(SBox[getByte(origState[1],2)], 2)
- + putByte(SBox[getByte(origState[2],1)], 1)
- + putByte(SBox[getByte(origState[3],0)], 0)
- end
- --
- -- do decryption round
- --
- local function doInvRound(origState, dstState)
- dstState[1] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[1],3)],
- tableInv1[getByte(origState[4],2)]),
- tableInv2[getByte(origState[3],1)]),
- tableInv3[getByte(origState[2],0)])
- dstState[2] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[2],3)],
- tableInv1[getByte(origState[1],2)]),
- tableInv2[getByte(origState[4],1)]),
- tableInv3[getByte(origState[3],0)])
- dstState[3] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[3],3)],
- tableInv1[getByte(origState[2],2)]),
- tableInv2[getByte(origState[1],1)]),
- tableInv3[getByte(origState[4],0)])
- dstState[4] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[4],3)],
- tableInv1[getByte(origState[3],2)]),
- tableInv2[getByte(origState[2],1)]),
- tableInv3[getByte(origState[1],0)])
- end
- --
- -- do last decryption round
- --
- local function doInvLastRound(origState, dstState)
- dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
- + putByte(iSBox[getByte(origState[4],2)], 2)
- + putByte(iSBox[getByte(origState[3],1)], 1)
- + putByte(iSBox[getByte(origState[2],0)], 0)
- dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
- + putByte(iSBox[getByte(origState[1],2)], 2)
- + putByte(iSBox[getByte(origState[4],1)], 1)
- + putByte(iSBox[getByte(origState[3],0)], 0)
- dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
- + putByte(iSBox[getByte(origState[2],2)], 2)
- + putByte(iSBox[getByte(origState[1],1)], 1)
- + putByte(iSBox[getByte(origState[4],0)], 0)
- dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
- + putByte(iSBox[getByte(origState[3],2)], 2)
- + putByte(iSBox[getByte(origState[2],1)], 1)
- + putByte(iSBox[getByte(origState[1],0)], 0)
- end
- --
- -- encrypts 16 Bytes
- -- key encryption key schedule
- -- input array with input data
- -- inputOffset start index for input
- -- output array for encrypted data
- -- outputOffset start index for output
- --
- local function encrypt(key, input, inputOffset, output, outputOffset)
- --default parameters
- inputOffset = inputOffset or 1
- output = output or {}
- outputOffset = outputOffset or 1
- local state = {}
- local tmpState = {}
- if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
- error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
- return
- end
- state = util.bytesToInts(input, inputOffset, 4)
- addRoundKey(state, key, 0)
- local round = 1
- while (round < key[ROUNDS] - 1) do
- -- do a double round to save temporary assignments
- doRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round + 1
- doRound(tmpState, state)
- addRoundKey(state, key, round)
- round = round + 1
- end
- doRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round +1
- doLastRound(tmpState, state)
- addRoundKey(state, key, round)
- util.sleepCheckIn()
- return util.intsToBytes(state, output, outputOffset)
- end
- --
- -- decrypt 16 bytes
- -- key decryption key schedule
- -- input array with input data
- -- inputOffset start index for input
- -- output array for decrypted data
- -- outputOffset start index for output
- ---
- local function decrypt(key, input, inputOffset, output, outputOffset)
- -- default arguments
- inputOffset = inputOffset or 1
- output = output or {}
- outputOffset = outputOffset or 1
- local state = {}
- local tmpState = {}
- if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
- error("No decryption key: " .. tostring(key[KEY_TYPE]))
- return
- end
- state = util.bytesToInts(input, inputOffset, 4)
- addRoundKey(state, key, key[ROUNDS])
- local round = key[ROUNDS] - 1
- while (round > 2) do
- -- do a double round to save temporary assignments
- doInvRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round - 1
- doInvRound(tmpState, state)
- addRoundKey(state, key, round)
- round = round - 1
- end
- doInvRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round - 1
- doInvLastRound(tmpState, state)
- addRoundKey(state, key, round)
- util.sleepCheckIn()
- return util.intsToBytes(state, output, outputOffset)
- end
- -- calculate all tables when loading this file
- calcSBox()
- calcRoundTables()
- calcInvRoundTables()
- return {
- ROUNDS = ROUNDS,
- KEY_TYPE = KEY_TYPE,
- ENCRYPTION_KEY = ENCRYPTION_KEY,
- DECRYPTION_KEY = DECRYPTION_KEY,
- expandEncryptionKey = expandEncryptionKey,
- expandDecryptionKey = expandDecryptionKey,
- encrypt = encrypt,
- decrypt = decrypt,
- }
- end)
- local buffer=_W(function(_ENV, ...)
- local function new ()
- return {}
- end
- local function addString (stack, s)
- table.insert(stack, s)
- end
- local function toString (stack)
- return table.concat(stack)
- end
- return {
- new = new,
- addString = addString,
- toString = toString,
- }
- end)
- ciphermode=_W(function(_ENV, ...)
- local public = {}
- --
- -- Encrypt strings
- -- key - byte array with key
- -- string - string to encrypt
- -- modefunction - function for cipher mode to use
- --
- local random, unpack = math.random, unpack or table.unpack
- function public.encryptString(key, data, modeFunction, iv)
- if iv then
- local ivCopy = {}
- for i = 1, 16 do ivCopy[i] = iv[i] end
- iv = ivCopy
- else
- iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- end
- local keySched = aes.expandEncryptionKey(key)
- local encryptedData = buffer.new()
- for i = 1, #data/16 do
- local offset = (i-1)*16 + 1
- local byteData = {string.byte(data,offset,offset +15)}
- iv = modeFunction(keySched, byteData, iv)
- buffer.addString(encryptedData, string.char(unpack(byteData)))
- end
- return buffer.toString(encryptedData)
- end
- --
- -- the following 4 functions can be used as
- -- modefunction for encryptString
- --
- -- Electronic code book mode encrypt function
- function public.encryptECB(keySched, byteData, iv)
- aes.encrypt(keySched, byteData, 1, byteData, 1)
- end
- -- Cipher block chaining mode encrypt function
- function public.encryptCBC(keySched, byteData, iv)
- util.xorIV(byteData, iv)
- aes.encrypt(keySched, byteData, 1, byteData, 1)
- return byteData
- end
- -- Output feedback mode encrypt function
- function public.encryptOFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return iv
- end
- -- Cipher feedback mode encrypt function
- function public.encryptCFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return byteData
- end
- function public.encryptCTR(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = iv[j] end
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- util.increment(nextIV)
- return nextIV
- end
- --
- -- Decrypt strings
- -- key - byte array with key
- -- string - string to decrypt
- -- modefunction - function for cipher mode to use
- --
- function public.decryptString(key, data, modeFunction, iv)
- if iv then
- local ivCopy = {}
- for i = 1, 16 do ivCopy[i] = iv[i] end
- iv = ivCopy
- else
- iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- end
- local keySched
- if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
- keySched = aes.expandEncryptionKey(key)
- else
- keySched = aes.expandDecryptionKey(key)
- end
- local decryptedData = buffer.new()
- for i = 1, #data/16 do
- local offset = (i-1)*16 + 1
- local byteData = {string.byte(data,offset,offset +15)}
- iv = modeFunction(keySched, byteData, iv)
- buffer.addString(decryptedData, string.char(unpack(byteData)))
- end
- return buffer.toString(decryptedData)
- end
- --
- -- the following 4 functions can be used as
- -- modefunction for decryptString
- --
- -- Electronic code book mode decrypt function
- function public.decryptECB(keySched, byteData, iv)
- aes.decrypt(keySched, byteData, 1, byteData, 1)
- return iv
- end
- -- Cipher block chaining mode decrypt function
- function public.decryptCBC(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = byteData[j] end
- aes.decrypt(keySched, byteData, 1, byteData, 1)
- util.xorIV(byteData, iv)
- return nextIV
- end
- -- Output feedback mode decrypt function
- function public.decryptOFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return iv
- end
- -- Cipher feedback mode decrypt function
- function public.decryptCFB(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = byteData[j] end
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return nextIV
- end
- public.decryptCTR = public.encryptCTR
- return public
- end)
- -- Simple API for encrypting strings.
- --
- AES128 = 16
- AES192 = 24
- AES256 = 32
- ECBMODE = 1
- CBCMODE = 2
- OFBMODE = 3
- CFBMODE = 4
- CTRMODE = 4
- local function pwToKey(password, keyLength, iv)
- local padLength = keyLength
- if (keyLength == AES192) then
- padLength = 32
- end
- if (padLength > #password) then
- local postfix = ""
- for i = 1,padLength - #password do
- postfix = postfix .. string.char(0)
- end
- password = password .. postfix
- else
- password = string.sub(password, 1, padLength)
- end
- local pwBytes = {string.byte(password,1,#password)}
- password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
- password = string.sub(password, 1, keyLength)
- return {string.byte(password,1,#password)}
- end
- --
- -- Encrypts string data with password password.
- -- password - the encryption key is generated from this string
- -- data - string to encrypt (must not be too large)
- -- keyLength - length of aes key: 128(default), 192 or 256 Bit
- -- mode - mode of encryption: ecb, cbc(default), ofb, cfb
- --
- -- mode and keyLength must be the same for encryption and decryption.
- --
- function encrypt(password, data, keyLength, mode, iv)
- assert(password ~= nil, "Empty password.")
- assert(data ~= nil, "Empty data.")
- local mode = mode or CBCMODE
- local keyLength = keyLength or AES128
- local key = pwToKey(password, keyLength, iv)
- local paddedData = util.padByteString(data)
- if mode == ECBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
- elseif mode == CBCMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
- elseif mode == OFBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
- elseif mode == CFBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
- elseif mode == CTRMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
- else
- error("Unknown mode", 2)
- end
- end
- --
- -- Decrypts string data with password password.
- -- password - the decryption key is generated from this string
- -- data - string to encrypt
- -- keyLength - length of aes key: 128(default), 192 or 256 Bit
- -- mode - mode of decryption: ecb, cbc(default), ofb, cfb
- --
- -- mode and keyLength must be the same for encryption and decryption.
- --
- function decrypt(password, data, keyLength, mode, iv)
- local mode = mode or CBCMODE
- local keyLength = keyLength or AES128
- local key = pwToKey(password, keyLength, iv)
- local plain
- if mode == ECBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
- elseif mode == CBCMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
- elseif mode == OFBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
- elseif mode == CFBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
- elseif mode == CTRMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
- else
- error("Unknown mode", 2)
- end
- result = util.unpadByteString(plain)
- if (result == nil) then
- return nil
- end
- return result
- end
- end
- local function saveData()
- local srvConfig = fs.open(config, "w") or error("saveData(): Cannot open " .. config .. " for writing", 0)
- srvConfig.write(textutils.serialize(ccSettings))
- srvConfig.close()
- end
- local function clearMon(bgColor)
- mon.setBackgroundColor(bgColor or mblack)
- mon.clear()
- end
- local function clearMonButtons()
- local line = string.rep(" ", monX - 1)
- mon.setBackgroundColor(mblack)
- for i = 3, 8 do
- mon.setCursorPos(2, i)
- mon.write(line)
- end
- end
- do
- local function splitName(name)
- if #name > 6 then
- if string.find(name, " ") then
- local firstPart, lastPart = name:sub(1, string.find(name, " ") - 1), name:sub(string.find(name, " ") + 1)
- if #firstPart <= 6 and #lastPart <= 6 then
- return firstPart, lastPart
- end
- end
- return name:sub(1, 6), name:sub(7)
- else
- return name, ""
- end
- end
- local function powerSwitch(x, y, state)
- mon.setCursorPos(x, y)
- mon.setBackgroundColor((state == "OPEN" or state == "OFF") and mgray or mgreen)
- mon.write(" ") --# Switch Top (OFF/ON/OPEN/CLOSED)
- mon.setCursorPos(x, y + 1)
- mon.setBackgroundColor((state == "OPEN" or state == "OFF") and morange or mgray)
- mon.write(" ") --# Switch Bottom (OFF/ON/OPEN/CLOSED)
- end
- monControls = function()
- if #allClients == 0 then
- mon.setTextColor(mred)
- mon.setCursorPos(4, 4)
- mon.write("No clients are")
- mon.setCursorPos(2, 5)
- mon.write("currently connected")
- else
- local firstName, lastName, xPos, devState, lockState
- for i = 1, #allClients do
- firstName, lastName = splitName(allClients[i].name)
- xPos, devState, lockState = (i * 8) - 6, allClients[i].deviceState, allClients[i].lockState
- mon.setBackgroundColor(mblack)
- mon.setTextColor(quietClients[i] and myellow or msky)
- mon.setCursorPos(xPos, 3)
- mon.write(firstName .. string.rep(" ", 6 - #firstName))
- mon.setCursorPos(xPos, 4)
- mon.write(lastName .. string.rep(" ", 6 - #lastName))
- mon.setCursorPos(xPos, 8)
- mon.setTextColor(lockState and mred or (validStates[devState][1] or myellow))
- mon.write(lockState and "LOCKED" or (devState .. string.rep(" ", 6 - #devState)))
- powerSwitch((i * 8) - 6, 5, devState)
- end
- end
- end
- end
- local function clearTerm()
- term.setBackgroundColor(black)
- term.setTextColor(white)
- term.clear()
- term.setCursorPos(1, 1)
- end
- local function clearDataArea()
- term.setBackgroundColor(black)
- local line = string.rep(" ", 25)
- for i = 5, termY do
- term.setCursorPos(26, i)
- term.write(line)
- end
- end
- do
- local function sortDeviceList(newDeviceData)
- local clientCount = #allClients
- if clientCount == 0 then --# the list is empty
- allClients[1] = { } --# add it
- quietClients[1] = false
- for k, v in pairs(newDeviceData) do
- allClients[1][k] = v
- end
- thisCommand = allClients[1].lockState and "LOCKED" or allClients[1].deviceState
- clearMonButtons()
- else
- for i = 1, clientCount do
- if client == allClients[i].cc then --# client is already on the list
- thisCommand = "WiReQRY"
- if newDeviceData.deviceState ~= allClients[i].deviceState then
- thisCommand = newDeviceData.deviceState
- allClients[i].deviceState = thisCommand
- ccUpdate = true
- end
- if newDeviceData.lockState ~= allClients[i].lockState then
- thisCommand = newDeviceData.lockState and "LOCKED" or "UNLOCK"
- allClients[i].lockState = newDeviceData.lockState
- ccUpdate = true
- end
- if quietClients[i] then ccUpdate = true end
- allClients[i].quietCount = 0
- quietClients[i] = false
- return
- end
- end
- if clientCount < 20 then
- for i = 1, clientCount do
- if newDeviceData.name < allClients[i].name then --# alphabetize
- table.insert(allClients, i, newDeviceData) --# insert
- table.insert(quietClients, i, false)
- break
- end
- if i == clientCount then --# we've reached the end of the list
- clientCount = clientCount + 1
- allClients[clientCount] = { } --# tack it on
- quietClients[clientCount] = false
- for k, v in pairs(newDeviceData) do
- allClients[clientCount][k] = v
- end
- break
- end
- end
- thisCommand = allClients[clientCount].lockState and "LOCKED" or allClients[clientCount].deviceState
- end
- end
- ccUpdate = true
- numPages = math.max(1, math.ceil(#allClients / 7))
- pageNum = math.min(math.max(1, pageNum), numPages)
- end
- netReceive = function()
- local id, newCmdData, success, encryptedMessage, decodedMessage, encKey
- while true do
- for i = 1, modemCount do
- if not rednet.isOpen(modemSides[i]) then rednet.open(modemSides[i]) end
- end
- id, encryptedMessage = rednet.receive(network)
- newCmdData, ccSuccess = { }, false
- if type(encryptedMessage) == "string" then
- success, decodedMessage = pcall(decode, encryptedMessage)
- if success and type(decodedMessage) == "string" then
- encKey = thisCC .. "WiRe!Comms" .. tostring(id)
- success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
- if success and type(decryptedMessage) == "string" then
- success, newCmdData = pcall(textutils.unserialize, decryptedMessage)
- if success and type(newCmdData) == "table" and newCmdData.program and newCmdData.program == "WiRe" and newCmdData.cc == id and newCmdData.color == ccSettings.color then
- client = id
- if newCmdData.deviceState == "OFFLINE" then
- for i = 1, #allClients do
- if allClients[i].cc == client then
- table.remove(allClients, i)
- table.remove(quietClients, i)
- clearDataArea()
- clearMonButtons()
- thisCommand = newCmdData.deviceState
- ccUpdate = true
- break
- end
- end
- else
- sortDeviceList(newCmdData)
- end
- ccSuccess = true
- end
- end
- end
- end
- if not ccSuccess then
- client = nil
- thisCommand = "Noise"
- end
- updateScreens()
- end
- end
- end
- local function netSend(toAll)
- local dataPack = textutils.serialize({ program = "WiRe", cc = tonumber(thisCC), color = ccSettings.color, cmd = thisCommand })
- for i = 1, modemCount do
- if not rednet.isOpen(modemSides[i]) then rednet.open(modemSides[i]) end
- end
- if toAll then
- local encKey = thisCC .. "WiRe!Comms" .. thisCC
- local encryptedPackage = encode(encrypt(encKey, dataPack))
- rednet.broadcast(encryptedPackage, network)
- return true
- elseif client then
- local encKey = tostring(client) .. "WiRe!Comms" .. thisCC
- local encryptedPackage = encode(encrypt(encKey, dataPack))
- rednet.send(client, encryptedPackage, network)
- return true
- end
- return false
- end
- local function termScreen()
- term.setCursorPos(14, 12)
- term.setTextColor(white)
- local lastClient = client or "Server"
- term.write(tostring(lastClient) .. " ")
- term.setCursorPos(14, 13)
- term.setTextColor(thisCommand == "LOCKED" and red or (validStates[thisCommand][2] or yellow))
- term.write(thisCommand .. string.rep(" ", 9 - #thisCommand))
- term.setCursorPos(14, 14)
- term.setTextColor(ccSuccess and green or red)
- term.write(tostring(ccSuccess) .. " ")
- term.setCursorPos(26, 3) --# Client list
- term.setTextColor(silver)
- term.write("Clients (page " .. tostring(pageNum) .. " of " .. tostring(numPages) .. ") ")
- local yPos, spacerA, spacerB, spacerC, lockState, devState = 0, string.rep(" ", math.floor(termX / 2)), string.rep(" ", 14), string.rep(" ", 10)
- for i = (pageNum * 7) - 6, math.min(pageNum * 7, #allClients) do
- yPos, lockState, devState = yPos + 1, allClients[i].lockState, allClients[i].deviceState
- term.setCursorPos(26, (yPos * 2) + 3)
- term.setTextColor(quietClients[i] and yellow or sky)
- term.write(allClients[i].name .. " (" .. tostring(allClients[i].cc) .. ")" .. spacerA)
- term.setTextColor(lockState and red or (validStates[devState][2] or yellow))
- term.setCursorPos(termX - 8, (yPos * 2) + 3)
- term.write(lockState and " LOCKED" or (string.rep(" ", 8 - #devState) .. devState))
- term.setCursorPos(27, (yPos * 2) + 4)
- term.setTextColor(silver)
- if allClients[i].loc.x == "No GPS Fix" then
- term.write(allClients[i].loc.x .. spacerB)
- else
- term.write("GPS: " .. tostring(allClients[i].loc.x) .. "/" .. tostring(allClients[i].loc.y) .. "/" .. tostring(allClients[i].loc.z) .. spacerC)
- end
- end
- end
- do
- local labels = {
- [1] = { "Name:", 1, 3 };
- [2] = { "Note:", 1, 4 };
- [3] = { "Group:", 1, 6 };
- [4] = { "cc#", 1, 8 };
- [5] = { "Modems:", 1, 10 };
- [6] = { "Last Client:", 1, 12 };
- [7] = { "Last State:", 1, 13 };
- [8] = { "Success:", 1, 14 };
- [9] = { "Location: x:", 1, 16 };
- [10] = { "y:", 11, 17 };
- [11] = { "z:", 11, 18 };
- }
- termScreenStatic = function()
- term.setBackgroundColor(black)
- term.clear()
- local hText = "WiRe Server " .. WiReSver
- local spacer = (termX - #hText) / 2
- term.setBackgroundColor(blue)
- term.setTextColor(white)
- term.setCursorPos(1, 1)
- term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
- term.setBackgroundColor(black)
- term.setTextColor(silver)
- for i = 1, 11 do
- term.setCursorPos(labels[i][2], labels[i][3])
- term.write(labels[i][1])
- end
- term.setTextColor(white)
- term.setCursorPos(7, 3)
- term.write(ccSettings.name)
- term.setCursorPos(7, 4)
- term.write(ccSettings.note)
- term.setCursorPos(5, 8)
- term.write(thisCC)
- term.setCursorPos(9, 10)
- term.write(tostring(modemCount))
- term.setCursorPos(14, 16)
- term.write(tostring(loc.x))
- term.setCursorPos(14, 17)
- term.write(tostring(loc.y))
- term.setCursorPos(14, 18)
- term.write(tostring(loc.z))
- term.setTextColor(colorBurst[ccSettings.color][1] or silver)
- term.setCursorPos(8, 6)
- term.write(ccSettings.color)
- end
- end
- local function helpScreen()
- local hText = "WiRe Server Help"
- local xPos, spacer = math.floor(termX / 2), (termX - #hText) / 2
- term.setBackgroundColor(white)
- term.clear()
- term.setBackgroundColor(blue)
- term.setTextColor(white)
- term.setCursorPos(1, 1)
- term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
- term.setCursorPos(1, 2)
- term.setBackgroundColor(gray)
- term.write(string.rep(" ", termX))
- term.setCursorPos(xPos - 8, 2)
- term.write("-- Key Commands --")
- term.setCursorPos(1, 7)
- term.write(string.rep(" ", termX))
- term.setCursorPos(xPos - 8, 7)
- term.write("-- Client list --")
- term.setCursorPos(1, 13)
- term.write(string.rep(" ", termX))
- term.setCursorPos(xPos - 10, 13)
- term.write("-- Monitor Controls --")
- term.setBackgroundColor(white)
- term.setTextColor(black)
- term.setCursorPos(xPos - 8, 3)
- term.write("'q' to quit server")
- term.setCursorPos(xPos - 12, 5)
- term.write("'F1' to display/exit help")
- term.setCursorPos(xPos - 18, 9)
- term.write(", < [ { PGUP Go back one page")
- term.setCursorPos(xPos - 18, 11)
- term.write(". > ] } PGDN Go forward one page")
- term.setCursorPos(xPos - 18, 15)
- term.write("Touch a switch to toggle its state")
- term.setCursorPos(xPos - 18, 17)
- term.write("Touch a switch's status line to lock")
- term.setCursorPos(xPos - 18, 19)
- term.write("Touch a switch's status line to unlock")
- end
- updateScreens = function()
- if not tArgs[1] and not help then termScreen() end
- if #allClients == 0 or (thisCommand ~= "Noise" and ccUpdate) then
- monControls()
- ccUpdate = false
- end
- end
- local function shutDown()
- kernelState = false
- rednet.unhost(network, ccSettings.color)
- for i = 1, modemCount do
- if rednet.isOpen(modemSides[i]) then rednet.close(modemSides[i]) end
- end
- clearMon()
- end
- local function monTouch()
- local halfMon, _, touchSide, posX, posY, continue = monX / 2
- while true do
- _, touchSide, posX, posY = os.pullEvent("monitor_touch")
- if touchSide == monSide then
- continue = true
- if posY == monY and (posX < math.floor(halfMon) or posX > math.ceil(halfMon)) then
- thisCommand = posX < math.floor(halfMon) and "LOCKED" or "UNLOCK"
- client = "ALL"
- ccSuccess = netSend(true)
- ccUpdate = true
- continue = false
- end
- if continue then
- for i = 1, #allClients do
- if posX >= (i * 8) - 6 and posX <= (i * 8) - 1 then
- client = allClients[i].cc
- if posY == 8 then
- allClients[i].lockState = not allClients[i].lockState
- thisCommand = allClients[i].lockState and "LOCKED" or "UNLOCK"
- ccSuccess = netSend()
- ccUpdate = true
- break
- elseif posY > 4 and posY < 7 then
- if not allClients[i].lockState then
- thisCommand = validStates[allClients[i].deviceState][3]
- allClients[i].deviceState = thisCommand
- ccSuccess = netSend()
- ccUpdate = true
- end
- break
- end
- end
- end
- end
- if ccUpdate then updateScreens() end
- end
- end
- end
- local function userInput()
- local event, data
- while true do
- event, data = os.pullEvent()
- if event == "key" then
- if (data == keys.pageUp or data == keys.pageDown) and not help then
- pageNum = data == keys.pageUp and math.max(1, pageNum - 1) or math.min(pageNum + 1, numPages)
- if pageNum == numPages and numPages > 1 then clearDataArea() end
- termScreen()
- elseif (data == keys.home or data == keys["end"]) and not help then
- pageNum = data == keys.home and 1 or numPages
- if pageNum == numPages and numPages > 1 then clearDataArea() end
- termScreen()
- elseif data == keys.f1 then
- help = not help
- if help then
- helpScreen()
- else
- termScreenStatic()
- termScreen()
- end
- end
- elseif event == "char" then
- if (data == "," or data == "<" or data == "[" or data == "{" or data == "." or data == ">" or data == "]" or data == "}") and not help then
- pageNum = (data == "," or data == "<" or data == "[" or data == "{") and math.max(1, pageNum - 1) or math.min(pageNum + 1, numPages)
- if pageNum == numPages and numPages > 1 then clearDataArea() end
- termScreen()
- elseif string.lower(data) == "q" then
- shutDown()
- clearTerm()
- term.write("WiRe Server is OFFLINE")
- term.setCursorPos(1, 3)
- return
- end
- end
- end
- end
- local function foregroundShell()
- clearTerm()
- if fs.exists(tArgs[1]) then
- shell.run(table.unpack(tArgs))
- clearTerm()
- else
- term.write(tArgs[1] .. " missing")
- term.setCursorPos(1, 3)
- end
- shutDown()
- term.write("WiRe Server is OFFLINE")
- term.setCursorPos(1, 5)
- end
- local function dataPoller()
- local _, timer, clientSilent
- while true do
- _, timer = os.pullEvent("timer")
- if timer == pollTimer and kernelState then
- clientSilent = false
- for i = 1, #allClients do
- if allClients[i].quietCount > 2 then
- if not quietClients[i] then
- quietClients[i] = true
- clientSilent = true
- end
- else
- allClients[i].quietCount = allClients[i].quietCount + 1
- end
- end
- if clientSilent then monControls() end
- thisCommand = "WiReQRY"
- client = nil
- ccSuccess = true
- pollTimer = os.startTimer(7)
- if not help and not tArgs[1] then termScreen() end
- end
- end
- end
- local function initError(missing, device)
- if modemCount > 0 then
- for i = 1, modemCount do
- if rednet.isOpen(modemSides[i]) then
- rednet.close(modemSides[i])
- end
- end
- end
- term.clear()
- term.setTextColor(red)
- term.setCursorPos(1, 2)
- print("No " .. missing .. " detected!")
- print("WiRe Server REQUIRES")
- print(device .. ".")
- term.setCursorPos(1, 6)
- end
- local function firstRun()
- term.clear()
- local gotModem = false
- for _, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
- gotModem = true
- break
- end
- end
- if not gotModem then return initError("modem", "a modem") end
- --# Set server name
- term.setCursorPos(2, 2)
- term.write("Please name this server")
- repeat
- term.setCursorPos(2, 4)
- local newName = read()
- ccSettings.name = newName
- until newName ~= ""
- --# Set computer label
- if not os.getComputerLabel() then os.setComputerLabel(ccSettings.name) end
- --# Set server description
- term.clear()
- term.setCursorPos(2, 2)
- term.write("Please type in a short")
- term.setCursorPos(2, 3)
- term.write("server description")
- repeat
- term.setCursorPos(2, 5)
- local newDesc = read()
- ccSettings.note = newDesc
- until newDesc ~= ""
- --# Select color
- local colorWheel = {
- P = "Purple";
- M = "Magenta";
- B = "Blue";
- S = "Sky";
- C = "Cyan";
- E = "Green";
- L = "Lime";
- R = "Red";
- O = "Orange";
- Y = "Yellow";
- N = "Brown";
- K = "Black";
- G = "Gray";
- I = "Silver";
- W = "White";
- }
- term.clear()
- term.setCursorPos(2, 1)
- term.write("Please select the network group")
- term.setCursorPos(2, 2)
- term.write("this server will manage")
- local ttY = 2
- for k, v in pairs(colorWheel) do
- ttY = ttY + 1
- term.setCursorPos(2, ttY)
- term.write(k .. " = " .. v)
- end
- repeat
- term.setCursorPos(30, 2)
- local newColor = string.upper(read())
- ccSettings.color = colorWheel[newColor:sub(1, 1)]
- until colorWheel[newColor:sub(1, 1)]
- --# Should WiRe server get a GPS fix on startup?
- term.clear()
- term.setCursorPos(2, 1)
- term.write("Last question!")
- term.setCursorPos(2, 3)
- term.write("Do you want WiRe server to")
- term.setCursorPos(2, 4)
- term.write("aquire a GPS fix on startup? [y/n]")
- term.setCursorPos(2, 6)
- local getFix = string.lower(read())
- ccSettings.getGPSFix = getFix:sub(1, 1) == "y"
- if not fs.exists("/data") then fs.makeDir("/data") end
- saveData()
- return true
- end
- term.setBackgroundColor(black)
- if pocket or turtle then error("Computer REQUIRED.", 0) end
- if not fs.exists(config) then
- if not firstRun() then return end
- end
- term.clear()
- term.setCursorPos(2, 2)
- term.setTextColor(white)
- term.write("Ingesting configuration data . . .")
- local srvConfig = fs.open(config, "r") or error("initMe(): Cannot open " .. config .. " for reading", 0)
- ccSettings = textutils.unserialize(srvConfig.readAll())
- srvConfig.close()
- if ccSettings.getFix ~= nil or not ccSettings.newColors then
- if ccSettings.getFix ~= nil then
- ccSettings.getGPSFix = ccSettings.getFix
- ccSettings.getFix = nil
- end
- if not ccSettings.newColors then
- if ccSettings.color == "lgray" or ccSettings.color == "Light Gray" then
- ccSettings.color = "Silver"
- elseif ccSettings.color == "lblue" or ccSettings.color == "Light Blue" then
- ccSettings.color = "Sky"
- end
- ccSettings.newColors = true
- end
- saveData()
- end
- term.setCursorPos(2, 4)
- term.write("Configuring hardware . . .")
- for _, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) then
- if peripheral.getType(side) == "monitor" and peripheral.call(side, "isColor") then
- mon = peripheral.wrap(side)
- monSide = side
- elseif peripheral.getType(side) == "modem" then
- if peripheral.call(side, "isWireless") then
- modemCount = modemCount + 1
- modemSides[modemCount] = side
- if not rednet.isOpen(side) then rednet.open(side) end
- else
- for _, name in pairs(peripheral.call(side, "getNamesRemote")) do
- if peripheral.getType(name) == "monitor" and peripheral.call(name, "isColor") then
- mon = peripheral.wrap(name)
- monSide = name
- elseif peripheral.getType(name) == "computer" then
- local modemFound = false
- for i = 1, modemCount do
- if modemSides[i] == side then modemFound = true break end
- end
- if not modemFound then
- modemCount = modemCount + 1
- modemSides[modemCount] = side
- if not rednet.isOpen(side) then rednet.open(side) end
- end
- end
- end
- end
- end
- end
- end
- if modemCount == 0 then return initError("modem", "a modem") end
- if not mon then return initError("monitor", "an Advanced Monitor") end
- mon.setTextScale(0.5)
- monX, monY = mon.getSize()
- clearMon(mwhite)
- mon.setTextColor(mblack)
- mon.setCursorPos(2, 3)
- mon.write("Initializing...")
- term.setCursorPos(2, 6)
- term.write("Hosting services...")
- network = "WiRe" .. ccSettings.color
- rednet.host(network, ccSettings.color)
- if ccSettings.getGPSFix then
- term.setCursorPos(2, 8)
- term.write("Acquiring GPS fix . . .")
- loc.x, loc.y, loc.z = gps.locate(2)
- end
- if not loc.x then
- loc.x, loc.y, loc.z = "No GPS Fix", "No GPS Fix", "No GPS Fix"
- end
- ccSuccess = true
- thisCommand = "init"
- kernelState = true
- if tArgs[1] then
- term.clear()
- else
- termScreenStatic()
- end
- clearMon()
- --# Monitor Header
- local labelText = ccSettings.name .. " [" .. ccSettings.color .. "]"
- local ccNameLen, labelLen, monLabel = #ccSettings.name, #labelText
- if ccNameLen <= monX and labelLen > monX then
- local spacer = (monX - ccNameLen) / 2
- monLabel = string.rep(" ", math.floor(spacer)) .. ccSettings.name .. string.rep(" ", math.ceil(spacer))
- elseif ccNameLen > monX then
- monLabel = ccSettings.name:sub(1, monX)
- else
- local spacer = (monX - labelLen) / 2
- monLabel = string.rep(" ", math.floor(spacer)) .. labelText .. string.rep(" ", math.ceil(spacer))
- end
- mon.setBackgroundColor(colorBurst[ccSettings.color][2] or mgray)
- mon.setTextColor(colorBurst[ccSettings.color][3] or mcyan)
- mon.setCursorPos(1, 1)
- mon.write(monLabel)
- --# Monitor Footer
- local xPos, xPos2 = math.floor(monX / 4), monX > 15 and math.ceil(monX / 2) + 8 or math.ceil(monX / 2) + 2
- mon.setCursorPos(1, monY)
- mon.setBackgroundColor(mgray)
- mon.write(string.rep(" ", monX))
- mon.setTextColor(mred)
- mon.setCursorPos(xPos - 2, monY)
- mon.write("LOCK")
- mon.setTextColor(mgreen)
- mon.setCursorPos(monX > 36 and monX - xPos - 3 or xPos2, monY)
- mon.write("UNLOCK")
- mon.setCursorPos(math.floor(monX / 2) - 1, monY)
- mon.setBackgroundColor(mblack)
- mon.write(" ")
- updateScreens()
- pollTimer = os.startTimer(1)
- if tArgs[1] then
- parallel.waitForAny(netReceive, dataPoller, monTouch, foregroundShell)
- else
- parallel.waitForAny(netReceive, dataPoller, monTouch, userInput)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement