simple-unix-users 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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simple-unix-users.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Keith R. Bennett
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # SimpleUnixUsers
2
+
3
+ Reads and parses user information from /etc/passwd or a specified
4
+ filespec, and provides simple operations on the collection of users,
5
+ and individual users.
6
+
7
+ This code was written as an example of something Ruby could be useful
8
+ for when administering a Unix system.
9
+
10
+ It's just a starting point, and lacks necessary error checking and
11
+ polish.
12
+
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'simple-unix-users'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install simple-unix-users
27
+ :w
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ require 'simple-unix-users'
33
+
34
+ users = Users.new
35
+ # or
36
+ users = Users.new('my-test-passwd-file')
37
+ ```
38
+
39
+ Then you can use the services provided by the Users and User classes.
40
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ require "simple-unix-users/version"
2
+
3
+ if /darwin/ === RUBY_PLATFORM
4
+ $stderr.puts "
5
+
6
+ A message from the simple-unix-users gem...
7
+
8
+ Although simple-unix-users will read a passwd file on Mac OS,
9
+ it is not guaranteed to work correctly. In addition, according to the Mac's
10
+ /etc/passwd file:
11
+
12
+ # Note that this file is consulted directly only when the system is running
13
+ # in single-user mode. At other times this information is provided by
14
+ # Open Directory.
15
+
16
+ "
17
+ end
18
+
19
+ module SimpleUnixUsers
20
+ require_relative 'simple-unix-users/user'
21
+ require_relative 'simple-unix-users/users'
22
+ end
@@ -0,0 +1,40 @@
1
+ # This class is for illustrative purposes and lacks necessary error handling.
2
+
3
+ # Stores state, and provides some useful behavior, relating to a given user.
4
+ class User
5
+
6
+ attr_accessor :name, :dummy_pw, :uid, :gid, :personal_data, :home_dir, :shell
7
+
8
+ NULL_SHELL = '/bin/false'
9
+ NULL_HOME_DIR = '/nonexistent'
10
+
11
+ def initialize(line)
12
+ @name, @dummy_pw, @uid, @gid, p_data, @home_dir, @shell = line.chomp.split(':')
13
+ @personal_data = p_data.split(',')
14
+ end
15
+
16
+ def uid_number
17
+ uid.to_i
18
+ end
19
+
20
+ def gid_number
21
+ gid.to_i
22
+ end
23
+
24
+ def home_dir_size_in_mb
25
+ `du -sm #{home_dir}`.to_i
26
+ end
27
+
28
+ def has_shell?
29
+ shell != NULL_SHELL
30
+ end
31
+
32
+ def has_home_dir?
33
+ home_dir != NULL_HOME_DIR
34
+ end
35
+
36
+ def groups
37
+ `groups #{name}`.chomp.split(':').last.strip.split(' ')
38
+ end
39
+
40
+ end
@@ -0,0 +1,78 @@
1
+ require_relative 'user'
2
+
3
+ # This class is for illustrative purposes and lacks necessary error handling.
4
+
5
+ # Manages a collection of users (instances of class 'User'),
6
+ # optionally loaded from /etc/passwd.
7
+ class Users < Array
8
+
9
+ # Reads the user information from the passwd file, and returns
10
+ # a Users instance.
11
+ def self.from_passwd_file(filespec = '/etc/passwd')
12
+ file_lines = File.readlines(filespec)
13
+ non_comment_lines = file_lines.reject { |line| /^#/ === line }
14
+ Users.new(non_comment_lines)
15
+ end
16
+
17
+ # Constructor; takes an array of passwd-formatted lines, or
18
+ # User instances, or any combination thereof.
19
+ def initialize(array)
20
+ array.each do |element|
21
+ user = element.is_a?(String) ? User.new(element) : element
22
+ self << user
23
+ end
24
+ end
25
+
26
+ # Methods that will return arrays of field objects (e.g. names).
27
+ def names; self.map(&:name) end
28
+ def uids; self.map(&:uid) end
29
+ def gids; self.map(&:gid) end
30
+ def personal_datas; self.map(&:personal_data) end
31
+ def home_dirs; self.map(&:home_dir) end
32
+ def shells; self.map(&:shell) end
33
+
34
+ def uid_numbers; self.map(&:uid_number) end
35
+ def gid_numbers; self.map(&:gid_number) end
36
+
37
+ # Returns a new instance of Users containing only those users
38
+ # whose shell is not '/bin/false'.
39
+ def having_shell
40
+ Users.new(select { |user| user.has_shell? })
41
+ end
42
+
43
+ def having_shell_of(shell)
44
+ Users.new(select { |user| user.shell == shell })
45
+ end
46
+
47
+ def not_having_shell
48
+ Users.new(self - having_shell)
49
+ end
50
+
51
+ def having_home_dir
52
+ Users.new(select { |user| user.has_home_dir? })
53
+ end
54
+
55
+ def not_having_home_dir
56
+ Users.new(select { |user| ! user.has_home_dir? })
57
+ # or, less efficiently: Users.new(self - having_home_dir)
58
+ end
59
+
60
+ # Returns a new Users instance consisting only of
61
+ # those users having the specified group id.
62
+ def having_gid(gid)
63
+ gid = (gid.is_a?(Fixnum) ? gid.to_s : gid)
64
+ filtered_array = (select { |user| user.gid == gid })
65
+ Users.new(filtered_array)
66
+ end
67
+
68
+ def find_by_name(name)
69
+ detect { |user| user.name == name }
70
+ end
71
+
72
+ def find_by_uid(uid)
73
+ uid = uid.is_a?(String) ? uid : uid.to_s
74
+ detect { |user| user.uid == uid }
75
+ end
76
+ end
77
+
78
+
@@ -0,0 +1,3 @@
1
+ module SimpleUnixUsers
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple-unix-users/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "simple-unix-users"
8
+ gem.version = SimpleUnixUsers::VERSION
9
+ gem.authors = ["Keith R. Bennett"]
10
+ gem.email = ["keithrbennett@gmail.com"]
11
+ gem.description = %q{
12
+ Reads and parses user information from /etc/passwd or a specified
13
+ filespec, and provides simple operations on the collection of users,
14
+ and individual users.
15
+ }
16
+ gem.summary = %q{Manages Unix user information based on the content of /etc/passwd.}
17
+ gem.homepage = "https://github.com/keithrbennett/simple-unix-users"
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = ["lib"]
23
+ end
@@ -0,0 +1,38 @@
1
+ root:x:0:0:root:/root:/bin/bash
2
+ daemon:x:1:1:daemon:/usr/sbin:/bin/sh
3
+ bin:x:2:2:bin:/bin:/bin/sh
4
+ sys:x:3:3:sys:/dev:/bin/sh
5
+ sync:x:4:65534:sync:/bin:/bin/sync
6
+ games:x:5:60:games:/usr/games:/bin/sh
7
+ man:x:6:12:man:/var/cache/man:/bin/sh
8
+ lp:x:7:7:lp:/var/spool/lpd:/bin/sh
9
+ mail:x:8:8:mail:/var/mail:/bin/sh
10
+ news:x:9:9:news:/var/spool/news:/bin/sh
11
+ uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
12
+ proxy:x:13:13:proxy:/bin:/bin/sh
13
+ www-data:x:33:33:www-data:/var/www:/bin/sh
14
+ backup:x:34:34:backup:/var/backups:/bin/sh
15
+ list:x:38:38:Mailing List Manager:/var/list:/bin/sh
16
+ irc:x:39:39:ircd:/var/run/ircd:/bin/sh
17
+ gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
18
+ nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
19
+ libuuid:x:100:101::/var/lib/libuuid:/bin/sh
20
+ syslog:x:101:103::/home/syslog:/bin/false
21
+ messagebus:x:102:105::/var/run/dbus:/bin/false
22
+ colord:x:103:108:colord colour management daemon,,,:/var/lib/colord:/bin/false
23
+ whoopsie:x:105:114::/nonexistent:/bin/false
24
+ avahi-autoipd:x:106:117:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false
25
+ avahi:x:107:118:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
26
+ usbmux:x:108:46:usbmux daemon,,,:/home/usbmux:/bin/false
27
+ kernoops:x:109:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
28
+ pulse:x:110:119:PulseAudio daemon,,,:/var/run/pulse:/bin/false
29
+ rtkit:x:111:122:RealtimeKit,,,:/proc:/bin/false
30
+ speech-dispatcher:x:112:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
31
+ hplip:x:113:7:HPLIP system user,,,:/var/run/hplip:/bin/false
32
+ saned:x:114:123::/home/saned:/bin/false
33
+ haldaemon:x:115:125:Hardware abstraction layer,,,:/var/run/hald:/bin/false
34
+ mdm:x:116:128:MDM Display Manager:/var/lib/mdm:/bin/false
35
+ kbennett:x:1000:1000:Keith Bennett,,,:/home/kbennett:/usr/bin/zsh
36
+ sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
37
+ mysql:x:117:129:MySQL Server,,,:/nonexistent:/bin/false
38
+ postgres:x:118:130:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
@@ -0,0 +1,41 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../../lib/simple-unix-users/user'
4
+
5
+ describe User do
6
+
7
+ subject { User.new( 'kbennett:x:1000:1000:Keith Bennett,,,:/home/kbennett:/usr/bin/zsh') }
8
+
9
+ it 'should create correctly from the passwd line' do
10
+ subject.class.should == User
11
+ end
12
+
13
+ it 'should create fields correctly' do
14
+ subject.name.should == 'kbennett'
15
+ subject.uid.should == '1000'
16
+ subject.gid.should == '1000'
17
+ subject.personal_data.first.should == 'Keith Bennett'
18
+ subject.home_dir.should == '/home/kbennett'
19
+ subject.shell.should == '/usr/bin/zsh'
20
+ end
21
+
22
+ it 'should detect an existing home correctly' do
23
+ subject.has_home_dir?.should be_true
24
+ end
25
+
26
+ it 'should detect a nonexistent home correctly' do
27
+ subject.home_dir = User::NULL_HOME_DIR
28
+ subject.has_home_dir?.should be_false
29
+ end
30
+
31
+ it 'should calculate uid_number correctly' do
32
+ subject.uid_number.should == subject.uid.to_i
33
+ end
34
+
35
+ it 'should calculate gid_number correctly' do
36
+ subject.gid_number.should == subject.gid.to_i
37
+ end
38
+
39
+ end
40
+
41
+
@@ -0,0 +1,79 @@
1
+ require 'rspec'
2
+
3
+ require_relative '../../lib/simple-unix-users/users.rb'
4
+
5
+ describe Users do
6
+
7
+ subject { Users.from_passwd_file(File.join(File.dirname(__FILE__), 'passwd-sample')) }
8
+
9
+ it 'should load a list of users' do
10
+ subject.should be_a Array
11
+ subject.should_not be_empty
12
+ end
13
+
14
+ it 'should return a list of names for the names function' do
15
+ names = subject.names.sort
16
+ names.sort.uniq.size.should > 1
17
+ end
18
+
19
+ it 'should be able to get uids as numbers' do
20
+ uid_numbers = subject.uid_numbers
21
+ uid_numbers.should_not be_empty
22
+ uid_numbers.first.should be_a(Fixnum)
23
+ end
24
+
25
+ it 'should be able to get gids as numbers' do
26
+ gid_numbers = subject.gid_numbers
27
+ gid_numbers.should_not be_empty
28
+ gid_numbers.first.should be_a(Fixnum)
29
+ end
30
+
31
+ it 'should be able to get the field objects arrays' do
32
+ [:names, :uids, :gids, :personal_datas, :home_dirs, :shells].each do |field|
33
+ array = subject.send(field)
34
+ array.size.should == subject.size
35
+ end
36
+ end
37
+
38
+ it 'should calculate having_shell correctly' do
39
+ num_with_shell = subject.inject(0) do |num, user|
40
+ num += 1 if user.has_shell?
41
+ num
42
+ end
43
+ subject.having_shell.size.should == num_with_shell
44
+ subject.not_having_shell.size.should == (subject.size - num_with_shell)
45
+ end
46
+
47
+ it 'should correctly include users in having_shell_of' do
48
+ first_user = subject.first
49
+ subject.having_shell_of(first_user.shell).should include(first_user)
50
+ subject.having_shell_of('ja;ksdfja;sdfkajsdf;k').should_not include(first_user)
51
+ end
52
+
53
+ it 'should correctly include users in having_home and not_having_home' do
54
+ user_with_home_dir = subject.detect { |user| user.has_home_dir? }
55
+ subject.having_home_dir.should include(user_with_home_dir)
56
+ subject.not_having_home_dir.should_not include(user_with_home_dir)
57
+ end
58
+
59
+ it 'should correctly find users with having_gid' do
60
+ first_gid = subject.first.gid
61
+ having_first_gid = subject.having_gid(first_gid)
62
+ having_first_gid.should include(subject.first)
63
+
64
+ first_user_with_different_gid = subject.detect { |user| user.gid != first_gid }
65
+ having_first_gid.should_not include(first_user_with_different_gid)
66
+ end
67
+
68
+ it 'should find_by_name correctly' do
69
+ last_user = subject.last
70
+ subject.find_by_name(last_user.name).should == last_user
71
+ end
72
+
73
+ it 'should find_by_uid correctly' do
74
+ last_user = subject.last
75
+ subject.find_by_uid(last_user.uid).should == last_user
76
+ end
77
+
78
+ end
79
+
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-unix-users
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Keith R. Bennett
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-15 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "\nReads and parses user information from /etc/passwd or a specified\nfilespec,
15
+ and provides simple operations on the collection of users,\nand individual users.\n "
16
+ email:
17
+ - keithrbennett@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - lib/simple-unix-users.rb
28
+ - lib/simple-unix-users/user.rb
29
+ - lib/simple-unix-users/users.rb
30
+ - lib/simple-unix-users/version.rb
31
+ - simple-unix-users.gemspec
32
+ - spec/simple-unix-users/passwd-sample
33
+ - spec/simple-unix-users/user_spec.rb
34
+ - spec/simple-unix-users/users_spec.rb
35
+ homepage: https://github.com/keithrbennett/simple-unix-users
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 1.8.24
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Manages Unix user information based on the content of /etc/passwd.
59
+ test_files:
60
+ - spec/simple-unix-users/passwd-sample
61
+ - spec/simple-unix-users/user_spec.rb
62
+ - spec/simple-unix-users/users_spec.rb