-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLAuth.lua
89 lines (74 loc) · 2.27 KB
/
LAuth.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package.path = arg[0]:gsub("(.-[\\/]?)[%w_.]+(%.luac?)$", "%1?%2;") .. package.path
package.cpath = arg[0]:gsub("(.-[\\/]?)[%w_.]+(%.luac?)$", "%1?.dll;") .. package.cpath
require 'rfc6238'
local pp = require 'pl.pretty'
local lapp = require 'pl.lapp'
local args = lapp
[[
LAuth - A simple CLI app for two-factor authentication.
Usage: LAuth <action> arguments...
Actions:
-a, --add <name> <secret token> Add a new 2FA base32-encoded HOTP token
-r, --remove <name> Remove an existing token
--show [search pattern] Show OTP of all tokens in account
options:
-f, --file (default account.lua) Filename of the account storage
]]
local basepath = function(filepath)
return filepath:match "(.+[\\/])[%w._]+"
end
local check_args = function(args)
local action_count = 0
local action
for k, v in pairs(args) do
if v == true then
action_count = action_count + 1
action = k
end
end
lapp.assert(action_count == 1, "Please specify exactly one action.")
args.action = action
local account_path = basepath(args.file)
if not account_path then
local LAuthpath = basepath(arg[0]) or ""
args.file = LAuthpath .. args.file
end
end
local account =
{
load = function(filename)
local infile = io.open(filename, 'r')
return not infile
and {}
or pp.read(infile:read '*a')
end,
save = pp.dump,
}
local handlers =
{
show = function (accounts, args)
local strfmt = " %-32s - %s"
local searchpat = args[1] or ".*"
print "OTP:"
for account, secret in pairs(accounts) do
if account:match(searchpat) then
print(strfmt:format(account, TOTP_base32(secret)))
end
end
end,
add = function (accounts, args)
local name, secret = args[1], args[2]
lapp.assert(name and secret, "LAuth add <name> <secret token>")
accounts[name] = secret
end,
remove = function (accounts, args)
local name = args[1]
lapp.assert(name, "LAuth remove <name>")
accounts[name] = nil
end,
}
check_args(args)
local accounts = account.load(args.file)
assert(accounts, "Could not load " .. args.file)
handlers[args.action](accounts, args)
account.save(accounts, args.file)