brownbeagle-gitauth 0.0.1 → 0.0.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/README.rdoc +11 -1
- data/bin/gitauth +100 -24
- data/bin/gitauth-shell +2 -32
- data/lib/gitauth/client.rb +17 -19
- data/lib/gitauth/command.rb +2 -2
- data/lib/gitauth/group.rb +86 -0
- data/lib/gitauth/repo.rb +43 -40
- data/lib/gitauth/saveable_class.rb +60 -0
- data/lib/gitauth/{users.rb → user.rb} +35 -31
- data/lib/gitauth/web_app.rb +230 -0
- data/lib/gitauth.rb +29 -5
- data/public/gitauth.css +264 -0
- data/public/gitauth.js +17 -0
- data/public/jquery.js +19 -0
- data/views/group.erb +24 -0
- data/views/index.erb +80 -0
- data/views/layout.erb +27 -0
- data/views/repo.erb +56 -0
- data/views/user.erb +51 -0
- metadata +26 -5
@@ -18,41 +18,20 @@
|
|
18
18
|
|
19
19
|
|
20
20
|
module GitAuth
|
21
|
-
class
|
22
|
-
|
23
|
-
USERS_PATH = File.join(GitAuth::GITAUTH_DIR, "users.yml")
|
24
|
-
|
25
|
-
def self.all
|
26
|
-
@@all_users ||= nil
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.load!
|
30
|
-
self.all = YAML.load_file(USERS_PATH) rescue nil if File.exist?(USERS_PATH)
|
31
|
-
self.all = [] unless self.all.is_a?(Array)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.save!
|
35
|
-
load! if self.all.nil?
|
36
|
-
File.open(USERS_PATH, "w+") do |f|
|
37
|
-
f.write self.all.to_yaml
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.all=(value)
|
42
|
-
@@all_users = value
|
43
|
-
end
|
44
|
-
|
21
|
+
class User < SaveableClass(:users)
|
22
|
+
|
45
23
|
def self.get(name)
|
46
24
|
GitAuth.logger.debug "Getting user for the name '#{name}'"
|
47
25
|
self.all.detect { |r| r.name == name }
|
48
26
|
end
|
49
27
|
|
50
28
|
def self.create(name, admin, key)
|
29
|
+
# Basic sanity checking.
|
30
|
+
return false if name.nil? || admin.nil? || key.nil?
|
31
|
+
return false unless name =~ /^([\w\_\-\.]+)$/ && !!admin == admin
|
51
32
|
user = self.new(name, admin)
|
52
33
|
if user.write_ssh_key!(key)
|
53
|
-
self.
|
54
|
-
self.all << user
|
55
|
-
self.save!
|
34
|
+
self.add_item(user)
|
56
35
|
return true
|
57
36
|
else
|
58
37
|
return false
|
@@ -66,13 +45,16 @@ module GitAuth
|
|
66
45
|
@admin = admin
|
67
46
|
end
|
68
47
|
|
48
|
+
def to_s
|
49
|
+
@name.to_s
|
50
|
+
end
|
51
|
+
|
69
52
|
def write_ssh_key!(key)
|
70
|
-
cleaned_key = clean_ssh_key(key)
|
53
|
+
cleaned_key = self.class.clean_ssh_key(key)
|
71
54
|
if cleaned_key.nil?
|
72
55
|
return false
|
73
56
|
else
|
74
|
-
|
75
|
-
output = "command=\"#{gitauth_path} #{@name}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding#{shell_accessible? ? "" : ",no-pty"} #{cleaned_key}"
|
57
|
+
output = "#{command_prefix} #{cleaned_key}"
|
76
58
|
File.open(GitAuth.settings.authorized_keys_file, "a+") do |file|
|
77
59
|
file.puts output
|
78
60
|
end
|
@@ -80,6 +62,27 @@ module GitAuth
|
|
80
62
|
end
|
81
63
|
end
|
82
64
|
|
65
|
+
def command_prefix
|
66
|
+
"command=\"#{GitAuth.settings.shell_executable} #{@name}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding#{shell_accessible? ? "" : ",no-pty"}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def destroy!
|
70
|
+
GitAuth::Repo.all.each { |r| r.remove_permissions_for(self) }
|
71
|
+
GitAuth::Group.all.each { |g| g.remove_member(self) }
|
72
|
+
# Remove the public key from the authorized_keys file.
|
73
|
+
auth_keys_path = GitAuth.settings.authorized_keys_file
|
74
|
+
if File.exist?(auth_keys_path)
|
75
|
+
contents = File.read(auth_keys_path)
|
76
|
+
contents.gsub!(/#{command_prefix} ssh-\w+ [a-zA-Z0-9\/\+]+==\r?\n?/m, "")
|
77
|
+
File.open(auth_keys_path, "w+") { |f| f.write contents }
|
78
|
+
end
|
79
|
+
self.class.all.reject! { |u| u == self }
|
80
|
+
# Finally, save everything
|
81
|
+
self.class.save!
|
82
|
+
GitAuth::Repo.save!
|
83
|
+
GitAuth::Group.save!
|
84
|
+
end
|
85
|
+
|
83
86
|
def admin?
|
84
87
|
!!@admin
|
85
88
|
end
|
@@ -107,7 +110,7 @@ module GitAuth
|
|
107
110
|
end
|
108
111
|
end
|
109
112
|
|
110
|
-
def clean_ssh_key(key)
|
113
|
+
def self.clean_ssh_key(key)
|
111
114
|
if key =~ /^(ssh-\w+ [a-zA-Z0-9\/\+]+==) .*$/
|
112
115
|
return $1
|
113
116
|
else
|
@@ -116,4 +119,5 @@ module GitAuth
|
|
116
119
|
end
|
117
120
|
|
118
121
|
end
|
122
|
+
Users = User # For Backwards Compat.
|
119
123
|
end
|
@@ -0,0 +1,230 @@
|
|
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 'sinatra'
|
20
|
+
require 'digest/sha2'
|
21
|
+
module GitAuth
|
22
|
+
class WebApp < Sinatra::Base
|
23
|
+
|
24
|
+
use Rack::Auth::Basic do |username, password|
|
25
|
+
[username, Digest::SHA256.hexdigest(password)] == [GitAuth.settings.web_username, GitAuth.settings.web_password_hash]
|
26
|
+
end
|
27
|
+
|
28
|
+
configure do
|
29
|
+
set :port, 8998
|
30
|
+
set :views, File.join(GitAuth::BASE_DIR, "views")
|
31
|
+
set :public, File.join(GitAuth::BASE_DIR, "public")
|
32
|
+
set :static, true
|
33
|
+
set :methodoverride, true
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
GitAuth.force_setup!
|
38
|
+
end
|
39
|
+
|
40
|
+
helpers do
|
41
|
+
include Rack::Utils
|
42
|
+
alias_method :h, :escape_html
|
43
|
+
|
44
|
+
def link_to(text, link)
|
45
|
+
"<a href='#{link}'>#{text}</a>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_link(text, url)
|
49
|
+
id = "deleteable-#{Digest::SHA256.hexdigest(url.to_s)[0, 6]}"
|
50
|
+
html = "<div class='deletable-container' style='display: none; margin: 0; padding: 0;'>"
|
51
|
+
html << "<form method='post' action='#{url}' id='#{id}'>"
|
52
|
+
html << "<input name='_method' type='hidden' value='delete' />"
|
53
|
+
html << "</form></div>"
|
54
|
+
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>"
|
55
|
+
return html
|
56
|
+
end
|
57
|
+
|
58
|
+
def auto_link(member)
|
59
|
+
member = member.to_s
|
60
|
+
url = (member[0] == ?@ ? "/groups/#{URI.encode(member[1..-1])}" : "/users/#{URI.encode(member)}")
|
61
|
+
return link_to(member, url)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
get '/' do
|
67
|
+
@repos = GitAuth::Repo.all
|
68
|
+
@users = GitAuth::User.all
|
69
|
+
@groups = GitAuth::Group.all
|
70
|
+
erb :index
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Listing / Index Page
|
75
|
+
|
76
|
+
get '/repos/:name' do
|
77
|
+
@repo = GitAuth::Repo.get(params[:name])
|
78
|
+
if @repo.nil?
|
79
|
+
redirect root_with_message("The given repository couldn't be found.")
|
80
|
+
else
|
81
|
+
read_perms, write_perms = (@repo.permissions[:read]||[]), (@repo.permissions[:write]||[])
|
82
|
+
@all_access = read_perms & write_perms
|
83
|
+
@read_only = read_perms - @all_access
|
84
|
+
@write_only = write_perms - @all_access
|
85
|
+
erb :repo
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
get '/users/:name' do
|
90
|
+
@user = GitAuth::User.get(params[:name])
|
91
|
+
if @user.nil?
|
92
|
+
redirect root_with_message("The given user couldn't be found.")
|
93
|
+
else
|
94
|
+
repos = GitAuth::Repo.all
|
95
|
+
read_perms = repos.select { |r| r.readable_by?(@user) }
|
96
|
+
write_perms = repos.select { |r| r.writeable_by?(@user) }
|
97
|
+
@all_access = read_perms & write_perms
|
98
|
+
@read_only = read_perms - @all_access
|
99
|
+
@write_only = write_perms - @all_access
|
100
|
+
@groups = GitAuth::Group.all.select { |g| g.member?(@user) }
|
101
|
+
erb :user
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
get '/groups/:name' do
|
106
|
+
@group = GitAuth::Group.get(params[:name])
|
107
|
+
if @group.nil?
|
108
|
+
redirect root_with_message("The given group could not be found.")
|
109
|
+
else
|
110
|
+
erb :group
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Create and update repos
|
115
|
+
|
116
|
+
post '/repos' do
|
117
|
+
name = params[:repo][:name]
|
118
|
+
path = params[:repo][:path]
|
119
|
+
path = name if path.to_s.strip.empty?
|
120
|
+
if GitAuth::Repo.create(name, path)
|
121
|
+
redirect root_with_message("Repository successfully added")
|
122
|
+
else
|
123
|
+
redirect root_with_message("There was an error adding the repository.")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
post '/repos/:name' do
|
128
|
+
repo = GitAuth::Repo.get(params[:name])
|
129
|
+
if repo.nil?
|
130
|
+
redirect root_with_message("The given repository couldn't be found.")
|
131
|
+
else
|
132
|
+
new_permissions = Hash.new([])
|
133
|
+
[:all, :read, :write].each do |k|
|
134
|
+
if params[:repo][k]
|
135
|
+
perm_lines = params[:repo][k].to_s.split("\n")
|
136
|
+
new_permissions[k] = perm_lines.map do |l|
|
137
|
+
i = GitAuth.get_user_or_group(l.strip)
|
138
|
+
i.nil? ? nil : i.to_s
|
139
|
+
end.compact
|
140
|
+
end
|
141
|
+
end
|
142
|
+
all = new_permissions.delete(:all)
|
143
|
+
new_permissions[:read] |= all
|
144
|
+
new_permissions[:write] |= all
|
145
|
+
new_permissions.each_value { |v| v.uniq! }
|
146
|
+
repo.permissions = new_permissions
|
147
|
+
GitAuth::Repo.save!
|
148
|
+
redirect "/repos/#{URI.encode(repo.name)}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
delete '/repos/:name' do
|
153
|
+
repo = GitAuth::Repo.get(params[:name])
|
154
|
+
if repo.nil?
|
155
|
+
redirect root_with_message("The given repository couldn't be found.")
|
156
|
+
else
|
157
|
+
repo.destroy!
|
158
|
+
redirect root_with_message("Repository removed.")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Create, delete and update users
|
163
|
+
|
164
|
+
post '/users' do
|
165
|
+
name = params[:user][:name]
|
166
|
+
admin = params[:user][:admin].to_s == "1"
|
167
|
+
key = params[:user][:key]
|
168
|
+
if GitAuth::User.create(name, admin, key)
|
169
|
+
redirect root_with_message("User Added")
|
170
|
+
else
|
171
|
+
redirect root_with_message("There was an error adding the requested user.")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
delete '/users/:name' do
|
176
|
+
user = GitAuth::User.get(params[:name])
|
177
|
+
if user.nil?
|
178
|
+
redirect root_with_message("The specified user couldn't be found.")
|
179
|
+
else
|
180
|
+
user.destroy!
|
181
|
+
redirect root_with_message("User removed.")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Create and Update Groups
|
186
|
+
|
187
|
+
post '/groups' do
|
188
|
+
if GitAuth::Group.create(params[:group][:name])
|
189
|
+
redirect root_with_message("Group added")
|
190
|
+
else
|
191
|
+
redirect root_with_message("There was an error adding the requested group.")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
post '/groups/:name' do
|
196
|
+
group = GitAuth::Group.get(params[:name])
|
197
|
+
if group.nil?
|
198
|
+
redirect root_with_message("The specified group couldn't be found.")
|
199
|
+
else
|
200
|
+
if params[:group][:members]
|
201
|
+
member_lines = params[:group][:members].to_s.split("\n")
|
202
|
+
group.members = member_lines.map do |l|
|
203
|
+
i = GitAuth.get_user_or_group(l.strip)
|
204
|
+
i.nil? ? nil : i.to_s
|
205
|
+
end.compact - [group.to_s]
|
206
|
+
GitAuth::Group.save!
|
207
|
+
end
|
208
|
+
redirect "/groups/#{URI.encode(group.name)}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
delete '/groups/:name' do
|
213
|
+
group = GitAuth::Group.get(params[:name])
|
214
|
+
if group.nil?
|
215
|
+
redirect root_with_message("The specified group couldn't be found.")
|
216
|
+
else
|
217
|
+
group.destroy!
|
218
|
+
redirect root_with_message("Group removed.")
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
# Misc Helpers
|
224
|
+
|
225
|
+
def root_with_message(message)
|
226
|
+
"/?message=#{URI.encode(message)}"
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
data/lib/gitauth.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (C) 2009
|
2
|
+
# Copyright (C) 2009 Brown Beagle Software
|
3
3
|
# Copyright (C) 2008 Darcy Laycock <sutto@sutto.net>
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
@@ -23,8 +23,8 @@ require 'ostruct'
|
|
23
23
|
|
24
24
|
module GitAuth
|
25
25
|
|
26
|
-
BASE_DIR
|
27
|
-
GITAUTH_DIR
|
26
|
+
BASE_DIR = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
27
|
+
GITAUTH_DIR = File.expand_path("~/.gitauth/")
|
28
28
|
|
29
29
|
def self.logger
|
30
30
|
@logger ||= ::Logger.new(File.join(GITAUTH_DIR, "gitauth.log"))
|
@@ -34,18 +34,42 @@ module GitAuth
|
|
34
34
|
@settings ||= OpenStruct.new(YAML.load_file(File.join(GITAUTH_DIR, "settings.yml")))
|
35
35
|
end
|
36
36
|
|
37
|
+
def self.reload_settings!
|
38
|
+
@settings = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.get_user_or_group(name)
|
42
|
+
return nil if name.to_s.strip.empty?
|
43
|
+
return (name =~ /^@/ ? Group : User).get(name)
|
44
|
+
end
|
45
|
+
|
37
46
|
def self.setup!
|
38
47
|
unless File.exist?(GITAUTH_DIR) && File.directory?(GITAUTH_DIR)
|
39
48
|
$stderr.puts "GitAuth not been setup, please run: gitauth install"
|
40
49
|
exit! 1
|
41
50
|
end
|
42
51
|
dir = File.expand_path(File.join(File.dirname(__FILE__), "gitauth"))
|
43
|
-
%w(repo
|
52
|
+
%w(saveable_class repo user command client group).each do |file|
|
44
53
|
require File.join(dir, file)
|
45
54
|
end
|
46
55
|
# Load the users and repositories from a YAML File.
|
47
56
|
GitAuth::Repo.load!
|
48
|
-
GitAuth::
|
57
|
+
GitAuth::User.load!
|
58
|
+
GitAuth::Group.load!
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.serve_web!
|
62
|
+
self.setup!
|
63
|
+
require File.join(File.expand_path(File.join(File.dirname(__FILE__), "gitauth")), "web_app")
|
64
|
+
GitAuth::WebApp.run!
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.force_setup!
|
68
|
+
@settings = nil
|
69
|
+
GitAuth::Repo.all = nil
|
70
|
+
GitAuth::User.all = nil
|
71
|
+
GitAuth::Group.all = nil
|
72
|
+
self.setup!
|
49
73
|
end
|
50
74
|
|
51
75
|
end
|
data/public/gitauth.css
ADDED
@@ -0,0 +1,264 @@
|
|
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
|
+
}
|
185
|
+
|
186
|
+
.section ul li {
|
187
|
+
padding: 0.5em 0;
|
188
|
+
color: #333;
|
189
|
+
}
|
190
|
+
|
191
|
+
.section ul li span.tag {
|
192
|
+
display: inline-block;
|
193
|
+
width: 4em;
|
194
|
+
color: white;
|
195
|
+
background: #666;
|
196
|
+
font-size: 0.8em;
|
197
|
+
text-transform: uppercase;
|
198
|
+
font-weight: bold;
|
199
|
+
text-align: center;
|
200
|
+
padding: 0 0.75em;
|
201
|
+
margin-right: 0.5em;
|
202
|
+
}
|
203
|
+
|
204
|
+
#users .tag.admin {
|
205
|
+
background: #163F10;
|
206
|
+
}
|
207
|
+
|
208
|
+
#users .tag.user {
|
209
|
+
background: #141A3F;
|
210
|
+
}
|
211
|
+
|
212
|
+
#repositories .tag.repo {
|
213
|
+
background: #720E12;
|
214
|
+
}
|
215
|
+
|
216
|
+
#groups .tag.group {
|
217
|
+
background: #17768A;
|
218
|
+
}
|
219
|
+
|
220
|
+
.section ul li a {
|
221
|
+
text-decoration: none;
|
222
|
+
color: #395F99;
|
223
|
+
}
|
224
|
+
|
225
|
+
/* View Stuff */
|
226
|
+
|
227
|
+
.view h2 {
|
228
|
+
margin: 0 0 1em;
|
229
|
+
text-align: center;
|
230
|
+
font-weight: bold;
|
231
|
+
font-size: 1.3em;
|
232
|
+
color: #333;
|
233
|
+
border-top: 0.1em solid #DDD;
|
234
|
+
border-bottom: 0.1em solid #DDD;
|
235
|
+
padding: 0.5em;
|
236
|
+
}
|
237
|
+
|
238
|
+
.view h3 {
|
239
|
+
margin: 0.5em 1em;
|
240
|
+
font-weight: bold;
|
241
|
+
color: #555;
|
242
|
+
font-size: 1.2em;
|
243
|
+
}
|
244
|
+
|
245
|
+
.view ul {
|
246
|
+
margin: 0.5em 2em;
|
247
|
+
line-height: 1.8em;
|
248
|
+
font-size: 1.1em;
|
249
|
+
list-style: disc inside;
|
250
|
+
}
|
251
|
+
|
252
|
+
.view ul li {
|
253
|
+
}
|
254
|
+
|
255
|
+
.view ul li.empty {
|
256
|
+
color: #4A5258;
|
257
|
+
}
|
258
|
+
|
259
|
+
br.clear { clear: both; }
|
260
|
+
|
261
|
+
.view ul li a {
|
262
|
+
text-decoration: none;
|
263
|
+
color: #416999;
|
264
|
+
}
|
data/public/gitauth.js
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$(function() {
|
2
|
+
setTimeout(function() { $(".message").slideUp("slow"); }, 7500);
|
3
|
+
});
|
4
|
+
|
5
|
+
function showForm(name)
|
6
|
+
{
|
7
|
+
$("#add-" + name + "-link").hide();
|
8
|
+
$("#add-" + name).slideDown("slow");
|
9
|
+
return false;
|
10
|
+
}
|
11
|
+
|
12
|
+
function hideForm(name)
|
13
|
+
{
|
14
|
+
$("#add-" + name + "-link").show();
|
15
|
+
$("#add-" + name).slideUp("slow");
|
16
|
+
return false;
|
17
|
+
}
|