brownbeagle-gitauth 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +661 -0
- data/README.rdoc +92 -0
- data/bin/gitauth +162 -0
- data/bin/gitauth-shell +66 -0
- data/lib/gitauth/client.rb +91 -0
- data/lib/gitauth/command.rb +105 -0
- data/lib/gitauth/repo.rb +106 -0
- data/lib/gitauth/users.rb +119 -0
- data/lib/gitauth.rb +51 -0
- metadata +74 -0
data/README.rdoc
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
== GitAuth - SSH-based authentication for Shared Git Repositories.
|
2
|
+
|
3
|
+
If you've heard of Gitosis before, GitAuth is like Gitosis but A) in Ruby, B) slightly simpler to get going and C) doesn't use a git repository to manage users.
|
4
|
+
|
5
|
+
At the moment configuration / adding users is done via a single command - +gitauth+. For usage, see below.
|
6
|
+
|
7
|
+
=== License
|
8
|
+
|
9
|
+
GitAuth is licensed under AGPL, with parts of the code being derived
|
10
|
+
from Gitorius - http://gitorious.org/
|
11
|
+
|
12
|
+
=== Installing GitAuth
|
13
|
+
|
14
|
+
Getting started is relatively simple. First of, you'll need to log onto the remote server / your git host. Next, you'll need to install the gem:
|
15
|
+
|
16
|
+
sudo gem install brownbeagle-gitauth --source=https://gems.github.com/
|
17
|
+
|
18
|
+
Once that's done, the +gitauth+ and +gitauth-shell+ commands should be in your path.
|
19
|
+
Next, you'll want to (in most cases anyway) use a specific +git+ user to host repositories.
|
20
|
+
|
21
|
+
Using the example of ubuntu, we'll add a git user under which all actions will now take place (note, this is essentially the same as gitosis):
|
22
|
+
|
23
|
+
sudo adduser --disabled-password --shell /bin/bash --group --home /home/git --system --gecos 'gitauth user for version control' git
|
24
|
+
|
25
|
+
Now, whenever you run the +gitauth+ executable, you'll do so as the user you just created
|
26
|
+
above. For simplicity purposes, I added the the following to my zsh profile so I always
|
27
|
+
had it available. If you don't wish to, just use as you would without the alias:
|
28
|
+
|
29
|
+
alias asgit='sudo -H -u git'
|
30
|
+
|
31
|
+
And finally, to create a settings file and initialize .ssh and authorized_keys, perform the
|
32
|
+
following:
|
33
|
+
|
34
|
+
asgit gitauth install
|
35
|
+
|
36
|
+
Note that when it asks you for the gitauth shell path, the default will lock
|
37
|
+
it to the current gitauth version SO if you want it to stay up to date between gem versions
|
38
|
+
point it to the path for always-current executable (e.g. on Ubuntu 9.04 w/ apt-get ruby + gems,
|
39
|
+
+/var/lib/gems/1.8/bin/gitauth-shell+)
|
40
|
+
|
41
|
+
Also, Note that if you append a path to a public key to the end of the install command,
|
42
|
+
it will initialize a new +admin+ user who can also login via SSH. e.g.
|
43
|
+
|
44
|
+
asgit gitauth install id_rsa.pub
|
45
|
+
|
46
|
+
Would initialize an admin user with the given public key.
|
47
|
+
|
48
|
+
Note that from now on, all gitauth keys should be run either logged in as
|
49
|
+
git (via the admin user and ssh) or by being prefixed with asgit or "sudo -H -u git"
|
50
|
+
|
51
|
+
=== Adding Users
|
52
|
+
|
53
|
+
Whenever you want to add a user, it's ass imple as:
|
54
|
+
|
55
|
+
gitauth adduser user-name path-to-public-key
|
56
|
+
|
57
|
+
Note that if the --admin option is specified, the user will
|
58
|
+
be able to log in to the shell via SSH and will also be able
|
59
|
+
to access any repository.
|
60
|
+
|
61
|
+
=== Adding Repositories
|
62
|
+
|
63
|
+
Adding a repository is a two step process. First, you create it:
|
64
|
+
|
65
|
+
gitauth addrepo repo-name
|
66
|
+
|
67
|
+
Then, for every user who needs access, you do:
|
68
|
+
|
69
|
+
gitauth permissions repo-name user-name permission-type
|
70
|
+
|
71
|
+
Where permission type is read, write or all. If permission
|
72
|
+
type isn't specified, it will default to all.
|
73
|
+
|
74
|
+
=== Accessing repos:
|
75
|
+
|
76
|
+
Finally, once you've added users / repos, using them is as simple
|
77
|
+
as doing the following on each users computer:
|
78
|
+
|
79
|
+
git clone git@your-remote-host:repo-name
|
80
|
+
|
81
|
+
Or
|
82
|
+
|
83
|
+
git clone git@your-remote-host:repo-name.git
|
84
|
+
|
85
|
+
Either form working just as well.
|
86
|
+
|
87
|
+
Note that for the first time you push, you will need
|
88
|
+
to use the full form:
|
89
|
+
|
90
|
+
git push origin master
|
91
|
+
|
92
|
+
As it starts as an empty repo.
|
data/bin/gitauth
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009 BrownBeagle
|
5
|
+
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#++
|
20
|
+
|
21
|
+
require 'rubygems'
|
22
|
+
require 'readline'
|
23
|
+
require 'thor'
|
24
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "gitauth")
|
25
|
+
|
26
|
+
|
27
|
+
class GitAuthRunner < Thor
|
28
|
+
|
29
|
+
|
30
|
+
desc "addrepo REPO-NAME [PATH-PART]", "Adds a new repository"
|
31
|
+
def addrepo(name, path = name)
|
32
|
+
GitAuth.setup!
|
33
|
+
if GitAuth::Repo.create(name, path)
|
34
|
+
$stdout.puts "Repo was successfully created"
|
35
|
+
else
|
36
|
+
$stderr.puts "There was an error creating the repo"
|
37
|
+
exit! 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "adduser NAME PATH-TO-PUBLIC-KEY [--admin]", "Adds a user"
|
42
|
+
method_options :admin => :boolean
|
43
|
+
def adduser(name, key_path)
|
44
|
+
GitAuth.setup!
|
45
|
+
admin = !!(options && options[:admin])
|
46
|
+
if GitAuth::Users.create(name, admin, File.read(key_path).strip)
|
47
|
+
$stdout.puts "User added"
|
48
|
+
else
|
49
|
+
$stderr.puts "There was an error adding the given user"
|
50
|
+
exit!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "repos", "Lists all the current repos"
|
55
|
+
def repos
|
56
|
+
GitAuth.setup!
|
57
|
+
$stdout.puts "repositories:"
|
58
|
+
GitAuth::Repo.all.each do |repo|
|
59
|
+
$stdout.puts " - #{repo.name}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "users", "Lists all users in the system"
|
64
|
+
def users
|
65
|
+
GitAuth.setup!
|
66
|
+
$stdout.puts "users:"
|
67
|
+
GitAuth::Users.all.each do |user|
|
68
|
+
$stdout.puts "- #{user.name}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
desc "permissions REPO USER [PERMISION=all,read,write]", "Adds Permissions for a user to a repository"
|
74
|
+
def permissions(repo, user, permissions = "all")
|
75
|
+
GitAuth.setup!
|
76
|
+
unless %w(read write all).include?(permissions)
|
77
|
+
$stderr.puts "Invalid permissions: #{permissions}"
|
78
|
+
exit! 1
|
79
|
+
end
|
80
|
+
repo = GitAuth::Repo.get(repo)
|
81
|
+
user = GitAuth::Users.get(user)
|
82
|
+
if repo.nil? || user.nil?
|
83
|
+
$stderr.puts "Invalid repository or user, please check the name"
|
84
|
+
exit! 1
|
85
|
+
end
|
86
|
+
repo.writeable_by(user) if %w(all write).include?(permissions)
|
87
|
+
repo.readable_by(user) if %w(all read).include?(permissions)
|
88
|
+
GitAuth::Users.save!
|
89
|
+
GitAuth::Repo.save!
|
90
|
+
$stdout.puts "Permissions Added"
|
91
|
+
end
|
92
|
+
|
93
|
+
desc "install [ADMIN-PUBLIC-KEY]", "creates and sets the permissions for .ssh and .ssh/authorized keys"
|
94
|
+
method_options :force_config => :boolean
|
95
|
+
def install(public_key_path = nil)
|
96
|
+
$stdout.print "Are you logged in as the correct user? (y/n) "
|
97
|
+
answer = Readline.readline
|
98
|
+
if answer !~ /^y/i
|
99
|
+
$stderr.puts "Please log in as the correct user and re-run"
|
100
|
+
exit! 1
|
101
|
+
end
|
102
|
+
require 'fileutils'
|
103
|
+
folder = File.expand_path("~/.ssh")
|
104
|
+
if !File.exist?(folder) || !File.directory?(folder)
|
105
|
+
FileUtils.mkdir(folder)
|
106
|
+
FileUtils.chmod(0700, folder)
|
107
|
+
end
|
108
|
+
authorized_keys = File.join(folder, "authorized_keys")
|
109
|
+
if !File.exist?(authorized_keys)
|
110
|
+
File.open(authorized_keys, "w+") do |f|
|
111
|
+
f.puts "## GitAuth - DO NO EDIT BELOW THIS LINE ##"
|
112
|
+
end
|
113
|
+
FileUtils.chmod(0600, authorized_keys)
|
114
|
+
end
|
115
|
+
gitauth_folder = File.expand_path("~/.gitauth/")
|
116
|
+
FileUtils.mkdir(gitauth_folder) if !File.exist?(gitauth_folder) || !File.directory?(gitauth_folder)
|
117
|
+
gitauth_settings_path = File.join(gitauth_folder, "settings.yml")
|
118
|
+
unless File.exist?(gitauth_settings_path) || (options && options[:force_config])
|
119
|
+
print "Where did you want repositories to be stored? (default: ~/repositories/): "
|
120
|
+
path = Readline.readline.strip
|
121
|
+
path = File.expand_path("~/repositories") if path.empty?
|
122
|
+
begin
|
123
|
+
FileUtils.mkdir_p(path)
|
124
|
+
rescue
|
125
|
+
$stderr.puts "There was an error making the repository folder: #{path}"
|
126
|
+
$stderr.puts "Please check again"
|
127
|
+
exit! 1
|
128
|
+
end
|
129
|
+
current_gitauth_shell_path = File.join(GitAuth::BASE_DIR, "bin", "gitauth-shell")
|
130
|
+
$stdout.print "What is the path to your gitauth-shell (default: '#{current_gitauth_shell_path}'): "
|
131
|
+
gitauth_shell_path = Readline.readline
|
132
|
+
gitauth_shell_path = current_gitauth_shell_path if gitauth_shell_path.empty?
|
133
|
+
File.open(gitauth_settings_path, "w+") do |f|
|
134
|
+
f.write({
|
135
|
+
"base_path" => path,
|
136
|
+
"authorized_keys_file" => authorized_keys,
|
137
|
+
"shell_executable" => gitauth_shell_path
|
138
|
+
}.to_yaml)
|
139
|
+
end
|
140
|
+
if !public_key_path.nil? && File.exist?(public_key_path)
|
141
|
+
GitAuth.setup!
|
142
|
+
created = GitAuth::Users.create("admin", true, File.read(public_key_path).strip)
|
143
|
+
if created
|
144
|
+
$stdout.puts "Admin User Created."
|
145
|
+
else
|
146
|
+
$stderr.puts "An admin user couldn't be created."
|
147
|
+
exit! 1
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
rescue Errno::EACCES
|
152
|
+
$stderr.puts "Hey, it looks you don't have access to that - sorry!"
|
153
|
+
exit! 1
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
if ARGV.empty?
|
159
|
+
GitAuthRunner.new.help
|
160
|
+
else
|
161
|
+
GitAuthRunner.start
|
162
|
+
end
|
data/bin/gitauth-shell
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009 BrownBeagle
|
5
|
+
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#++
|
20
|
+
|
21
|
+
|
22
|
+
REAL_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
23
|
+
|
24
|
+
# Require the proper gitauth file.
|
25
|
+
require File.expand_path(File.join(File.dirname(REAL_FILE), "..", "lib", "gitauth"))
|
26
|
+
|
27
|
+
GitAuth.setup!
|
28
|
+
|
29
|
+
# Gitorious does it so I should too!
|
30
|
+
File.umask(0022)
|
31
|
+
|
32
|
+
user_name = ARGV[0]
|
33
|
+
command = ENV["SSH_ORIGINAL_COMMAND"]
|
34
|
+
|
35
|
+
GitAuth::Client.start!(user_name, command) do |c|
|
36
|
+
|
37
|
+
c.on(:invalid_user) do |c|
|
38
|
+
c.exit_with_error "An invalid user / key was used. Please ensure it is setup with GitAuth"
|
39
|
+
end
|
40
|
+
|
41
|
+
c.on(:invalid_command) do |c|
|
42
|
+
if c.user.shell_accessible?
|
43
|
+
exec(ENV["SHELL"])
|
44
|
+
else
|
45
|
+
c.exit_with_error "SSH_ORIGINAL_COMMAND is needed, mmmkay?"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
c.on(:invalid_repository) do |c|
|
50
|
+
c.exit_with_error "Ze repository you specified does not exist."
|
51
|
+
end
|
52
|
+
|
53
|
+
c.on(:bad_command) do |c|
|
54
|
+
c.exit_with_error "A Bad Command Has Failed Ye, Thou Shalt Not Continue."
|
55
|
+
end
|
56
|
+
|
57
|
+
c.on(:access_denied) do |c|
|
58
|
+
c.exit_with_error "These are not the droids you are looking for"
|
59
|
+
end
|
60
|
+
|
61
|
+
c.on(:fatal_error) do |c|
|
62
|
+
c.exit_with_error "Holy crap, we've imploded cap'n!"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
|
+
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
|
4
|
+
# Copyright (C) 2007, 2008 Johan Sørensen <johan@johansorensen.com>
|
5
|
+
# Copyright (C) 2008 Tor Arne Vestbø <tavestbo@trolltech.com>
|
6
|
+
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
7
|
+
#
|
8
|
+
# This program is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU Affero General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU Affero General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU Affero General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
|
22
|
+
module GitAuth
|
23
|
+
class Client
|
24
|
+
|
25
|
+
attr_accessor :user, :command
|
26
|
+
|
27
|
+
def initialize(user_name, command)
|
28
|
+
GitAuth.logger.debug "Initializing client with command: '#{command}' and user name '#{user_name}'"
|
29
|
+
@callbacks = Hash.new { |h,k| h[k] = [] }
|
30
|
+
@user = GitAuth::Users.get(user_name.to_s.strip)
|
31
|
+
@command = command
|
32
|
+
end
|
33
|
+
|
34
|
+
def on(command, &blk)
|
35
|
+
@callbacks[command.to_sym] << blk
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute_callback!(command)
|
39
|
+
@callbacks[command.to_sym].each { |c| c.call(self) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def exit_with_error(error)
|
43
|
+
GitAuth.logger.warn "Exiting with error: #{error}"
|
44
|
+
$stderr.puts error
|
45
|
+
exit! 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def run!
|
49
|
+
if @user.nil?
|
50
|
+
execute_callback! :invalid_user
|
51
|
+
elsif @command.to_s.strip.empty?
|
52
|
+
execute_callback! :invalid_command
|
53
|
+
else
|
54
|
+
command = Command.parse!(@command)
|
55
|
+
repo = Repo.get(extract_repo_name(command))
|
56
|
+
if command.bad?
|
57
|
+
execute_callback! :bad_command
|
58
|
+
elsif repo.nil?
|
59
|
+
execute_callback! :invalid_repository
|
60
|
+
elsif user.can_execute?(command, repo)
|
61
|
+
# We can go ahead.
|
62
|
+
git_shell_argument = "#{command.verb} '#{repo.real_path}'"
|
63
|
+
# And execute that soab.
|
64
|
+
GitAuth.logger.info "Running command: #{git_shell_argument} for user: #{@user.name}"
|
65
|
+
exec("git-shell", "-c", git_shell_argument)
|
66
|
+
else
|
67
|
+
execute_callback! :access_denied
|
68
|
+
end
|
69
|
+
end
|
70
|
+
rescue Exception => e
|
71
|
+
GitAuth.logger.fatal "Exception: #{e.class.name}: #{e.message}"
|
72
|
+
e.backtrace.each do |l|
|
73
|
+
GitAuth.logger.fatal " => #{l}"
|
74
|
+
end
|
75
|
+
execute_callback! :fatal_error
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.start!(user, command)
|
79
|
+
client = self.new(user, command)
|
80
|
+
yield client if block_given?
|
81
|
+
client.run!
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def extract_repo_name(command)
|
87
|
+
command.path.gsub(/\.git$/, "")
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
|
+
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
|
4
|
+
# Copyright (C) 2007, 2008 Johan Sørensen <johan@johansorensen.com>
|
5
|
+
# Copyright (C) 2008 Tim Dysinger <tim@dysinger.net>
|
6
|
+
# Copyright (C) 2008 Tor Arne Vestbø <tavestbo@trolltech.com>
|
7
|
+
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
8
|
+
#
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU Affero General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This program is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU Affero General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Affero General Public License
|
20
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
# This along with the associated gitauth-shell command are inspired by
|
24
|
+
# (and essentially, derived from) gitosis (http://eagain.net/gitweb/?p=gitosis.git)
|
25
|
+
# and gitorius (http://gitorius.org)
|
26
|
+
# Gitosis is of this writing licensed under the GPLv2 and is copyright (c) Tommi Virtanen
|
27
|
+
# and can be found at http://eagain.net/gitweb/?p=gitosis.git
|
28
|
+
# GitAuth::Command is licensed under the same license
|
29
|
+
|
30
|
+
module GitAuth
|
31
|
+
class Command
|
32
|
+
class BadCommandError < StandardError; end
|
33
|
+
|
34
|
+
# Standard Commands
|
35
|
+
READ_COMMANDS = ["git-upload-pack", "git upload-pack"]
|
36
|
+
WRITE_COMMANDS = ["git-receive-pack", "git receive-pack"]
|
37
|
+
PATH_REGEXP = /^'([a-z0-9\-\+]+(\.git)?)'$/i.freeze
|
38
|
+
|
39
|
+
attr_reader :path, :verb, :command
|
40
|
+
|
41
|
+
def initialize(command)
|
42
|
+
@command = command
|
43
|
+
@verb = nil
|
44
|
+
@argument = nil
|
45
|
+
@path = nil
|
46
|
+
@bad_command = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def bad?
|
50
|
+
!!@bad_command
|
51
|
+
end
|
52
|
+
|
53
|
+
def write?
|
54
|
+
!bad? && @verb_type == :write
|
55
|
+
end
|
56
|
+
|
57
|
+
def read?
|
58
|
+
!bad? && !write?
|
59
|
+
end
|
60
|
+
|
61
|
+
# These exceptions are FUGLY.
|
62
|
+
# Clean up, mmkay?
|
63
|
+
def process!
|
64
|
+
raise BadCommandError if @command.include?("\n")
|
65
|
+
@verb, @argument = split_command
|
66
|
+
raise BadCommandError if @argument.nil? || @argument.is_a?(Array)
|
67
|
+
# Check if it's read / write
|
68
|
+
if READ_COMMANDS.include?(@verb)
|
69
|
+
@verb_type = :read
|
70
|
+
elsif WRITE_COMMANDS.include?(@verb)
|
71
|
+
@verb_type = :write
|
72
|
+
else
|
73
|
+
raise BadCommandError
|
74
|
+
end
|
75
|
+
if PATH_REGEXP =~ @argument
|
76
|
+
@path = $1
|
77
|
+
raise BadCommandError unless @path
|
78
|
+
else
|
79
|
+
raise BadCommandError
|
80
|
+
end
|
81
|
+
@bad_command = false
|
82
|
+
rescue BadCommandError
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.parse!(command)
|
86
|
+
command = self.new(command)
|
87
|
+
command.process!
|
88
|
+
command
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def split_command
|
94
|
+
parts = @command.split(" ")
|
95
|
+
if parts.size == 3
|
96
|
+
["#{parts[0]} #{parts[1]}", parts[2]]
|
97
|
+
elsif parts.size == 2
|
98
|
+
parts
|
99
|
+
else
|
100
|
+
raise BadCommandError
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
data/lib/gitauth/repo.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
|
+
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#++
|
18
|
+
|
19
|
+
require 'fileutils'
|
20
|
+
module GitAuth
|
21
|
+
class Repo
|
22
|
+
REPOS_PATH = File.join(GitAuth::GITAUTH_DIR, "repositories.yml")
|
23
|
+
|
24
|
+
def self.all
|
25
|
+
@@all_repositories ||= nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.load!
|
29
|
+
self.all = YAML.load_file(REPOS_PATH) rescue nil if File.exist?(REPOS_PATH)
|
30
|
+
self.all = [] unless self.all.is_a?(Array)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.save!
|
34
|
+
load! if self.all.nil?
|
35
|
+
File.open(REPOS_PATH, "w+") do |f|
|
36
|
+
f.write self.all.to_yaml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.all=(value)
|
41
|
+
@@all_repositories = value
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.get(name)
|
45
|
+
GitAuth.logger.debug "Getting Repo w/ name: '#{name}'"
|
46
|
+
self.all.detect { |r| r.name == name }
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.create(name, path = name)
|
50
|
+
return false unless self.get(name).nil?
|
51
|
+
repository = self.new(name, path)
|
52
|
+
if repository.create_repo!
|
53
|
+
self.load!
|
54
|
+
self.all << repository
|
55
|
+
self.save!
|
56
|
+
return true
|
57
|
+
else
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_accessor :name, :path
|
63
|
+
|
64
|
+
def initialize(name, path, auto_create = false)
|
65
|
+
@name, @path = name, path
|
66
|
+
@permissions = {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def writeable_by(user)
|
70
|
+
@permissions[:write] ||= []
|
71
|
+
@permissions[:write] << user.name
|
72
|
+
@permissions[:write].uniq!
|
73
|
+
end
|
74
|
+
|
75
|
+
def readable_by(user)
|
76
|
+
@permissions[:read] ||= []
|
77
|
+
@permissions[:read] << user.name
|
78
|
+
@permissions[:read].uniq!
|
79
|
+
end
|
80
|
+
|
81
|
+
def writeable_by?(user)
|
82
|
+
(@permissions[:write] || []).include? user.name
|
83
|
+
end
|
84
|
+
|
85
|
+
def readable_by?(user)
|
86
|
+
(@permissions[:read] || []).include? user.name
|
87
|
+
end
|
88
|
+
|
89
|
+
def real_path
|
90
|
+
File.join(GitAuth.settings.base_path, @path)
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_repo!
|
94
|
+
path = self.real_path
|
95
|
+
unless File.exist?(path) && File.directory?(path)
|
96
|
+
FileUtils.mkdir_p(path)
|
97
|
+
output = ""
|
98
|
+
Dir.chdir(path) do
|
99
|
+
IO.popen("git init --bare") { |f| output << f.read }
|
100
|
+
end
|
101
|
+
return !!(output =~ /Initialized empty Git repository/)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|