Class: Gitolite::SSHKey

Inherits:
Object
  • Object
show all
Defined in:
lib/gitolite/ssh_key.rb

Overview

Models an SSH key within gitolite provides support for multikeys

Types of multi keys:

username: bob => <keydir>/bob/bob.pub
username: bob, location: desktop => <keydir>/bob/desktop/bob.pub

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, blob, email, owner = nil, location = "") ⇒ SSHKey

Returns a new instance of SSHKey.


104
105
106
107
108
109
110
111
# File 'lib/gitolite/ssh_key.rb', line 104

def initialize(type, blob, email, owner=nil, location = "")
  @type = type
  @blob = blob
  @email = email

  @owner = owner || email
  @location = location
end

Instance Attribute Details

#blobObject

Returns the value of attribute blob


13
14
15
# File 'lib/gitolite/ssh_key.rb', line 13

def blob
  @blob
end

#emailObject

Returns the value of attribute email


13
14
15
# File 'lib/gitolite/ssh_key.rb', line 13

def email
  @email
end

#locationObject

Returns the value of attribute location


13
14
15
# File 'lib/gitolite/ssh_key.rb', line 13

def location
  @location
end

#ownerObject

Returns the value of attribute owner


13
14
15
# File 'lib/gitolite/ssh_key.rb', line 13

def owner
  @owner
end

#typeObject

Returns the value of attribute type


13
14
15
# File 'lib/gitolite/ssh_key.rb', line 13

def type
  @type
end

Class Method Details

.delete_dir_if_empty(dir) ⇒ Object


71
72
73
74
75
76
77
# File 'lib/gitolite/ssh_key.rb', line 71

def delete_dir_if_empty(dir)
  if File.directory?(dir) && Dir["#{dir}/*"].empty?
    Dir.rmdir(dir)
  end
rescue => e
  STDERR.puts("Warning: Couldn't delete empty directory: #{e.message}")
end

.from_file(key) ⇒ Object


17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/gitolite/ssh_key.rb', line 17

def from_file(key)
  raise "#{key} does not exist!" unless File.exists?(key)

  # Owner is the basename of the key
  # i.e., <owner>/<location>/<owner>.pub
  owner = File.basename(key, ".pub")

  # Location is the middle section of the path, if any
  location = self.location_from_path(File.dirname(key), owner)

  # Use string key constructor
  self.from_string(File.read(key), owner, location)
end

.from_string(key_string, owner, location = "") ⇒ Object

Construct a SSHKey from a string


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/gitolite/ssh_key.rb', line 32

def from_string(key_string, owner, location = "")
  if owner.nil?
    raise ArgumentError, "owner was nil, you must specify an owner"
  end

  # Get parts of the key
  type, blob, email = key_string.split

  # We need at least a type or blob
  if type.nil? || blob.nil?
    raise ArgumentError, "'#{key_string}' is not a valid SSH key string"
  end

  # If the key didn't have an email, just use the owner
  if email.nil?
    email = owner
  end

  self.new(type, blob, email, owner, location)
end

.location_from_path(path, owner) ⇒ Object

Parse the key path above the key to be read. As we can omit the location, there are two possible options:

  1. Location is empty. Path is <keydir>/<owner>/

  2. Location is non-empty. Path is <keydir>/<owner>/<location>

We test this by checking the parent of the given path. If it equals owner, a location was set. This allows the daft case of e.g., using <keydir>/bob/bob/bob.pub.


62
63
64
65
66
67
68
69
# File 'lib/gitolite/ssh_key.rb', line 62

def location_from_path(path, owner)
  keyroot = File.dirname(path)
  if File.basename(keyroot) == owner
    File.basename(path)
  else
    ''
  end
end

.remove(key_file, key_dir_path) ⇒ Object

Remove a key given a relative path

Unlinks the key file and removes any empty parent directory below key_dir


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/gitolite/ssh_key.rb', line 83

def remove(key_file, key_dir_path)

  abs_key_path = File.join(key_dir_path, key_file)
  key = self.from_file(abs_key_path)

  # Remove the file itself
  File.unlink(abs_key_path)

  key_owner_dir = File.join(key_dir_path, key.owner)

  # Remove the location, if it exists and is empty
  if key.location
    self.delete_dir_if_empty(File.join(key_owner_dir, key.location))
  end

  # Remove the owner dir, if empty
  self.delete_dir_if_empty(key_owner_dir)
end

Instance Method Details

#==(key) ⇒ Object


144
145
146
147
148
149
150
# File 'lib/gitolite/ssh_key.rb', line 144

def ==(key)
  @type == key.type &&
  @blob == key.blob &&
  @email == key.email &&
  @owner == key.owner &&
  @location == key.location
end

#filenameObject


139
140
141
# File 'lib/gitolite/ssh_key.rb', line 139

def filename
  [@owner, '.pub'].join
end

#hashObject


153
154
155
# File 'lib/gitolite/ssh_key.rb', line 153

def hash
  [@owner, @location, @type, @blob, @email].hash
end

#relative_pathObject


135
136
137
# File 'lib/gitolite/ssh_key.rb', line 135

def relative_path
  File.join(@owner, @location, self.filename)
end

#to_file(path) ⇒ Object


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/gitolite/ssh_key.rb', line 119

def to_file(path)
  # Ensure multi-key directory structure
  # <keydir>/<owner>/<location?>/<owner>.pub
  key_dir  = File.join(path, @owner, @location)
  key_file = File.join(key_dir, self.filename)

  # Ensure subdirs exist
  FileUtils.mkdir_p(key_dir) unless File.directory?(key_dir)

  File.open(key_file, "w") do |f|
    f.sync = true
    f.write(self.to_s)
  end
  key_file
end

#to_sObject


114
115
116
# File 'lib/gitolite/ssh_key.rb', line 114

def to_s
  [@type, @blob, @email].join(' ')
end