diff --git a/dist/ecmo-linux-x64.bin b/dist/ecmo-linux-x64.bin index 9a4efeb..41fb45b 100755 Binary files a/dist/ecmo-linux-x64.bin and b/dist/ecmo-linux-x64.bin differ diff --git a/src/constants.cr b/src/constants.cr index 2b6f49f..db84f60 100644 --- a/src/constants.cr +++ b/src/constants.cr @@ -25,6 +25,9 @@ module App DB_RETENTION = (ENV["DB_RETENTION"]? || 7).to_i + ALLOW_READ = ENV["ALLOW_READ"]? || "" + ALLOW_WRITE = ENV["ALLOW_WRITE"]? || "wheel" + COOKIE_SESSION_KEY = ENV["SESSION_KEY"]? || "_ecmo_" COOKIE_SESSION_SECRET = ENV["SESSION_SECRET"]? || "4f74c0b358d5bab4000dd3c75465dc2c" diff --git a/src/controllers/application.cr b/src/controllers/application.cr index 0668876..a38e5ad 100644 --- a/src/controllers/application.cr +++ b/src/controllers/application.cr @@ -2,6 +2,10 @@ require "uuid" abstract class Application < ActionController::Base + @title : String? + @description : String? + @alert : String? + force_ssl layout "layout.slang" Log = ::App::Log.for("controller") @@ -24,11 +28,39 @@ abstract class Application < ActionController::Base end def require_read - true + @alert = "Read access required" + authorize_groups App::ALLOW_WRITE + " " + App::ALLOW_READ end def require_write - false + @alert = "Write access required" + authorize_groups App::ALLOW_WRITE + end + + def authorize_groups(group_names : String) + user = current_user.not_nil! + route = self.class.name + "#" + action_name.to_s + level = @alert.to_s + granted = group_names.strip + time = Time.utc + perm = "#{level} for #{route} | Groups allowed: #{granted}." + + if (user.groups & granted.split(" ")).empty? + tone :warn + theme :night + + notice "Access denied for user '#{user.name}'" + puts "#{time} | #{user.name} blocked. | #{perm}" + + respond_with do + html template("unauthorized.slang") + end + + else + puts "#{time} | #{user.name} granted. | #{perm}" + + end + end end diff --git a/src/controllers/dashboard.cr b/src/controllers/dashboard.cr index a8a7324..cbcd7cc 100644 --- a/src/controllers/dashboard.cr +++ b/src/controllers/dashboard.cr @@ -1,7 +1,7 @@ class Dashboard < Application - @title : String = "Dashboard" - @description : String = "General System Metrics" + @title = "Dashboard" + @description = "General System Metrics" rescue_from DB::ConnectionRefused, :db_error rescue_from NilAssertionError, :null_error diff --git a/src/controllers/home.cr b/src/controllers/home.cr index 1ca3c40..146286e 100644 --- a/src/controllers/home.cr +++ b/src/controllers/home.cr @@ -1,7 +1,7 @@ class Home < Application - @title : String = App::NAME - @description : String = App::DESC + @title = App::NAME + @description = App::DESC base "/" diff --git a/src/controllers/jobs.cr b/src/controllers/jobs.cr index e4f1ff7..b8d5212 100644 --- a/src/controllers/jobs.cr +++ b/src/controllers/jobs.cr @@ -1,7 +1,7 @@ class Jobs < Application - @title : String = "Jobs" - @description : String = "System Configuration" + @title = "Jobs" + @description = "System Configuration" before_action :set_theme @@ -35,6 +35,11 @@ class Jobs < Application def show job = Job.find(params["id"]).not_nil! + job_report job + end + + def replace + job = Job.find(params["id"]).not_nil! if job.cron == "on-demand" mitamae = App::ROOT + "/bin/mitamae" @@ -65,29 +70,32 @@ class Jobs < Application success: success, job_id: job.id - log = last_run job.id - else - log = last_run job.id + job_report job end - respond_with do - html template("job_report.slang") - json({job: job.to_json, log: log}) - end end private def last_run(job_id) - last = {:output => "", :error => nil, :duration => 0_i64, :success => false} + log = {:output => "", :error => nil, :duration => 0_i64, :success => false} Run.where(job_id: job_id).order(seconds: :desc).each do |run| - last[:output] = run.output - last[:error] = run.error - last[:duration] = run.duration - last[:success] = run.success + log[:output] = run.output + log[:error] = run.error + log[:duration] = run.duration + log[:success] = run.success break end - last + log + end + + private def job_report(job) + log = last_run(job.id) + log[:success] ? (tone :success) : (tone :error) + respond_with do + html template("job_report.slang") + json({job: job.to_json, log: log}) + end end end diff --git a/src/views/jobs.slang b/src/views/jobs.slang index 0844688..5e8a1df 100644 --- a/src/views/jobs.slang +++ b/src/views/jobs.slang @@ -54,9 +54,19 @@ h4 On-Demand Jobs tr th Log level td= job.log.to_s + tr + th Last Run + - if last_run(job.id)[:success] + td + a href=Jobs.show(id:job.id) + ins View Log + - else + td + a href=Jobs.show(id:job.id) + del View Log tr th Run job td - a href=Jobs.show(id:job.id) role="button" Start! + a.btn.solid.black hx-put=Jobs.replace(id:job.id) hx-target="body" Start! br diff --git a/src/views/unauthorized.slang b/src/views/unauthorized.slang new file mode 100644 index 0000000..bcb1b5f --- /dev/null +++ b/src/views/unauthorized.slang @@ -0,0 +1 @@ +h2= @alert diff --git a/vfs/setup/service/ecmo.conf b/vfs/setup/service/ecmo.conf index 94241cb..d480e3e 100644 --- a/vfs/setup/service/ecmo.conf +++ b/vfs/setup/service/ecmo.conf @@ -2,5 +2,7 @@ MODE="production" SERVER_PORT=3000 SERVER_HOST="127.0.0.1" DB_RETENTION=7 -SESSION_KEY="_os_probe_" +SESSION_KEY="_ecmo_" SESSION_SECRET="4f74c0b358d5bab4000dd3c75465dc2c" +ALLOW_READ="" +ALLOW_WRITE="wheel" diff --git a/vfs/setup/service/ecmo.service b/vfs/setup/service/ecmo.service index 1b43fc3..366d480 100644 --- a/vfs/setup/service/ecmo.service +++ b/vfs/setup/service/ecmo.service @@ -4,7 +4,7 @@ After=network.target remote-fs.target [Service] EnvironmentFile=/opt/ecmo/ecmo.conf -PassEnvironment=MODE SERVER_PORT SERVER_HOST DB_RETENTION SESSION_KEY SESSION_SECRET +PassEnvironment=MODE SERVER_PORT SERVER_HOST DB_RETENTION SESSION_KEY SESSION_SECRET ALLOW_READ ALLOW_WRITE ExecStart=/opt/ecmo/bin/ecmo ExecStop=/bin/kill -s TERM $MAINPID User=root diff --git a/vfs/setup/service/ecmo.sh b/vfs/setup/service/ecmo.sh index 4bd8252..f0a9527 100644 --- a/vfs/setup/service/ecmo.sh +++ b/vfs/setup/service/ecmo.sh @@ -8,7 +8,7 @@ output_log="/opt/ecmo/service.log" error_log="/opt/ecmo/error.log" start_pre() { - export MODE SERVER_PORT SERVER_HOST DB_RETENTION SESSION_KEY SESSION_SECRET + export MODE SERVER_PORT SERVER_HOST DB_RETENTION SESSION_KEY SESSION_SECRET ALLOW_READ ALLOW_WRITE } depend() {