main.lua (3665B)
1 local lfs = require( "lfs" ) 2 local symmetric = require( "symmetric" ) 3 4 local actions = require( "actions" ) 5 local paths = require( "paths" ) 6 7 function io.readfile( path ) 8 local file, err = io.open( path, "r" ) 9 if not file then 10 return nil, err 11 end 12 13 local contents, err = file:read( "*all" ) 14 file:close() 15 return contents, err 16 end 17 18 function io.writefile( path, contents ) 19 local file, err = io.open( path, "w" ) 20 if not file then 21 return nil, err 22 end 23 24 local ok, err = file:write( contents ) 25 if not ok then 26 file:close() 27 return nil, err 28 end 29 30 local ok, err = file:close() 31 if not ok then 32 return nil, err 33 end 34 35 return true 36 end 37 38 table.unpack = table.unpack or unpack 39 40 local default_length = 32 41 local default_pattern = "[%w%p ]" 42 43 local function eprintf( form, ... ) 44 io.stderr:write( form:format( ... ) .. "\n" ) 45 end 46 47 local help = 48 "Usage: " .. arg[ 0 ] .. " <command>\n" 49 .. "where <command> is one of the following:\n" 50 .. "\n" 51 .. "init - generate a new key\n" 52 .. "add <name> - prompt you to enter a password for <name>\n" 53 .. "get <name> - print the password stored under <name>\n" 54 .. "delete <name> - delete the password stored under <name>\n" 55 .. "list - list stored passwords\n" 56 .. "gen <name> [length] [pattern] - generate a password for <name>\n" 57 .. "[pattern] is a Lua pattern. Some examples:\n" 58 .. " gen test - 32 characters, alphanumeric/puntuation/spaces\n" 59 .. " gen test 16 - 16 characters, alphanumeric/puntuation/spaces\n" 60 .. " gen test 10 %d - 10 characters, numbers only\n" 61 .. " gen test \"%l \" - 32 characters, lowercase/spaces" 62 63 local function load_key() 64 local key, err = io.readfile( paths.key ) 65 if not key then 66 eprintf( "Unable to read key file: %s", err ) 67 eprintf( "You might need to generate one with `pdb init`." ) 68 return os.exit( 1 ) 69 end 70 71 return key 72 end 73 74 local function write_new_key() 75 local key = symmetric.key() 76 return io.writefile( paths.key, key ) 77 end 78 79 local commands = { 80 add = { 81 args = 1, 82 syntax = "<name>", 83 }, 84 get = { 85 args = 1, 86 }, 87 delete = { 88 args = 1, 89 syntax = "<name>", 90 }, 91 list = { 92 args = 0, 93 }, 94 gen = { 95 args = 3, 96 syntax = "<name> [length] [pattern]", 97 }, 98 } 99 100 local cmd = arg[ 1 ] 101 table.remove( arg, 1 ) 102 103 if not cmd then 104 print( help ) 105 106 return os.exit( 0 ) 107 end 108 109 if cmd == "init" then 110 if io.open( paths.key, "r" ) then 111 eprintf( "Your key file already exists. Remove it and run init again if you're sure about this." ) 112 return os.exit( 1 ) 113 end 114 115 lfs.mkdir( paths.path ) 116 lfs.mkdir( paths.db ) 117 118 local ok, err = write_new_key() 119 if not ok then 120 eprintf( "Unable to write key file: %s", err ) 121 return os.exit( 1 ) 122 end 123 124 print( "You should chmod 600 " .. paths.key ) 125 126 return os.exit( 0 ) 127 end 128 129 local key = load_key() 130 131 if cmd == "gen" and #arg > 0 then 132 local length 133 local pattern 134 135 if #arg == 1 then 136 length = default_length 137 pattern = default_pattern 138 elseif #arg == 3 then 139 length = tonumber( arg[ 2 ] ) 140 pattern = "[" .. arg[ 3 ] .. "]" 141 else 142 length = tonumber( arg[ 2 ] ) or default_length 143 pattern = tonumber( arg[ 2 ] ) and default_pattern or arg[ 2 ] 144 end 145 146 arg[ 2 ] = length 147 arg[ 3 ] = pattern 148 end 149 150 if not actions[ cmd ] then 151 eprintf( "%s", help ) 152 return os.exit( 1 ) 153 end 154 155 if commands[ cmd ].args > 0 then 156 if arg[ 1 ]:find( "/" ) then 157 eprintf( "Password name can't contain slashes." ) 158 return os.exit( 1 ) 159 end 160 161 arg[ 1 ] = paths.db .. arg[ 1 ] 162 end 163 164 if commands[ cmd ].args ~= #arg then 165 eprintf( "Usage: %s %s %s", arg[ 0 ], cmd, commands[ cmd ].syntax or "" ) 166 return os.exit( 1 ) 167 end 168 169 local err = actions[ cmd ]( key, table.unpack( arg ) ) 170 171 if err then 172 eprintf( "%s", err ) 173 return os.exit( 1 ) 174 end