Merge branch 'feature/admin-cli' into dev

This commit is contained in:
Alex Ling 2020-06-01 04:33:27 +00:00
commit 96b8186add
7 changed files with 132 additions and 62 deletions

View File

@ -2,7 +2,7 @@ version: 1.0
shards:
ameba:
github: crystal-ameba/ameba
version: 0.12.0
version: 0.12.1
archive:
github: hkalexling/archive.cr
@ -12,6 +12,10 @@ shards:
github: schovi/baked_file_system
version: 0.9.8
clim:
github: at-grandpa/clim
version: 0.12.0
db:
github: crystal-lang/crystal-db
version: 0.9.0

View File

@ -23,3 +23,5 @@ dependencies:
github: hkalexling/archive.cr
ameba:
github: crystal-ameba/ameba
clim:
github: at-grandpa/clim

View File

@ -45,7 +45,7 @@ end
def with_storage
with_default_config do
temp_db = get_tempfile "mango-test-db"
storage = Storage.new temp_db.path
storage = Storage.new temp_db.path, false
clear = yield storage, temp_db.path
if clear == true
temp_db.delete

View File

@ -2,31 +2,100 @@ require "./config"
require "./server"
require "./mangadex/*"
require "option_parser"
require "clim"
VERSION = "0.4.0"
MANGO_VERSION = "0.4.0"
config_path = nil
macro common_option
option "-c PATH", "--config=PATH", type: String,
desc: "Path to the config file"
end
OptionParser.parse do |parser|
parser.banner = "Mango e-manga server/reader. Version #{VERSION}\n"
macro throw(msg)
puts "ERROR: #{{{msg}}}"
puts
puts "Please see the `--help`."
exit 1
end
parser.on "-v", "--version", "Show version" do
puts "Version #{VERSION}"
exit
end
parser.on "-h", "--help", "Show help" do
puts parser
exit
end
parser.on "-c PATH", "--config=PATH",
"Path to the config file. " \
"Default is `~/.config/mango/config.yml`" do |path|
config_path = path
class CLI < Clim
main do
desc "Mango - Manga Server and Web Reader. Version #{MANGO_VERSION}"
usage "mango [sub_command] [options]"
help short: "-h"
version "Version #{MANGO_VERSION}", short: "-v"
common_option
run do |opts|
Config.load(opts.config).set_current
MangaDex::Downloader.default
server = Server.new
server.start
end
sub "admin" do
desc "Run admin tools"
usage "mango admin [tool]"
help short: "-h"
run do |opts|
puts opts.help_string
end
sub "user" do
desc "User management tool"
usage "mango admin user [arguments] [options]"
help short: "-h"
argument "action", type: String,
desc: "Action to perform. Can be add/delete/update/list"
argument "username", type: String,
desc: "Username to update or delete"
option "-u USERNAME", "--username=USERNAME", type: String,
desc: "Username"
option "-p PASSWORD", "--password=PASSWORD", type: String,
desc: "Password"
option "-a", "--admin", desc: "Admin flag", type: Bool, default: false
common_option
run do |opts, args|
Config.load(opts.config).set_current
storage = Storage.new nil, false
case args.action
when "add"
throw "Options `-u` and `-p` required." if opts.username.nil? ||
opts.password.nil?
storage.new_user opts.username.not_nil!,
opts.password.not_nil!, opts.admin
when "delete"
throw "Argument `username` required." if args.username.nil?
storage.delete_user args.username
when "update"
throw "Argument `username` required." if args.username.nil?
username = opts.username || args.username
password = opts.password || ""
storage.update_user args.username, username.not_nil!,
password.not_nil!, opts.admin
when "list"
users = storage.list_users
name_length = users.map(&.[0].size).max
l_cell_width = ["username".size, name_length].max
r_cell_width = "admin access".size
header = " #{"username".ljust l_cell_width} | admin access "
puts "-" * header.size
puts header
puts "-" * header.size
users.each do |name, admin|
puts " #{name.ljust l_cell_width} | " \
"#{admin.to_s.ljust r_cell_width} "
end
puts "-" * header.size
when nil
puts opts.help_string
else
throw "Unknown action \"#{args.action}\"."
end
end
end
end
end
end
Config.load(config_path).set_current
MangaDex::Downloader.default
server = Server.new
server.start
CLI.start(ARGV)

