#!/usr/bin/env lua basepath = (debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])") or "./"):sub(1,-2) local entryBackups = {} local function makeEntryBackup(id) if entryBackups[id] ~= nil then return end env.run({"entry_backup",id}) entryBackups[id] = true end local function eprint(text) io.stderr:write(text .. "\n") end local function input(text) if text == nil then text = "" end io.stderr:write(text) return io.read() end local function yn(question) io.stderr:write(question .. " - y/n: ") local inp = false while true do inp = string.lower(input()) if ( inp == "y" or inp == "n" ) then break end end return (inp == "y") end local function menu(choices) for i,v in ipairs(choices) do eprint(tostring(i).. ": " ..tostring(v)) end local choice = false while true do choice = tonumber(input("Choice: ")) if not ( choice == nil or choice < 1 or choice > #choices or math.floor(choice) ~= choice ) then break end end return choice end local function emenu(title,choices,functions,lastSelection) if lastSelection == nil then lastSelection = "<- BACK" end table.insert(choices,lastSelection) while true do eprint(title) local i = menu(choices) if i == #choices then return end eprint("") functions[i]() eprint("") end end local function printPassword(entry) print(env.run({"field_get",entry.attrs.id,"password"})) end local function fieldPrint(entry,field) print(env.run({"field_get",entry.attrs.id,field.attrs.name})) end local function fieldPrintType(entry,field) print(env.run({"field_get_type",entry.attrs.id,field.attrs.name})) end local function fieldSetText(entry,field) local text = input("Text: ") makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,field.attrs.name,text}) env.run({"save"}) end local function fieldSetType(entry,field) local tp = input("Type: ") makeEntryBackup(entry.attrs.id) env.run({"field_set_type",entry.attrs.id,field.attrs.name,tp}) env.run({"save"}) end local function fieldRemove(entry,field) if not yn("Do you want to remove the field '" ..field.attrs.name.. "'?") then return end makeEntryBackup(entry.attrs.id) env.run({"field_remove",entry.attrs.id,field.attrs.name}) env.run({"save"}) end local function fieldImportFile(entry,field) local fpath = input("File path: ") local fh = io.open(fpath,"r") if fh == nil then eprint("Error opening file, make sure to remove any \" or '.") return end local bytes = fh:read("*a") fh:close() local base64 = require("base64") bytes = base64.encode(bytes) makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,field.attrs.name,bytes}) bytes = nil collectgarbage("collect") env.run({"save"}) end local function fieldExportFile(entry,field) local fpath = input("File path: ") local fh = io.open(fpath,"r") if fh ~= nil then fh:close() eprint("Error: file already exists.") return end fh = io.open(fpath,"w") if fh == nil then eprint("Error opening file, make sure to remove any \" or '.") return end local bytes = env.run({"field_get",entry.attrs.id,field.attrs.name}) local base64 = require("base64") bytes = base64.decode(bytes) fh:write(bytes) fh:close() bytes = nil collectgarbage("collect") end local function fieldActions(entry,field) emenu( "Field '" ..field.attrs.name.. "':", { "Print value + exit", "Print value", "Print type", "Set value", "Set type", "Import file", "Export file", "Rename", "Remove" }, { function() fieldPrint(entry,field); os.exit(0) end, function() fieldPrint(entry,field) end, function() fieldPrintType(entry,field) end, function() fieldSetText(entry,field) end, function() fieldSetType(entry,field) end, function() fieldImportFile(entry,field) end, function() fieldExportFile(entry,field) end, function() fieldRename(entry,field) end, --todo (needs prpw impl) function() fieldRemove(entry,field) end } ) end local function fieldsActions(entry) local fields = env.run({"field_list",entry.attrs.id}) local funcs = {} for i,field in pairs(fields) do fields[i] = field.attrs.name; table.insert(funcs,function() fieldActions(entry,field) end) end emenu("Fields:",fields,funcs) end local function fieldAdd(entry) local fieldName = input("Field name: ") makeEntryBackup(entry.attrs.id) env.run({"field_set",entry.attrs.id,fieldName,""}) env.run({"save"}) end local function manageEntry(entry) emenu( "Entry - " ..entry.attrs.name.. ":", { "Print password + exit", "Field add", "Fields", "Entry rename", "Entry remove" }, { function() printPassword(entry); os.exit(0) end, function() fieldAdd(entry) end, function() fieldsActions(entry) end, function() entryRename(entry) end, --todo (needs prpw impl) function() entryRemove(entry) end --todo } ) end local function searchByName() local entries = {} local entriesMenu = {} local name = string.lower(input("Name: ")) for i,entry in pairs(env.xmlFindTags(env.db,"entries")[1].children) do if string.find(string.lower(entry.attrs.name),name) ~= nil then table.insert(entries,function() manageEntry(entry) end) table.insert(entriesMenu,entry.attrs.name) end end emenu("Found entries:",entriesMenu,entries) end local function main(arg) package.path = basepath .. "/lib/?.lua;" .. basepath .. "/lib/?/main.lua;" .. package.path require("prpw") env.cli = false env.run({"open",arg[1]}) emenu( "Search entry by ...", { "Name", "All non-secret field contents", "Field content", "List all" }, { searchByName, searchByFields, -- todo searchByField, -- todo listAll -- todo }, "<- EXIT" ) end main(arg)