|
local API_REQUEST_TOKEN_URL="https://api.dropbox.com/1/oauth/request_token" |
|
local API_USER_AUTH_URL="https://www.dropbox.com/1/oauth/authorize" |
|
local API_ACCESS_TOKEN_URL="https://api.dropbox.com/1/oauth/access_token" |
|
|
|
local API_UPLOAD_URL="https://api-content.dropbox.com/1/files_put/auto/" |
|
local API_DOWNLOAD_URL="https://api-content.dropbox.com/1/files/auto" |
|
local API_DELETE_URL="https://api.dropbox.com/1/fileops/delete" |
|
local API_MOVE_URL="https://api.dropbox.com/1/fileops/move" |
|
local API_COPY_URL="https://api.dropbox.com/1/fileops/copy" |
|
local API_METADATA_URL="https://api.dropbox.com/1/metadata/auto/" |
|
local API_MKDIR_URL="https://api.dropbox.com/1/fileops/create_folder" |
|
local APP_CREATE_URL="https://www.dropbox.com/developers/apps" |
|
|
|
--- Generate random numbers (9 characters long) |
|
local random = math.random |
|
local function nonce() |
|
local rnd = "" |
|
for i=0,9,1 do rnd = rnd..random(0,9) end |
|
return rnd |
|
end |
|
|
|
if not http then error("Cannot access HTTP") end |
|
if not json then |
|
if not fs.exists("json") then shell.run("pastebin get 4nRg9CHU json") end |
|
os.loadAPI("json") |
|
end |
|
local jsonDecode = json.decode |
|
|
|
function create(config) |
|
--- Generate default OAuth url parameters |
|
local function oauth() |
|
return "oauth_consumer_key="..config.app_key.. |
|
"&oauth_token="..config.token.. |
|
"&oauth_signature_method=PLAINTEXT&oauth_signature="..config.app_secret.."%26"..config.token_secret.. |
|
"&oauth_timestamp=".."0".."&oauth_nonce"..nonce() |
|
end |
|
|
|
--- Gets various metadata for a file/directory |
|
-- https://www.dropbox.com/developers/core/docs#metadata |
|
local function getMetadata(src) |
|
local url = API_METADATA_URL..textutils.urlEncode(src)..'?'..oauth() |
|
local response = http.get(url) |
|
if not response then return nil end |
|
|
|
if response.getResponseCode() ~= 200 then |
|
response.close() |
|
return nil |
|
end |
|
|
|
local content=jsonDecode(response.readAll()) |
|
response.close() |
|
return content |
|
end |
|
|
|
local function makeDirectory(destination) |
|
local url = API_MKDIR_URL..'?'..oauth()..'&root=auto&path='..textutils.urlEncode(destination) |
|
local response = http.get(url) |
|
if response then response.close() end |
|
end |
|
|
|
local function isDir(file) |
|
local meta = getMetadata(file) |
|
return meta and meta.is_dir |
|
end |
|
|
|
local function list(destination, expanded) |
|
local meta = getMetadata(destination) |
|
|
|
if not meta then error("Not a directory", 2) end |
|
if not meta.contents then error("API error", 2) end |
|
|
|
if expanded then return meta.contents end |
|
|
|
local result = {} |
|
for _,file in pairs(meta.contents) do |
|
result[#result + 1] = fs.getName(file.path) |
|
end |
|
|
|
return result |
|
end |
|
|
|
local function copy(src, destination) |
|
--If destination is directory then copy into directory |
|
local meta = getMetadata(destination) |
|
if not meta then error("No such file", 2) end |
|
|
|
if meta.is_dir then |
|
destination = destination..'/'..fs.getName(src) |
|
end |
|
|
|
local url = API_COPY_URL .. '?'..oauth()..'&root=auto&from_path='..textutils.urlEncode(src)..'&to_path='..destination |
|
local response = http.get(url) |
|
|
|
if not response then error("API error", 2) end |
|
if response.getResponseCode() ~= 200 then |
|
response.close() |
|
error("No such file", 2) |
|
end |
|
|
|
response.close() |
|
end |
|
|
|
local function move(src, destination) |
|
--If destination is directory then copy into directory |
|
local meta = getMetadata(destination) |
|
if not meta then error("No such file", 2) end |
|
|
|
if meta.is_dir then |
|
destination = destination..'/'..fs.getName(src) |
|
end |
|
|
|
local url=API_MOVE_URL..'?'..oauth()..'&root=auto&from_path='..textutils.urlEncode(src)..'&to_path='..destination |
|
local response = http.get(url) |
|
|
|
if not response then error("API error", 2) end |
|
if response.getResponseCode() ~= 200 then |
|
response.close() |
|
error("No such file", 2) |
|
end |
|
|
|
response.close() |
|
end |
|
|
|
local function delete(src) |
|
local url = API_DELETE_URL..'?'..oauth()..'&root=auto&path='..textutils.urlEncode(src) |
|
local response = http.get(url) |
|
|
|
if response then response.close() end |
|
end |
|
|
|
local function open(file, mode) |
|
if mode:find("b") then error("Binary mode not supported", 2) end |
|
if mode == "w" then |
|
local buffer = {} |
|
local size = 0 |
|
|
|
local function serialize(contents) |
|
local t = type(contents) |
|
if t == "string" then return contents end |
|
if t == "number" or t == "boolean" then return tostring(t) end |
|
|
|
-- Technically not accurate. |
|
if t == "table" then return textutils.serialize(contents) end |
|
|
|
return "" |
|
end |
|
|
|
local function write(contents) |
|
contents = serialize(contents) |
|
buffer[#buffer + 1] = contents |
|
size = size + #contents |
|
end |
|
|
|
return { |
|
write = write, |
|
writeLine = function(contents) |
|
write(contents) |
|
write("\n") |
|
end, |
|
close = function() |
|
local url=API_UPLOAD_URL..textutils.urlEncode(file)..'?'..oauth() -- "http://httpbin.org/post" -- |
|
local response = http.post(url, table.concat(buffer, ""), { |
|
["Content-Length"] = size, |
|
["Content-Type"] = "application/octet-stream", |
|
}) |
|
if response then |
|
response.close() |
|
end |
|
|
|
return response ~= nil |
|
end, |
|
} |
|
elseif mode == "r" then |
|
local url = API_DOWNLOAD_URL..textutils.urlEncode(file)..'?'..oauth() |
|
local response = http.get(url) |
|
|
|
if response and response.getResponseCode() then |
|
return { |
|
readLine = response.readLine, |
|
readAll = response.readAll, |
|
close = response.close |
|
} |
|
end |
|
else |
|
error("Unsupported mode", 2) |
|
end |
|
end |
|
|
|
return { |
|
open = open, |
|
move = move, |
|
list = list, |
|
copy = copy, |
|
delete = delete, |
|
makeDir = makeDirectory, |
|
isDir = isDir, |
|
|
|
getMetadata = getMetadata, |
|
} |
|
end |
|
|
|
--- Request a token |
|
-- @tparam table config Table composed of app_key and app_secret |
|
-- @treturn table Table composed of the token, secret and url required to authorise |
|
function requestToken(config) |
|
local url = API_REQUEST_TOKEN_URL.."?oauth_consumer_key="..config.app_key.."&oauth_signature_method=PLAINTEXT&oauth_signature="..config.app_secret.."%26".."&oauth_timestamp=".."0".."&oauth_nonce"..nonce() |
|
|
|
local response = http.get(url) |
|
if not response then return end |
|
|
|
local result_content = response.readAll() |
|
response.close() |
|
|
|
local token = string.match(result_content, "oauth_token=\([a-z A-Z 0-9]*\)") |
|
local secret = string.match(result_content, "oauth_token_secret=\([a-z A-Z 0-9]*\)") |
|
|
|
if not token or not secret then return end |
|
|
|
return { |
|
secret = secret, |
|
token = token, |
|
url = API_USER_AUTH_URL..'?oauth_token='..token |
|
} |
|
end |
|
|
|
--- Authorise a token |
|
-- @tparam table config Table composed of app_key and app_secret |
|
-- @tparam table tokens The result of requestToken |
|
function accessToken(config, tokens) |
|
local url=API_ACCESS_TOKEN_URL.."?oauth_consumer_key="..config.app_key.. |
|
"&oauth_token="..tokens.token.. |
|
"&oauth_signature_method=PLAINTEXT&oauth_signature="..config.app_secret.."%26"..token.secret.. |
|
"&oauth_timestamp=0&oauth_nonce="..nonce() |
|
|
|
local response=http.get(url) |
|
if not respose then return end |
|
|
|
local result_content=response.readAll() |
|
response.close() |
|
|
|
local secret = string.match(result_content, "oauth_token_secret=\([a-z A-Z 0-9]*\)") |
|
local token = string.match(result_content, "oauth_token=\([a-z A-Z 0-9]*\)") |
|
|
|
if not token or not secret then return end |
|
|
|
return { |
|
app_key = config.app_key, |
|
app_secret = config.app_secret, |
|
token = token, |
|
token_secret = secret, |
|
} |
|
end |