gitauth 0.0.5.0

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.
@@ -0,0 +1,310 @@
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='#{link}'>#{text}</a>"
122
+ end
123
+
124
+ def delete_link(text, url)
125
+ id = "deleteable-#{Digest::SHA256.hexdigest(url.to_s)[0, 6]}"
126
+ html = "<div class='deletable-container' style='display: none; margin: 0; padding: 0;'>"
127
+ html << "<form method='post' action='#{url}' id='#{id}'>"
128
+ html << "<input name='_method' type='hidden' value='delete' />"
129
+ html << "</form></div>"
130
+ 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>"
131
+ return html
132
+ end
133
+
134
+ def auto_link(member)
135
+ member = member.to_s
136
+ url = (member[0] == ?@ ? "/groups/#{URI.encode(member[1..-1])}" : "/users/#{URI.encode(member)}")
137
+ return link_to(member, url)
138
+ end
139
+
140
+ end
141
+
142
+ get '/' do
143
+ @repos = GitAuth::Repo.all
144
+ @users = GitAuth::User.all
145
+ @groups = GitAuth::Group.all
146
+ erb :index
147
+ end
148
+
149
+ # Listing / Index Page
150
+
151
+ get '/repos/:name' do
152
+ @repo = GitAuth::Repo.get(params[:name])
153
+ if @repo.nil?
154
+ redirect root_with_message("The given repository couldn't be found.")
155
+ else
156
+ read_perms, write_perms = (@repo.permissions[:read]||[]), (@repo.permissions[:write]||[])
157
+ @all_access = read_perms & write_perms
158
+ @read_only = read_perms - @all_access
159
+ @write_only = write_perms - @all_access
160
+ erb :repo
161
+ end
162
+ end
163
+
164
+ get '/users/:name' do
165
+ @user = GitAuth::User.get(params[:name])
166
+ if @user.nil?
167
+ redirect root_with_message("The given user couldn't be found.")
168
+ else
169
+ repos = GitAuth::Repo.all
170
+ read_perms = repos.select { |r| r.readable_by?(@user) }
171
+ write_perms = repos.select { |r| r.writeable_by?(@user) }
172
+ @all_access = read_perms & write_perms
173
+ @read_only = read_perms - @all_access
174
+ @write_only = write_perms - @all_access
175
+ @groups = GitAuth::Group.all.select { |g| g.member?(@user) }
176
+ erb :user
177
+ end
178
+ end
179
+
180
+ get '/groups/:name' do
181
+ @group = GitAuth::Group.get(params[:name])
182
+ if @group.nil?
183
+ redirect root_with_message("The given group could not be found.")
184
+ else
185
+ erb :group
186
+ end
187
+ end
188
+
189
+ # Create and update repos
190
+
191
+ post '/repos' do
192
+ name = params[:repo][:name]
193
+ path = params[:repo][:path]
194
+ path = name if path.to_s.strip.empty?
195
+ if repo = GitAuth::Repo.create(name, path)
196
+ make_empty = (params[:repo][:make_empty] == "1")
197
+ repo.make_empty! if make_empty
198
+ if repo.execute_post_create_hook!
199
+ redirect "/?repo_name=#{URI.encode(name)}&made_empty=#{make_empty ? "yes" : "no"}"
200
+ else
201
+ redirect root_with_message("Repository added but the post-create hook exited unsuccessfully.")
202
+ end
203
+ else
204
+ redirect root_with_message("There was an error adding the repository.")
205
+ end
206
+ end
207
+
208
+ post '/repos/:name' do
209
+ repo = GitAuth::Repo.get(params[:name])
210
+ if repo.nil?
211
+ redirect root_with_message("The given repository couldn't be found.")
212
+ else
213
+ new_permissions = Hash.new([])
214
+ [:all, :read, :write].each do |k|
215
+ if params[:repo][k]
216
+ perm_lines = params[:repo][k].to_s.split("\n")
217
+ new_permissions[k] = perm_lines.map do |l|
218
+ i = GitAuth.get_user_or_group(l.strip)
219
+ i.nil? ? nil : i.to_s
220
+ end.compact
221
+ end
222
+ end
223
+ all = new_permissions.delete(:all)
224
+ new_permissions[:read] |= all
225
+ new_permissions[:write] |= all
226
+ new_permissions.each_value { |v| v.uniq! }
227
+ repo.permissions = new_permissions
228
+ GitAuth::Repo.save!
229
+ redirect "/repos/#{URI.encode(repo.name)}"
230
+ end
231
+ end
232
+
233
+ delete '/repos/:name' do
234
+ repo = GitAuth::Repo.get(params[:name])
235
+ if repo.nil?
236
+ redirect root_with_message("The given repository couldn't be found.")
237
+ else
238
+ repo.destroy!
239
+ redirect root_with_message("Repository removed.")
240
+ end
241
+ end
242
+
243
+ # Create, delete and update users
244
+
245
+ post '/users' do
246
+ name = params[:user][:name]
247
+ admin = params[:user][:admin].to_s == "1"
248
+ key = params[:user][:key]
249
+ if GitAuth::User.create(name, admin, key)
250
+ redirect root_with_message("User Added")
251
+ else
252
+ redirect root_with_message("There was an error adding the requested user.")
253
+ end
254
+ end
255
+
256
+ delete '/users/:name' do
257
+ user = GitAuth::User.get(params[:name])
258
+ if user.nil?
259
+ redirect root_with_message("The specified user couldn't be found.")
260
+ else
261
+ user.destroy!
262
+ redirect root_with_message("User removed.")
263
+ end
264
+ end
265
+
266
+ # Create and Update Groups
267
+
268
+ post '/groups' do
269
+ if GitAuth::Group.create(params[:group][:name])
270
+ redirect root_with_message("Group added")
271
+ else
272
+ redirect root_with_message("There was an error adding the requested group.")
273
+ end
274
+ end
275
+
276
+ post '/groups/:name' do
277
+ group = GitAuth::Group.get(params[:name])
278
+ if group.nil?
279
+ redirect root_with_message("The specified group couldn't be found.")
280
+ else
281
+ if params[:group][:members]
282
+ member_lines = params[:group][:members].to_s.split("\n")
283
+ group.members = member_lines.map do |l|
284
+ i = GitAuth.get_user_or_group(l.strip)
285
+ i.nil? ? nil : i.to_s
286
+ end.compact - [group.to_s]
287
+ GitAuth::Group.save!
288
+ end
289
+ redirect "/groups/#{URI.encode(group.name)}"
290
+ end
291
+ end
292
+
293
+ delete '/groups/:name' do
294
+ group = GitAuth::Group.get(params[:name])
295
+ if group.nil?
296
+ redirect root_with_message("The specified group couldn't be found.")
297
+ else
298
+ group.destroy!
299
+ redirect root_with_message("Group removed.")
300
+ end
301
+ end
302
+
303
+ # Misc Helpers
304
+
305
+ def root_with_message(message)
306
+ "/?message=#{URI.encode(message)}"
307
+ end
308
+
309
+ end
310
+ end
@@ -0,0 +1,316 @@
1
+ /* Reset */
2
+ html, body, div, span, applet, object, iframe,
3
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4
+ a, abbr, acronym, address, big, cite, code,
5
+ del, dfn, em, font, img, ins, kbd, q, s, samp,
6
+ small, strike, strong, sub, sup, tt, var,
7
+ dl, dt, dd, ol, ul, li,
8
+ fieldset, form, label, legend,
9
+ table, caption, tbody, tfoot, thead, tr, th, td {
10
+ margin: 0;
11
+ padding: 0;
12
+ border: 0;
13
+ outline: 0;
14
+ font-weight: inherit;
15
+ font-style: inherit;
16
+ font-size: 100%;
17
+ font-family: inherit;
18
+ vertical-align: baseline;
19
+ }
20
+ /* remember to define focus styles! */
21
+ :focus {
22
+ outline: 0;
23
+ }
24
+ body {
25
+ line-height: 1;
26
+ color: black;
27
+ background: white;
28
+ }
29
+ ol, ul {
30
+ list-style: none;
31
+ }
32
+ /* tables still need 'cellspacing="0"' in the markup */
33
+ table {
34
+ border-collapse: separate;
35
+ border-spacing: 0;
36
+ }
37
+ caption, th, td {
38
+ text-align: left;
39
+ font-weight: normal;
40
+ }
41
+ blockquote:before, blockquote:after,
42
+ q:before, q:after {
43
+ content: "";
44
+ }
45
+ blockquote, q {
46
+ quotes: "" "";
47
+ }
48
+
49
+ /* Other Stuff */
50
+
51
+ body {
52
+ background: #222;
53
+ }
54
+
55
+ #container {
56
+ width: 640px;
57
+ margin: 2em auto;
58
+ padding: 1em;
59
+ background: #FFF;
60
+ -moz-border-radius: 0.5em;
61
+ -webkit-border-radius: 0.5em;
62
+ border-radius: 0.5em;
63
+ }
64
+
65
+ #header {
66
+ text-align: center;
67
+ margin: 0.5em 0 1em;
68
+ }
69
+
70
+ #header h1 {
71
+ font-size: 2em;
72
+ font-weight: bold;
73
+ }
74
+
75
+ #header h1 a {
76
+ text-decoration: none;
77
+ color: #000;
78
+ }
79
+
80
+ #footer {
81
+ color: #777;
82
+ text-align: center;
83
+ margin: 1em 0 0;
84
+ }
85
+
86
+ .section {
87
+ margin: 0.5em 0 1.5em;
88
+ }
89
+
90
+ .section h2 {
91
+ padding: 0.5em;
92
+ text-transform: uppercase;
93
+ background: #EEE;
94
+ border-top: 0.1em solid #999;
95
+ border-bottom: 0.1em solid #999;
96
+ font-weight: bold;
97
+ font-size: 1.25em;
98
+ color: #333;
99
+ }
100
+
101
+ .section h2 a {
102
+ text-decoration: none;
103
+ color: #233967;
104
+ margin-left: 0.15em;
105
+ }
106
+
107
+ form {
108
+ background: #FDFFE9;
109
+ border: 0.5em solid #F0EBD4;
110
+ padding: 0.5em;
111
+ margin: 1em;
112
+ }
113
+
114
+ .hidden {
115
+ display: none;
116
+ }
117
+
118
+ form .row {
119
+ margin: 0 0.5em 0.5em;
120
+ line-height: 1.8em;
121
+ display: inline-block;
122
+ display: block;
123
+ }
124
+
125
+ form .row:after {
126
+ clear: both;
127
+ content: '.';
128
+ display: block;
129
+ visibility: hidden;
130
+ height: 0;
131
+ }
132
+
133
+ form .row label {
134
+ display: block;
135
+ float: left;
136
+ zoom: 1;
137
+ width: 30%;
138
+ font-weight: bold;
139
+ font-size: 1.1em;
140
+ padding-top: 0.15em;
141
+ }
142
+
143
+ form .row input, form .row textarea {
144
+ font-size: 1.1em;
145
+ padding: 0.25em;
146
+ border: 0.15em solid #AAA;
147
+ }
148
+
149
+ form .row input {
150
+ width: 60%;
151
+ }
152
+
153
+ form .row input:focus, form .row textarea:focus {
154
+ border-color: #3E5299;
155
+ }
156
+
157
+ form .row p.hint {
158
+ color: #24813D;
159
+ padding-left: 30%;
160
+ }
161
+
162
+ form .buttons {
163
+ text-align: center;
164
+ padding: 0.75em;
165
+ }
166
+
167
+ form .buttons a {
168
+ text-decoration: none;
169
+ color: #204B99;
170
+ }
171
+
172
+ div.message {
173
+ font-size: 1.2em;
174
+ text-align: center;
175
+ padding: 0.5em 1em 1.5em;
176
+ color: #DE701E;
177
+ }
178
+
179
+ /* Listings */
180
+
181
+ .section ul {
182
+ line-height: 1.8em;
183
+ margin: 0.5em 1em;
184
+ font-family: Helvetica, Arial, Sans-Serif;
185
+ }
186
+
187
+ .section ul li {
188
+ padding: 0.5em 0;
189
+ color: #333;
190
+ }
191
+
192
+ .section ul li span.tag {
193
+ display: inline-block;
194
+ width: 4em;
195
+ color: white;
196
+ background: #666;
197
+ font-size: 0.65em;
198
+ text-transform: uppercase;
199
+ font-weight: bold;
200
+ text-align: center;
201
+ padding: 0 0.5em;
202
+ margin-right: 0.5em;
203
+ -moz-border-radius: 0.6em;
204
+ -webkit-border-radius: 0.6em;
205
+ font-family: Helvetica, Arial, Sans-Serif;
206
+ }
207
+
208
+ #users .tag.admin {
209
+ background: #163F10;
210
+ }
211
+
212
+ #users .tag.user {
213
+ background: #141A3F;
214
+ }
215
+
216
+ #repositories .tag.repo {
217
+ background: #720E12;
218
+ }
219
+
220
+ #groups .tag.group {
221
+ background: #17768A;
222
+ }
223
+
224
+ .section ul li a, #repository-details a {
225
+ text-decoration: none;
226
+ color: #395F99;
227
+ }
228
+
229
+ /* View Stuff */
230
+
231
+ .view h2 {
232
+ margin: 0 0 1em;
233
+ text-align: center;
234
+ font-weight: bold;
235
+ font-size: 1.3em;
236
+ color: #333;
237
+ border-top: 0.1em solid #DDD;
238
+ border-bottom: 0.1em solid #DDD;
239
+ padding: 0.5em;
240
+ }
241
+
242
+ .view h3 {
243
+ margin: 0.5em 1em;
244
+ font-weight: bold;
245
+ color: #555;
246
+ font-size: 1.2em;
247
+ }
248
+
249
+ .view ul {
250
+ margin: 0.5em 2em;
251
+ line-height: 1.8em;
252
+ font-size: 1.1em;
253
+ list-style: disc inside;
254
+ }
255
+
256
+ .view ul li {
257
+ }
258
+
259
+ .view ul li.empty {
260
+ color: #4A5258;
261
+ }
262
+
263
+ br.clear { clear: both; }
264
+
265
+ .view ul li a {
266
+ text-decoration: none;
267
+ color: #416999;
268
+ }
269
+
270
+ #repository-details {
271
+ line-height: 1.8em;
272
+ padding: 0.5em 1em;
273
+ margin-bottom: 2em;
274
+ }
275
+
276
+ #repository-details h3 {
277
+ font-weight: bold;
278
+ font-size: 1.1em;
279
+ text-align: center;
280
+ margin-bottom: 0.75em;
281
+ color: #C55E25;
282
+ }
283
+
284
+ #repository-details code {
285
+ display: block;
286
+ white-space: pre;
287
+ padding: 0.5em;
288
+ font-family: Consolas, Lucida Console, Monaco, monospace;
289
+ background: #F4F4F4;
290
+ margin: 0.25em 0;
291
+ }
292
+
293
+ #error-container {
294
+ padding: 1em 3em 1.5em;
295
+ }
296
+
297
+ #error-container h2 {
298
+ font-size: 1.5em;
299
+ text-align: center;
300
+ font-weight: bold;
301
+ padding: 0 0 0.5em;
302
+ color: red;
303
+ }
304
+
305
+ #error-container p {
306
+ font-size: 1.2em;
307
+ line-height: 1.5em;
308
+ color: #222;
309
+ text-align: center;
310
+ }
311
+
312
+ #error-container p code {
313
+ font-style: italic;
314
+ color: black;
315
+ font-weight: bold;
316
+ }