From a77d55e33f3bd6c5564c7472ad4809f8d4233866 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 12 Apr 2019 08:33:41 -0400 Subject: [PATCH] pastebin rework round 3 --- sys/apis/http/pastebin.lua | 222 +++++++++++++++++-------------------- sys/apps/pastebin.lua | 55 ++++++--- sys/help/pastebin | 15 +++ 3 files changed, 157 insertions(+), 135 deletions(-) create mode 100644 sys/help/pastebin diff --git a/sys/apis/http/pastebin.lua b/sys/apis/http/pastebin.lua index 54f5b24..343a7db 100644 --- a/sys/apis/http/pastebin.lua +++ b/sys/apis/http/pastebin.lua @@ -1,150 +1,128 @@ +--- Parse the pastebin code from the given code or URL +local function parseCode(paste) + local patterns = { + "^([%a%d]+)$", + "^https?://pastebin.com/([%a%d]+)$", + "^pastebin.com/([%a%d]+)$", + "^https?://pastebin.com/raw/([%a%d]+)$", + "^pastebin.com/raw/([%a%d]+)$", + } ---- Attempts to guess the pastebin ID from the given code or URL -local function extractId(paste) - local patterns = { - "^([%a%d]+)$", - "^https?://pastebin.com/([%a%d]+)$", - "^pastebin.com/([%a%d]+)$", - "^https?://pastebin.com/raw/([%a%d]+)$", - "^pastebin.com/raw/([%a%d]+)$", - } + for i = 1, #patterns do + local code = paste:match(patterns[i]) + if code then + return code + end + end - for i = 1, #patterns do - local code = paste:match( patterns[i] ) - if code then return code end - end - - return nil + return nil end -function download(url) - if type( url ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( url ) .. ")", 2 ) - end +-- Download the contents of a paste +local function download(url) + if type(url) ~= "string" then + error("bad argument #1 (expected string, got " .. type(url) .. ")", 2) + end - if not http then - return false, "Pastebin requires http API" - end + if not http then + return false, "Pastebin requires http API" + end - local paste = extractId( url ) - if not paste then - return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." - end + -- Add a cache buster so that spam protection is re-checked + local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) + local response, err = http.get( + "https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster + ) - -- Add a cache buster so that spam protection is re-checked - local cacheBuster = ("%x"):format(math.random(0, 2^30)) - local response, err = http.get( - "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster - ) + if not response then + return response, err + end - if not response then - return response, err - end + -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html + local headers = response.getResponseHeaders() + if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then + return false, "Pastebin blocked due to spam protection" + end - -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html - local headers = response.getResponseHeaders() - if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then - return false, "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) - end - - local sResponse = response.readAll() - response.close() - return sResponse + local contents = response.readAll() + response.close() + return contents end -local function put(sPath) - if type( sPath ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 ) - end +-- Upload text to pastebin +local function upload(name, text) + if not http then + return false, "Pastebin requires http API" + end - if not http then - return false, "Pastebin requires http API" - end + -- POST the contents to pastebin + local key = "0ec2eb25b6166c0c27a394ae118ad829" + local response = http.post( + "https://pastebin.com/api/api_post.php", + "api_option=paste&" .. + "api_dev_key=" .. key .. "&" .. + "api_paste_format=lua&" .. + "api_paste_name=" .. textutils.urlEncode(name) .. "&" .. + "api_paste_code=" .. textutils.urlEncode(text) + ) - -- Upload a file to pastebin.com - -- Determine file to upload - if not fs.exists( sPath ) or fs.isDir( sPath ) then - return false, "No such file" - end + if not response then + return false, "Failed." + end - -- Read in the file - local sName = fs.getName( sPath ) - local file = fs.open( sPath, "r" ) - local sText = file.readAll() - file.close() + local contents = response.readAll() + response.close() - -- POST the contents to pastebin - local key = "0ec2eb25b6166c0c27a394ae118ad829" - local response = http.post( - "https://pastebin.com/api/api_post.php", - "api_option=paste&".. - "api_dev_key="..key.."&".. - "api_paste_format=lua&".. - "api_paste_name="..textutils.urlEncode(sName).."&".. - "api_paste_code="..textutils.urlEncode(sText) - ) - - if response then - local sResponse = response.readAll() - response.close() - - return string.match( sResponse, "[^/]+$" ) - end - return false, "Failed." + return string.match(contents, "[^/]+$") end -local function get(sCode, sPath) - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end +-- Download the contents to a file from pastebin +local function get(code, path) + if type(code) ~= "string" then + error( "bad argument #1 (expected string, got " .. type(code) .. ")", 2) + end - if type( sPath ) ~= "string" then - error( "bad argument #2 (expected string, got " .. type( sPath ) .. ")", 2 ) - end + if type(path) ~= "string" then + error("bad argument #2 (expected string, got " .. type(path) .. ")", 2) + end - if not http then - return false, "Pastebin requires http API" - end + local res, msg = download(code) + if not res then + return res, msg + end - if fs.exists( sPath ) then - return false, "File already exists" - end + local file = fs.open(path, "w") + file.write(res) + file.close() - -- GET the contents from pastebin - local res, msg = download(sCode) - if not res then - return res, msg - end - - local file = fs.open( sPath, "w" ) - file.write( res ) - file.close() - - return sPath + return true end -local function run(sCode, ...) - if not http then - return false, "Pastebin requires http API" - end +-- Upload a file to pastebin.com +local function put(path) + if type(path) ~= "string" then + error("bad argument #1 (expected string, got " .. type(path) .. ")", 2) + end - if type( sCode ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( sCode ) .. ")", 2 ) - end + -- Determine file to upload + if not fs.exists(path) or fs.isDir(path) then + return false, "No such file" + end - local res, msg = download(sCode) - if not res then - return res, msg - end - local func, err = load(res, sCode, "t", _ENV) - if not func then - return func, err - end - return pcall(func, ...) + -- Read in the file + local name = fs.getName(path) + local file = fs.open(path, "r") + local text = file.readAll() + file.close() + + return upload(name, text) end return { - get = get, - put = put, - run = run, -} \ No newline at end of file + download = download, + upload = upload, + get = get, + put = put, + parseCode = parseCode, +} + diff --git a/sys/apps/pastebin.lua b/sys/apps/pastebin.lua index 6c4df9e..d2ee048 100644 --- a/sys/apps/pastebin.lua +++ b/sys/apps/pastebin.lua @@ -1,4 +1,3 @@ - local function printUsage() print( "Usages:" ) print( "pastebin put " ) @@ -6,12 +5,6 @@ local function printUsage() print( "pastebin run " ) end -local tArgs = { ... } -if #tArgs < 2 then - printUsage() - return -end - if not http then printError( "Pastebin requires http API" ) printError( "Set http_enable to true in ComputerCraft.cfg" ) @@ -20,9 +13,17 @@ end local pastebin = require('http.pastebin') +local tArgs = { ... } local sCommand = tArgs[1] + if sCommand == "put" then -- Upload a file to pastebin.com + + if #tArgs < 2 then + printUsage() + return + end + -- Determine file to upload local sFile = tArgs[2] local sPath = shell.resolve( sFile ) @@ -45,15 +46,18 @@ if sCommand == "put" then elseif sCommand == "get" then -- Download a file from pastebin.com + if #tArgs < 3 then printUsage() return end - print( "Connecting to pastebin.com... " ) + local sCode = pastebin.parseCode(tArgs[2]) + if not sCode then + return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." + end -- Determine file to download - local sCode = tArgs[2] local sFile = tArgs[3] local sPath = shell.resolve( sFile ) if fs.exists( sPath ) then @@ -61,21 +65,45 @@ elseif sCommand == "get" then return end + print( "Connecting to pastebin.com... " ) + local resp, msg = pastebin.get(sCode, sPath) if resp then - print( "Downloaded as "..resp ) + print( "Downloaded as " .. sPath ) else printError( msg ) end elseif sCommand == "run" then - local sCode = tArgs[2] + -- Download and run a file from pastebin.com + + if #tArgs < 2 then + printUsage() + return + end + + local sCode = pastebin.parseCode(tArgs[2]) + if not sCode then + return false, "Invalid pastebin code. The code is the ID at the end of the pastebin.com URL." + end print( "Connecting to pastebin.com... " ) - local resp, msg = pastebin.run(sCode, table.unpack(tArgs, 3)) - if not resp then + local res, msg = pastebin.download(sCode) + if not res then + printError( msg ) + return res, msg + end + + res, msg = load(res, sCode, "t", _ENV) + if not res then + printError( msg ) + return res, msg + end + + res, msg = pcall(res, table.unpack(tArgs, 3)) + if not res then printError( msg ) end else @@ -83,3 +111,4 @@ else printUsage() return end + diff --git a/sys/help/pastebin b/sys/help/pastebin new file mode 100644 index 0000000..57e4d0a --- /dev/null +++ b/sys/help/pastebin @@ -0,0 +1,15 @@ +pastebin is a program for uploading files to and downloading files from pastebin.com. This is useful for sharing programs with other players. +The HTTP API must be enabled in ComputerCraft.cfg to use this program. + +ex: +"pastebin put foo" will upload the file "foo" to pastebin.com, and print the URL. +"pastebin get xq5gc7LB foo" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as "foo". +"pastebin run CxaWmPrX" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it. + +Functions in the pastebin API: +pastebin.get( code, filepath ) +pastebin.put( filepath ) +pastebin.download( code ) +pastebin.upload( pastename, text ) +pastebin.parseCode( code ) +