mbbx6spp-gitauth 0.0.5.2
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 +141 -0
- data/USAGE +70 -0
- data/bin/gitauth +261 -0
- data/bin/gitauth-shell +30 -0
- data/config.ru +16 -0
- data/lib/gitauth/apache_authentication.rb +64 -0
- data/lib/gitauth/auth_setup_middleware.rb +53 -0
- data/lib/gitauth/client.rb +95 -0
- data/lib/gitauth/command.rb +101 -0
- data/lib/gitauth/group.rb +87 -0
- data/lib/gitauth/message.rb +69 -0
- data/lib/gitauth/repo.rb +155 -0
- data/lib/gitauth/saveable_class.rb +54 -0
- data/lib/gitauth/user.rb +135 -0
- data/lib/gitauth/web_app.rb +314 -0
- data/lib/gitauth.rb +101 -0
- data/public/gitauth.css +316 -0
- data/public/gitauth.js +17 -0
- data/public/jquery.js +19 -0
- data/resources/messages.yml +9 -0
- data/views/auth_setup.erb +27 -0
- data/views/clone_repo.erb +24 -0
- data/views/group.erb +24 -0
- data/views/index.erb +88 -0
- data/views/layout.erb +27 -0
- data/views/repo.erb +57 -0
- data/views/user.erb +51 -0
- metadata +196 -0
@@ -0,0 +1,314 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
|
+
# Copyright (C) 2009 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 'rack'
|
20
|
+
require 'sinatra'
|
21
|
+
require 'digest/sha2'
|
22
|
+
|
23
|
+
module GitAuth
|
24
|
+
class WebApp < Sinatra::Base
|
25
|
+
include GitAuth::Loggable
|
26
|
+
|
27
|
+
cattr_accessor :current_server
|
28
|
+
|
29
|
+
def self.has_auth?
|
30
|
+
username = GitAuth::Settings["web_username"]
|
31
|
+
password = GitAuth::Settings["web_password_hash"]
|
32
|
+
!(username.blank? || password.blank?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.update_auth
|
36
|
+
raw_username = Readline.readline('GitAuth Username (default is \'gitauth\'): ')
|
37
|
+
raw_username = 'gitauth' if raw_username.blank?
|
38
|
+
raw_password = ''
|
39
|
+
while raw_password.blank?
|
40
|
+
system "stty -echo"
|
41
|
+
raw_password = Readline.readline('GitAuth Password: ')
|
42
|
+
system "stty echo"
|
43
|
+
print "\n"
|
44
|
+
puts "You need to provide a password, please try again" if raw_password.blank?
|
45
|
+
end
|
46
|
+
password_confirmation = nil
|
47
|
+
while password_confirmation != raw_password
|
48
|
+
system "stty -echo"
|
49
|
+
password_confirmation = Readline.readline('Confirm Password: ')
|
50
|
+
system "stty echo"
|
51
|
+
print "\n"
|
52
|
+
puts "The confirmation doesn't match your password, please try again" if raw_password != password_confirmation
|
53
|
+
end
|
54
|
+
GitAuth::Settings.update!({
|
55
|
+
:web_username => raw_username,
|
56
|
+
:web_password_hash => Digest::SHA256.hexdigest(raw_password)
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.check_auth
|
61
|
+
GitAuth.prepare
|
62
|
+
if !has_auth?
|
63
|
+
if $stderr.tty?
|
64
|
+
logger.verbose = true
|
65
|
+
puts "For gitauth to continue, you need to provide a username and password."
|
66
|
+
update_auth
|
67
|
+
else
|
68
|
+
logger.fatal "You need to provide a username and password for GitAuth to function; Please run 'gitauth webapp` once"
|
69
|
+
exit!
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.run(options = {})
|
75
|
+
check_auth
|
76
|
+
set options
|
77
|
+
handler = detect_rack_handler
|
78
|
+
handler_name = handler.name.gsub(/.*::/, '')
|
79
|
+
logger.info "Starting up web server on #{port}"
|
80
|
+
handler.run self, :Host => host, :Port => port do |server|
|
81
|
+
GitAuth::WebApp.current_server = server
|
82
|
+
set :running, true
|
83
|
+
end
|
84
|
+
rescue Errno::EADDRINUSE => e
|
85
|
+
logger.fatal "Server is already running on port #{port}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.stop
|
89
|
+
if current_server.present?
|
90
|
+
current_server.respond_to?(:stop!) ? current_server.stop! : current_server.stop
|
91
|
+
end
|
92
|
+
exit!
|
93
|
+
logger.debug "Stopped Server."
|
94
|
+
end
|
95
|
+
|
96
|
+
unless GitAuth::ApacheAuthentication.setup?
|
97
|
+
|
98
|
+
use GitAuth::AuthSetupMiddleware
|
99
|
+
|
100
|
+
use Rack::Auth::Basic do |username, password|
|
101
|
+
[username, Digest::SHA256.hexdigest(password)] == [GitAuth::Settings["web_username"], GitAuth::Settings["web_password_hash"]]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
configure do
|
107
|
+
set :port, 8998
|
108
|
+
set :views, GitAuth::BASE_DIR.join("views")
|
109
|
+
set :public, GitAuth::BASE_DIR.join("public")
|
110
|
+
set :static, true
|
111
|
+
set :methodoverride, true
|
112
|
+
end
|
113
|
+
|
114
|
+
before { GitAuth.reload_models! }
|
115
|
+
|
116
|
+
helpers do
|
117
|
+
include Rack::Utils
|
118
|
+
alias_method :h, :escape_html
|
119
|
+
|
120
|
+
def link_to(text, link)
|
121
|
+
"<a href='#{u link}'>#{text}</a>"
|
122
|
+
end
|
123
|
+
|
124
|
+
def u(url)
|
125
|
+
"#{request.script_name}#{url}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete_link(text, url)
|
129
|
+
id = "deleteable-#{Digest::SHA256.hexdigest(url.to_s)[0, 6]}"
|
130
|
+
html = "<div class='deletable-container' style='display: none; margin: 0; padding: 0;'>"
|
131
|
+
html << "<form method='post' action='#{u url}' id='#{id}'>"
|
132
|
+
html << "<input name='_method' type='hidden' value='delete' />"
|
133
|
+
html << "</form></div>"
|
134
|
+
html << "<a href='#' onclick='if(confirm(\"Are you sure you want to do that? Deletion can not be reversed.\")) $(\"##{id}\").submit(); return false;'>#{text}</a>"
|
135
|
+
return html
|
136
|
+
end
|
137
|
+
|
138
|
+
def auto_link(member)
|
139
|
+
member = member.to_s
|
140
|
+
url = (member[0] == ?@ ? "/groups/#{URI.encode(member[1..-1])}" : "/users/#{URI.encode(member)}")
|
141
|
+
return link_to(member, url)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
get '/' do
|
147
|
+
@repos = GitAuth::Repo.all
|
148
|
+
@users = GitAuth::User.all
|
149
|
+
@groups = GitAuth::Group.all
|
150
|
+
erb :index
|
151
|
+
end
|
152
|
+
|
153
|
+
# Listing / Index Page
|
154
|
+
|
155
|
+
get '/repos/:name' do
|
156
|
+
@repo = GitAuth::Repo.get(params[:name])
|
157
|
+
if @repo.nil?
|
158
|
+
redirect root_with_message("The given repository couldn't be found.")
|
159
|
+
else
|
160
|
+
read_perms, write_perms = (@repo.permissions[:read]||[]), (@repo.permissions[:write]||[])
|
161
|
+
@all_access = read_perms & write_perms
|
162
|
+
@read_only = read_perms - @all_access
|
163
|
+
@write_only = write_perms - @all_access
|
164
|
+
erb :repo
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
get '/users/:name' do
|
169
|
+
@user = GitAuth::User.get(params[:name])
|
170
|
+
if @user.nil?
|
171
|
+
redirect root_with_message("The given user couldn't be found.")
|
172
|
+
else
|
173
|
+
repos = GitAuth::Repo.all
|
174
|
+
read_perms = repos.select { |r| r.readable_by?(@user) }
|
175
|
+
write_perms = repos.select { |r| r.writeable_by?(@user) }
|
176
|
+
@all_access = read_perms & write_perms
|
177
|
+
@read_only = read_perms - @all_access
|
178
|
+
@write_only = write_perms - @all_access
|
179
|
+
@groups = GitAuth::Group.all.select { |g| g.member?(@user) }
|
180
|
+
erb :user
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
get '/groups/:name' do
|
185
|
+
@group = GitAuth::Group.get(params[:name])
|
186
|
+
if @group.nil?
|
187
|
+
redirect root_with_message("The given group could not be found.")
|
188
|
+
else
|
189
|
+
erb :group
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Create and update repos
|
194
|
+
|
195
|
+
post '/repos' do
|
196
|
+
name = params[:repo][:name]
|
197
|
+
path = params[:repo][:path]
|
198
|
+
path = name if path.to_s.strip.empty?
|
199
|
+
if repo = GitAuth::Repo.create(name, path)
|
200
|
+
make_empty = (params[:repo][:make_empty] == "1")
|
201
|
+
repo.make_empty! if make_empty
|
202
|
+
if repo.execute_post_create_hook!
|
203
|
+
redirect u("/?repo_name=#{URI.encode(name)}&made_empty=#{make_empty ? "yes" : "no"}")
|
204
|
+
else
|
205
|
+
redirect root_with_message("Repository added but the post-create hook exited unsuccessfully.")
|
206
|
+
end
|
207
|
+
else
|
208
|
+
redirect root_with_message("There was an error adding the repository.")
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
post '/repos/:name' do
|
213
|
+
repo = GitAuth::Repo.get(params[:name])
|
214
|
+
if repo.nil?
|
215
|
+
redirect root_with_message("The given repository couldn't be found.")
|
216
|
+
else
|
217
|
+
new_permissions = Hash.new([])
|
218
|
+
[:all, :read, :write].each do |k|
|
219
|
+
if params[:repo][k]
|
220
|
+
perm_lines = params[:repo][k].to_s.split("\n")
|
221
|
+
new_permissions[k] = perm_lines.map do |l|
|
222
|
+
i = GitAuth.get_user_or_group(l.strip)
|
223
|
+
i.nil? ? nil : i.to_s
|
224
|
+
end.compact
|
225
|
+
end
|
226
|
+
end
|
227
|
+
all = new_permissions.delete(:all)
|
228
|
+
new_permissions[:read] |= all
|
229
|
+
new_permissions[:write] |= all
|
230
|
+
new_permissions.each_value { |v| v.uniq! }
|
231
|
+
repo.permissions = new_permissions
|
232
|
+
GitAuth::Repo.save!
|
233
|
+
redirect u("/repos/#{URI.encode(repo.name)}")
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
delete '/repos/:name' do
|
238
|
+
repo = GitAuth::Repo.get(params[:name])
|
239
|
+
if repo.nil?
|
240
|
+
redirect root_with_message("The given repository couldn't be found.")
|
241
|
+
else
|
242
|
+
repo.destroy!
|
243
|
+
redirect root_with_message("Repository removed.")
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Create, delete and update users
|
248
|
+
|
249
|
+
post '/users' do
|
250
|
+
name = params[:user][:name]
|
251
|
+
admin = params[:user][:admin].to_s == "1"
|
252
|
+
key = params[:user][:key]
|
253
|
+
if GitAuth::User.create(name, admin, key)
|
254
|
+
redirect root_with_message("User Added")
|
255
|
+
else
|
256
|
+
redirect root_with_message("There was an error adding the requested user.")
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
delete '/users/:name' do
|
261
|
+
user = GitAuth::User.get(params[:name])
|
262
|
+
if user.nil?
|
263
|
+
redirect root_with_message("The specified user couldn't be found.")
|
264
|
+
else
|
265
|
+
user.destroy!
|
266
|
+
redirect root_with_message("User removed.")
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Create and Update Groups
|
271
|
+
|
272
|
+
post '/groups' do
|
273
|
+
if GitAuth::Group.create(params[:group][:name])
|
274
|
+
redirect root_with_message("Group added")
|
275
|
+
else
|
276
|
+
redirect root_with_message("There was an error adding the requested group.")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
post '/groups/:name' do
|
281
|
+
group = GitAuth::Group.get(params[:name])
|
282
|
+
if group.nil?
|
283
|
+
redirect root_with_message("The specified group couldn't be found.")
|
284
|
+
else
|
285
|
+
if params[:group][:members]
|
286
|
+
member_lines = params[:group][:members].to_s.split("\n")
|
287
|
+
group.members = member_lines.map do |l|
|
288
|
+
i = GitAuth.get_user_or_group(l.strip)
|
289
|
+
i.nil? ? nil : i.to_s
|
290
|
+
end.compact - [group.to_s]
|
291
|
+
GitAuth::Group.save!
|
292
|
+
end
|
293
|
+
redirect u("/groups/#{URI.encode(group.name)}")
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
delete '/groups/:name' do
|
298
|
+
group = GitAuth::Group.get(params[:name])
|
299
|
+
if group.nil?
|
300
|
+
redirect root_with_message("The specified group couldn't be found.")
|
301
|
+
else
|
302
|
+
group.destroy!
|
303
|
+
redirect root_with_message("Group removed.")
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Misc Helpers
|
308
|
+
|
309
|
+
def root_with_message(message)
|
310
|
+
u("/?message=#{URI.encode(message)}")
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
end
|
data/lib/gitauth.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
|
+
# Copyright (C) 2009 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 'rubygems'
|
20
|
+
require 'pathname'
|
21
|
+
|
22
|
+
# Prepend lib dir + any vendored lib's to the front of the load
|
23
|
+
# path to ensure they're loaded first.
|
24
|
+
$LOAD_PATH.unshift(*Dir[Pathname(__FILE__).dirname.join("../{lib,vendor/*/lib}").expand_path.to_s])
|
25
|
+
|
26
|
+
require 'perennial'
|
27
|
+
|
28
|
+
module GitAuth
|
29
|
+
include Perennial
|
30
|
+
include Loggable
|
31
|
+
|
32
|
+
VERSION = [0, 0, 5, 2]
|
33
|
+
BASE_DIR = Pathname(__FILE__).dirname.join("..").expand_path
|
34
|
+
GITAUTH_DIR = Pathname("~/.gitauth/").expand_path
|
35
|
+
|
36
|
+
manifest do |m, l|
|
37
|
+
Settings.root = File.dirname(__FILE__)
|
38
|
+
Settings.default_settings_path = GITAUTH_DIR.join("settings.yml")
|
39
|
+
Settings.lookup_key_path = []
|
40
|
+
Logger.default_logger_path = GITAUTH_DIR.join("gitauth.log")
|
41
|
+
# Register stuff on the loader.
|
42
|
+
l.register_controller :web_app, 'GitAuth::WebApp'
|
43
|
+
l.before_run { GitAuth.prepare }
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'gitauth/message' # Basic error messages etc (as of yet unushed)
|
47
|
+
require 'gitauth/saveable_class' # Simple YAML store for dumpables classes
|
48
|
+
require 'gitauth/repo' # The basic GitAuth repo object
|
49
|
+
require 'gitauth/user' # The basic GitAuth user object
|
50
|
+
require 'gitauth/group' # The basic GitAuth group object (collection of users)
|
51
|
+
require 'gitauth/command' # Processes / filters commands
|
52
|
+
require 'gitauth/client' # Handles the actual SSH interaction / bringing it together
|
53
|
+
|
54
|
+
autoload :AuthSetupMiddleware, 'gitauth/auth_setup_middleware'
|
55
|
+
autoload :ApacheAuthentication, 'gitauth/apache_authentication'
|
56
|
+
autoload :WebApp, 'gitauth/web_app'
|
57
|
+
|
58
|
+
class << self
|
59
|
+
|
60
|
+
def prepare
|
61
|
+
GitAuth::Settings.setup!
|
62
|
+
reload_models!
|
63
|
+
end
|
64
|
+
|
65
|
+
def version
|
66
|
+
VERSION.join(".")
|
67
|
+
end
|
68
|
+
|
69
|
+
def msg(type, message)
|
70
|
+
Message.new(type, message)
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_user_or_group(name)
|
74
|
+
name = name.to_s.strip
|
75
|
+
return if name.empty?
|
76
|
+
(name =~ /^@/ ? Group : User).get(name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_git?
|
80
|
+
!`which git`.blank?
|
81
|
+
end
|
82
|
+
|
83
|
+
def each_model(method = nil, &blk)
|
84
|
+
[Repo, User, Group].each { |m| m.send(method) } if method.present?
|
85
|
+
[Repo, User, Group].each(&blk) unless blk.nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
def reload_models!
|
89
|
+
each_model(:load!)
|
90
|
+
end
|
91
|
+
|
92
|
+
def run(command)
|
93
|
+
GitAuth::Logger.info "Running command: #{command}"
|
94
|
+
result = system "#{command} 2> /dev/null 1> /dev/null"
|
95
|
+
GitAuth::Logger.info "Command was #{"not " if !result}successful"
|
96
|
+
return result
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|