mirror of
https://github.com/kepler155c/opus
synced 2025-03-31 20:56:55 +00:00
rttp initial version -- insecure
This commit is contained in:
parent
a17677730f
commit
3dd351cc86
57
sys/apis/fs/redfs.lua
Normal file
57
sys/apis/fs/redfs.lua
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
--[[
|
||||||
|
Mount a readonly file system from another computer across rednet. The
|
||||||
|
target computer must be running OpusOS or redserver.
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
rn://<id>/directory/subdir
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
rn://12/usr/etc
|
||||||
|
rn://8/usr
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local rttp = require('rttp')
|
||||||
|
|
||||||
|
local fs = _G.fs
|
||||||
|
|
||||||
|
local redfs = { }
|
||||||
|
|
||||||
|
local function getListing(uri)
|
||||||
|
local success, response = rttp.get(uri .. '?recursive=true')
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
error(response)
|
||||||
|
end
|
||||||
|
|
||||||
|
if response.statusCode ~= 200 then
|
||||||
|
error('Received response ' .. response.statusCode)
|
||||||
|
end
|
||||||
|
|
||||||
|
local list = { }
|
||||||
|
for _,v in pairs(response.data) do
|
||||||
|
if not v.isDir then
|
||||||
|
list[v.path] = {
|
||||||
|
url = uri .. '/' .. v.path,
|
||||||
|
size = v.size,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
function redfs.mount(dir, uri)
|
||||||
|
if not uri then
|
||||||
|
error('redfs syntax: uri')
|
||||||
|
end
|
||||||
|
|
||||||
|
local list = getListing(uri)
|
||||||
|
for path, entry in pairs(list) do
|
||||||
|
if not fs.exists(fs.combine(dir, path)) then
|
||||||
|
local node = fs.mount(fs.combine(dir, path), 'urlfs', entry.url)
|
||||||
|
node.size = entry.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return redfs
|
@ -1,3 +1,4 @@
|
|||||||
|
local rttp = require('rttp')
|
||||||
local Util = require('util')
|
local Util = require('util')
|
||||||
|
|
||||||
local fs = _G.fs
|
local fs = _G.fs
|
||||||
@ -50,7 +51,12 @@ function urlfs.open(node, fn, fl)
|
|||||||
|
|
||||||
local c = node.cache
|
local c = node.cache
|
||||||
if not c then
|
if not c then
|
||||||
c = Util.httpGet(node.url)
|
if node.url:match('^([%w][%w%+%-%.]*)%:') == 'rn' then
|
||||||
|
local s, response = rttp.get(node.url)
|
||||||
|
c = s and response.statusCode == 200 and response.data
|
||||||
|
else
|
||||||
|
c = Util.httpGet(node.url)
|
||||||
|
end
|
||||||
if c then
|
if c then
|
||||||
node.cache = c
|
node.cache = c
|
||||||
node.size = #c
|
node.size = #c
|
||||||
|
95
sys/apis/rttp.lua
Normal file
95
sys/apis/rttp.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
local device = _G.device
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local rttp = { }
|
||||||
|
local computerId = os.getComputerID()
|
||||||
|
|
||||||
|
local function parse(url, default)
|
||||||
|
-- initialize default parameters
|
||||||
|
local parsed = {}
|
||||||
|
local authority
|
||||||
|
|
||||||
|
for i,v in pairs(default or parsed) do parsed[i] = v end
|
||||||
|
-- remove whitespace
|
||||||
|
-- url = string.gsub(url, "%s", "")
|
||||||
|
-- Decode unreserved characters
|
||||||
|
url = string.gsub(url, "%%(%x%x)", function(hex)
|
||||||
|
local char = string.char(tonumber(hex, 16))
|
||||||
|
if string.match(char, "[a-zA-Z0-9._~-]") then
|
||||||
|
return char
|
||||||
|
end
|
||||||
|
-- Hex encodings that are not unreserved must be preserved.
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
-- get fragment
|
||||||
|
url = string.gsub(url, "#(.*)$", function(f)
|
||||||
|
parsed.fragment = f
|
||||||
|
return ""
|
||||||
|
end)
|
||||||
|
-- get scheme. Lower-case according to RFC 3986 section 3.1.
|
||||||
|
url = string.gsub(url, "^(%w[%w.+-]*):",
|
||||||
|
function(s) parsed.scheme = string.lower(s); return "" end)
|
||||||
|
-- get authority
|
||||||
|
url = string.gsub(url, "^//([^/]*)", function(n)
|
||||||
|
authority = n
|
||||||
|
return ""
|
||||||
|
end)
|
||||||
|
-- get query stringing
|
||||||
|
url = string.gsub(url, "%?(.*)", function(q)
|
||||||
|
parsed.query = q
|
||||||
|
return ""
|
||||||
|
end)
|
||||||
|
-- get params
|
||||||
|
url = string.gsub(url, "%;(.*)", function(p)
|
||||||
|
parsed.params = p
|
||||||
|
return ""
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- path is whatever was left
|
||||||
|
parsed.path = url
|
||||||
|
|
||||||
|
-- Represents host:port, port = nil if not used.
|
||||||
|
if authority then
|
||||||
|
authority = string.gsub(authority, ":(%d+)$",
|
||||||
|
function(p) parsed.port = tonumber(p); return "" end)
|
||||||
|
if authority ~= "" then
|
||||||
|
parsed.host = authority
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return parsed
|
||||||
|
end
|
||||||
|
|
||||||
|
function rttp.get(url)
|
||||||
|
local modem = device.wireless_modem or error('Modem not found')
|
||||||
|
local parsed = parse(url, { port = 80 })
|
||||||
|
|
||||||
|
parsed.host = tonumber(parsed.host) or error('Invalid url')
|
||||||
|
|
||||||
|
for i = 16384, 32767 do
|
||||||
|
if not modem.isOpen(i) then
|
||||||
|
modem.open(i)
|
||||||
|
local path = parsed.query and parsed.path .. '?' .. parsed.query or parsed.path
|
||||||
|
|
||||||
|
modem.transmit(parsed.port, parsed.host, {
|
||||||
|
method = 'GET',
|
||||||
|
replyAddress = computerId,
|
||||||
|
replyPort = i,
|
||||||
|
path = path,
|
||||||
|
})
|
||||||
|
local timerId = os.startTimer(3)
|
||||||
|
repeat
|
||||||
|
local event, id, dport, dhost, response = os.pullEvent()
|
||||||
|
if event == 'modem_message' and
|
||||||
|
dport == i and
|
||||||
|
dhost == computerId and
|
||||||
|
type(response) == 'table' then
|
||||||
|
modem.close(i)
|
||||||
|
return true, response
|
||||||
|
end
|
||||||
|
until event == 'timer' and id == timerId
|
||||||
|
return false, 'timeout'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return rttp
|
@ -2,7 +2,7 @@
|
|||||||
local fs = _G.fs
|
local fs = _G.fs
|
||||||
local http = _G.http
|
local http = _G.http
|
||||||
|
|
||||||
_G.OPUS_BRANCH = 'master-1.8'
|
_G.OPUS_BRANCH = 'develop-1.8'
|
||||||
local GIT_REPO = 'kepler155c/opus/' .. _G.OPUS_BRANCH
|
local GIT_REPO = 'kepler155c/opus/' .. _G.OPUS_BRANCH
|
||||||
local BASE = 'https://raw.githubusercontent.com/' .. GIT_REPO
|
local BASE = 'https://raw.githubusercontent.com/' .. GIT_REPO
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@ function fs.complete(partial, dir, includeFiles, includeSlash)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function fs.listEx(dir)
|
function fs.listEx(dir)
|
||||||
|
dir = fs.combine(dir, '')
|
||||||
local node = getNode(dir)
|
local node = getNode(dir)
|
||||||
if node.fs.listEx then
|
if node.fs.listEx then
|
||||||
return node.fs.listEx(node, dir)
|
return node.fs.listEx(node, dir)
|
||||||
|
@ -252,7 +252,7 @@ local function init(...)
|
|||||||
local files = fs.list(dir)
|
local files = fs.list(dir)
|
||||||
table.sort(files)
|
table.sort(files)
|
||||||
for _,file in ipairs(files) do
|
for _,file in ipairs(files) do
|
||||||
local level = file:match('(%d).%S+.lua')
|
local level = file:match('(%d).%S+.lua') or 99
|
||||||
if tonumber(level) <= runLevel then
|
if tonumber(level) <= runLevel then
|
||||||
local s, m = shell.run(fs.combine(dir, file))
|
local s, m = shell.run(fs.combine(dir, file))
|
||||||
if not s then
|
if not s then
|
||||||
|
109
sys/network/redserver.lua
Normal file
109
sys/network/redserver.lua
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
local Event = require('event')
|
||||||
|
local Util = require('util')
|
||||||
|
|
||||||
|
local fs = _G.fs
|
||||||
|
local modem = _G.device.wireless_modem
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local computerId = os.getComputerID()
|
||||||
|
|
||||||
|
modem.open(80)
|
||||||
|
|
||||||
|
-- https://github.com/golgote/neturl/blob/master/lib/net/url.lua
|
||||||
|
local function parseQuery(str)
|
||||||
|
local sep = '&'
|
||||||
|
|
||||||
|
local values = {}
|
||||||
|
for key,val in str:gmatch(string.format('([^%q=]+)(=*[^%q=]*)', sep, sep)) do
|
||||||
|
--local key = decode(key)
|
||||||
|
local keys = {}
|
||||||
|
key = key:gsub('%[([^%]]*)%]', function(v)
|
||||||
|
-- extract keys between balanced brackets
|
||||||
|
if string.find(v, "^-?%d+$") then
|
||||||
|
v = tonumber(v)
|
||||||
|
--else
|
||||||
|
--v = decode(v)
|
||||||
|
end
|
||||||
|
table.insert(keys, v)
|
||||||
|
return "="
|
||||||
|
end)
|
||||||
|
key = key:gsub('=+.*$', "")
|
||||||
|
key = key:gsub('%s', "_") -- remove spaces in parameter name
|
||||||
|
val = val:gsub('^=+', "")
|
||||||
|
|
||||||
|
if not values[key] then
|
||||||
|
values[key] = {}
|
||||||
|
end
|
||||||
|
if #keys > 0 and type(values[key]) ~= 'table' then
|
||||||
|
values[key] = {}
|
||||||
|
elseif #keys == 0 and type(values[key]) == 'table' then
|
||||||
|
values[key] = val --decode(val)
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = values[key]
|
||||||
|
for i,k in ipairs(keys) do
|
||||||
|
if type(t) ~= 'table' then
|
||||||
|
t = {}
|
||||||
|
end
|
||||||
|
if k == "" then
|
||||||
|
k = #t+1
|
||||||
|
end
|
||||||
|
if not t[k] then
|
||||||
|
t[k] = {}
|
||||||
|
end
|
||||||
|
if i == #keys then
|
||||||
|
t[k] = val --decode(val)
|
||||||
|
end
|
||||||
|
t = t[k]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return values
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getListing(path, recursive)
|
||||||
|
local list = { }
|
||||||
|
local function listing(p)
|
||||||
|
for _, f in pairs(fs.listEx(p)) do
|
||||||
|
local abs = fs.combine(p, f.name)
|
||||||
|
table.insert(list, {
|
||||||
|
isDir = f.isDir,
|
||||||
|
path = string.sub(abs, #path + 1),
|
||||||
|
size = f.size,
|
||||||
|
})
|
||||||
|
if recursive and f.isDir then
|
||||||
|
listing(abs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
listing(path)
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.on('modem_message', function(_, _, dport, dhost, request)
|
||||||
|
if dport == 80 and dhost == computerId and type(request) == 'table' then
|
||||||
|
if request.method == 'GET' then
|
||||||
|
local query
|
||||||
|
local path = request.path:gsub('%?(.*)', function(v)
|
||||||
|
query = parseQuery(v)
|
||||||
|
return ''
|
||||||
|
end)
|
||||||
|
if fs.isDir(path) then
|
||||||
|
modem.transmit(request.replyPort, request.replyAddress, {
|
||||||
|
statusCode = 200,
|
||||||
|
contentType = 'table/directory',
|
||||||
|
data = getListing(path, query and query.recursive == 'true'),
|
||||||
|
})
|
||||||
|
elseif fs.exists(path) then
|
||||||
|
modem.transmit(request.replyPort, request.replyAddress, {
|
||||||
|
statusCode = 200,
|
||||||
|
contentType = 'table/file',
|
||||||
|
data = Util.readFile(path),
|
||||||
|
})
|
||||||
|
else
|
||||||
|
modem.transmit(request.replyPort, request.replyAddress, {
|
||||||
|
statusCode = 404,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
@ -74,7 +74,7 @@ Event.on('timer', function(_, timerId)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
Event.on('modem_message', function(_, _, dport, dhost, msg, distance)
|
Event.on('modem_message', function(_, _, dport, dhost, msg, distance)
|
||||||
if dhost == computerId and msg then
|
if dhost == computerId and type(msg) == 'table' then
|
||||||
local socket = transport.sockets[dport]
|
local socket = transport.sockets[dport]
|
||||||
if socket and socket.connected then
|
if socket and socket.connected then
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user