View File

@ -32,20 +32,6 @@ class AdminRouter < Router
# would not contain `admin`
admin = !env.params.body["admin"]?.nil?
if username.size < 3
raise "Username should contain at least 3 characters"
end
if (username =~ /^[A-Za-z0-9_]+$/).nil?
raise "Username should contain alphanumeric characters " \
"and underscores only"
end
if password.size < 6
raise "Password should contain at least 6 characters"
end
if (password =~ /^[[:ascii:]]+$/).nil?
raise "password should contain ASCII characters only"
end
@context.storage.new_user username, password, admin
redirect env, "/admin/user"
@ -65,23 +51,6 @@ class AdminRouter < Router
admin = !env.params.body["admin"]?.nil?
original_username = env.params.url["original_username"]
if username.size < 3
raise "Username should contain at least 3 characters"
end
if (username =~ /^[A-Za-z0-9_]+$/).nil?
raise "Username should contain alphanumeric characters " \
"and underscores only"
end
if password.size != 0
if password.size < 6
raise "Password should contain at least 6 characters"
end
if (password =~ /^[[:ascii:]]+$/).nil?
raise "password should contain ASCII characters only"
end
end
@context.storage.update_user \
original_username, username, password, admin

View File

@ -22,7 +22,7 @@ class Storage
@@default.not_nil!
end
def initialize(db_path : String? = nil)
def initialize(db_path : String? = nil, init_user = true)
@path = db_path || Config.current.db_path
dir = File.dirname @path
unless Dir.exists? dir
@ -51,12 +51,15 @@ class Storage
Logger.debug "Creating DB file at #{@path}"
db.exec "create unique index username_idx on users (username)"
db.exec "create unique index token_idx on users (token)"
random_pw = random_str
hash = hash_password random_pw
db.exec "insert into users values (?, ?, ?, ?)",
"admin", hash, nil, 1
Logger.log "Initial user created. You can log in with " \
"#{{"username" => "admin", "password" => random_pw}}"
if init_user
random_pw = random_str
hash = hash_password random_pw
db.exec "insert into users values (?, ?, ?, ?)",
"admin", hash, nil, 1
Logger.log "Initial user created. You can log in with " \
"#{{"username" => "admin", "password" => random_pw}}"
end
end
end
end
@ -124,6 +127,8 @@ class Storage
end
def new_user(username, password, admin)
validate_username username
validate_password password
admin = (admin ? 1 : 0)
DB.open "sqlite3://#{@path}" do |db|
hash = hash_password password
@ -134,8 +139,10 @@ class Storage
def update_user(original_username, username, password, admin)
admin = (admin ? 1 : 0)
validate_username username
validate_password password unless password.empty?
DB.open "sqlite3://#{@path}" do |db|
if password.size == 0
if password.empty?
db.exec "update users set username = (?), admin = (?) " \
"where username = (?)",
username, admin, original_username

View File

@ -102,3 +102,22 @@ def redirect(env, path)
base = Config.current.base_url
env.redirect File.join base, path
end
def validate_username(username)
if username.size < 3
raise "Username should contain at least 3 characters"
end
if (username =~ /^[A-Za-z0-9_]+$/).nil?
raise "Username should contain alphanumeric characters " \
"and underscores only"
end
end
def validate_password(password)
if password.size < 6
raise "Password should contain at least 6 characters"
end
if (password =~ /^[[:ascii:]]+$/).nil?
raise "password should contain ASCII characters only"
end
end