Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

225 lines (199 sloc) 6.568 kB
module Shellular
# Try to load bundler
begin
require "rubygems"
require "bundler"
gemfile = File.join( File.dirname(Pathname(__FILE__).expand_path), "Gemfile" )
ENV["BUNDLE_GEMFILE"] ||= gemfile
Bundler.setup
end
require "rails_config"
require "httparty"
require "cgi"
require "json"
require "uri"
# Setup configuration
config = File.join( File.dirname(Pathname(__FILE__).expand_path), "config/", "settings.yml")
RailsConfig.setup do |conf|
conf.const_name = "Settings"
end
RailsConfig.load_and_set_settings(config)
class Plug
include HTTParty
default_timeout 10
end
class Command
attr_accessor :user, :command, :kind, :cmd, :opts, :opts_user, :opts_repo, :key_bits, :rights
def initialize(user, command, key_bits)
@user = user
@command = command
@kind = nil # :git / :hg
@cmd = nil # git or hg command
@opts = nil # "user/repos.git"
@mode = nil # :read / :write
@opts_user = nil # user from @opts
@opts_repo = nil # repo from @opts
@key_bits = key_bits # the key without start and user@host
@rights = nil # :r or :w (:w includes :r)
end
def shlog(msg)
File.open(Settings.log, "a") do |log|
log.puts Time.now.strftime("%d/%m/%y %H:%M ") + msg
end
end
def git?
@kind == :git ? true : false
end
def hg?
@kind == :hg ? true : false
end
def valid?
if !(@command =~ /\n/) && (@command =~ /^git/)
read_commands = ["git-upload-pack", "git upload-pack"]
write_commands = ["git-receive-pack", "git receive-pack"]
@kind = :git
sh_command = @command.split(" ")
if sh_command.size == 3
# git foo "repo"
@cmd = sh_command[0] + " " + sh_command[1]
@opts = sh_command[2]
elsif sh_command.size == 2
@cmd = sh_command[0]
@opts = sh_command[1]
# git-foo "repo"
else
# Bad command
return false
end
# check if it's a read or write
if read_commands.include? @cmd
@mode = :read
shlog("INFO: Validated read command")
return true
elsif write_commands.include? @cmd
@mode = :write
shlog("INFO: Validated write command")
return true
else
return false
end
return false
elsif !(@command =~ /\n/) && (@command =~ /^git/)
@kind = :hg
# TODO FIXME
shlog("INFO: HG read or write currently not implemented.")
return false
else
return false
end
false
end
# Extract user and repository name from command opts
def extract_user_and_repo!
if self.git?
# /'(\w+)\/(\w+)\.git'/
bits = @command.match /'(\w+)\/(\w+)\.git'/
if !bits
shlog("ERROR: The path doesn't match a git repository !")
STDERR.puts "The git remote path doesn't seems to be right: #{@opts}, can't continue."
return false
end
if bits.size < 3
shlog("ERROR: Invalid: #{@opts}")
return false
end
@opts_user = bits[1]
@opts_repo = bits[2]
return true
elsif self.hg?
# nothing right now
else
return false
end
end
def check_permissions!
options = {
:password => CGI::escape(Settings.backend.pass),
:user => CGI::escape(@user),
:command => CGI::escape(@command),
:kind => CGI::escape(@kind.to_s),
:cmd => CGI::escape(@cmd),
:opts => CGI::escape(@opts),
:mode => CGI::escape(@mode.to_s),
:opts_user => CGI::escape(@opts_user),
:opts_repo => CGI::escape(@opts_repo),
:key_bits => CGI::escape(@key_bits)
}
req = Plug.post(URI::join(Settings.backend.url, "/users/permissions/check").to_s, :body => options)
if !req or !req.body
exit 1
end
body = JSON.parse(req.body)
# {"status" => "forbidden"}
# {"status" => "rights", :rights => [list of rights]}
# Write : W
# Read : R or W
if body["status"] == "rights"
# We found some rights
self.shlog("INFO: Rights from backend: #{body["rights"]}")
return false if !body["rights"] or body["rights"].empty?
@rights = :r if body["rights"].include? "r"
@rights = :w if body["rights"].include? "w"
return true
end
return false
end
def user_permitted?
perm = check_permissions!
return false if !perm
if (@mode == :write) && (@rights == :w)
return true # write ok
end
if (@mode == :read) && ((@rights == :W) || (@rights == :r))
return true # read ok
end
return false
end
def rights
@rights
end
def run_baby!
if git?
repos_path = File.join(Settings.repos, "/git/", @opts_user, "/", "#{@opts_repo}.git")
command = "#{Settings.git_shell} -c #{@cmd} '#{repos_path}'"
shlog("INFO: Running command: #{command}")
if system(Settings.git_shell, "-c", "#{@cmd} '#{repos_path}'")
shlog("INFO: OK")
STDERR.puts "Shellular says: The repository will be refreshed in database soon if you really commited something ;-)"
return true
else
shlog("ERROR: FAILED")
STDERR.puts "Something seems to have fail... Contact the administrator if you have an idea and if it is reproductible each time."
return false
end
elsif hg?
# not implemented
return false
else
return false
end
end
def self.kickstart!(user, key_bits, shell_command)
command = self.new(user, shell_command, key_bits)
if command.valid?
exit 1 if !command.extract_user_and_repo! # Exit if "user/repo.git" isn't valid
if command.user_permitted?
command.shlog("INFO: Rights: #{command.rights.to_s}")
return command.run_baby!
else
# :(
command.shlog("ERROR: Sorry, GTFO.")
STDERR.puts "Codular: Sorry, forbidden. If you think this is an error, contact the administrator."
exit 1
end
else
command.shlog("ERROR: Invalid command '#{shell_command}'")
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.