Class: Superhosting::Controller::User

Inherits:
Base
  • Object
show all
Defined in:
lib/superhosting/controller/user.rb

Constant Summary collapse

USER_NAME_FORMAT =
/^[a-zA-Z][-a-zA-Z0-9_]{,31}$/

Instance Attribute Summary

Attributes inherited from Base

#config, #lib

Instance Method Summary collapse

Methods inherited from Base

#repair

Methods inherited from Base

#get_base_controller_options, #get_controller

Methods included from Helpers

#instance_variables_to_hash

Methods included from Helper::Config

#_config, #_config_options, #_save_registry!, #apply, #configure, #configure_with_apply, #reconfig, #unapply, #unconfigure, #unconfigure_with_unapply

Methods included from Helper::Cmd

#_command, #_command_without_debug, #command, #command!

Methods included from Helper::File

#chmod!, #chown!, #chown_r!, #safe_link!, #safe_unlink!

Methods included from Helper::Logger

#__debug, #__dry_run, #__dry_run=, #__logger, #__logger=, #debug, #debug_block, #debug_operation, #indent, #indent=, #indent_reset, #indent_step, #indent_step_back, #info, #storage, #t, #with_dry_run, #with_indent, #with_logger

Constructor Details

#initialize(**kwargs) ⇒ User

Returns a new instance of User.



6
7
8
9
# File 'lib/superhosting/controller/user.rb', line 6

def initialize(**kwargs)
  super(**kwargs)
  @container_controller = self.get_controller(Container)
end

Instance Method Details

#_add(name:, container_name:, shell: '/usr/sbin/nologin', home_dir: "/web/#{container_name}") ⇒ Object



83
84
85
86
# File 'lib/superhosting/controller/user.rb', line 83

def _add(name:, container_name:, shell: '/usr/sbin/nologin', home_dir: "/web/#{container_name}")
  user = self._get(name: container_name)
  self._add_custom(name: "#{container_name}_#{name}", group: container_name, shell: shell, home_dir: home_dir, uid: user.uid)
end

#_add_custom(name:, group:, shell: '/usr/sbin/nologin', home_dir: "/web/#{group}", uid: nil) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/superhosting/controller/user.rb', line 92

def _add_custom(name:, group:, shell: '/usr/sbin/nologin', home_dir: "/web/#{group}", uid: nil)
  if (resp = self.adding_validation(name: name, container_name: group)).net_status_ok?
    container_lib_mapper = @lib.containers.f(group)
    passwd_mapper = container_lib_mapper.config.f('etc-passwd')

    useradd_command = "useradd #{name} -g #{group} -d #{home_dir} -s #{shell}".split
    useradd_command += "-u #{uid} -o".split unless uid.nil?
    self.command!(useradd_command, debug: false)

    user = self._get(name: name)

    self.with_dry_run do |dry_run|
      user_gid, user_uid = dry_run ? ['XXXX', 'XXXX'] : [user.gid, user.uid]
      passwd_mapper.append_line!("#{name}:x:#{user_uid}:#{user_gid}::#{home_dir}:#{shell}")
    end
  end
  resp
end

#_add_system_user(name:, container_name:, shell: '/usr/sbin/nologin', home_dir: "/web/#{container_name}") ⇒ Object



88
89
90
# File 'lib/superhosting/controller/user.rb', line 88

def _add_system_user(name:, container_name:, shell: '/usr/sbin/nologin', home_dir: "/web/#{container_name}")
  self._add_custom(name: "#{container_name}_#{name}", group: container_name, shell: shell, home_dir: home_dir)
end

#_create_password(generate: false) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/superhosting/controller/user.rb', line 141

def _create_password(generate: false)
  password = if generate
    SecureRandom.hex
  else
    while 1
      if (pass = ask('Enter password: ') { |q| q.echo = false }) != ask('Repeat password: ') { |q| q.echo = false }
        self.info('Passwords does not match')
      elsif !StrongPassword::StrengthChecker.new(pass).is_strong?(min_entropy: @config.f('password_strength', default: '15').to_i)
        self.info('Password is weak')
      else
        break
      end
    end
    pass
  end
  encrypted_password = UnixCrypt::SHA512.build(password)
  { password: password, encrypted_password: encrypted_password }
end

#_del(name:) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/superhosting/controller/user.rb', line 130

def _del(name:)
  self.debug_operation(desc: { code: :user, data: { name: name } }) do |&blk|
    self.with_dry_run do |dry_run|
      resp = {}
      resp = self.command!("userdel #{name}", debug: false) unless dry_run
      blk.call(code: :deleted)
      resp
    end
  end
end

#_get(name:) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/superhosting/controller/user.rb', line 75

def _get(name:)
  begin
    Etc.getpwnam(name)
  rescue ArgumentError => e
    nil
  end
end

#_group_add(name:) ⇒ Object



179
180
181
182
183
184
185
186
187
188
# File 'lib/superhosting/controller/user.rb', line 179

def _group_add(name:)
  self.debug_operation(desc: { code: :group, data: { name: name } }) do |&blk|
    self.with_dry_run do |dry_run|
      resp = {}
      resp = self.command!("groupadd #{name}", debug: false) unless dry_run
      blk.call(code: :added)
      resp
    end
  end
end

#_group_del(name:) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/superhosting/controller/user.rb', line 194

def _group_del(name:)
  self.debug_operation(desc: { code: :group, data: { name: name } }) do |&blk|
    self.with_dry_run do |dry_run|
      resp = {}
      resp = self.command!("groupdel #{name}", debug: false) unless dry_run
      blk.call(code: :deleted)
      resp
    end
  end
end

#_group_del_users(name:) ⇒ Object



235
236
237
# File 'lib/superhosting/controller/user.rb', line 235

def _group_del_users(name:)
  self._group_get_users_names(name: name).each {|user| self._del(name: user) }
end

#_group_get(name:) ⇒ Object



171
172
173
174
175
176
177
# File 'lib/superhosting/controller/user.rb', line 171

def _group_get(name:)
  begin
    Etc.getgrnam(name)
  rescue ArgumentError => e
    nil
  end
end

#_group_get_system_users(name:) ⇒ Object



227
228
229
230
231
232
233
# File 'lib/superhosting/controller/user.rb', line 227

def _group_get_system_users(name:)
  if (base_user = self._get(name: name))
    self._group_get_users(name: name).map {|u| u.name.slice(/(?<=#{name}_).*/) if u.uid != base_user.uid }.compact
  else
    []
  end
end

#_group_get_users(name:) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/superhosting/controller/user.rb', line 209

def _group_get_users(name:)
  if (group = self._group_get(name: name))
    gid = group.gid

    users = []
    Etc.passwd do |user|
      users << user if user.gid == gid
    end
    users
  else
    []
  end
end

#_group_get_users_names(name:) ⇒ Object



223
224
225
# File 'lib/superhosting/controller/user.rb', line 223

def _group_get_users_names(name:)
  self._group_get_users(name: name).map(&:name)
end

#_group_pretty_add(name:) ⇒ Object



190
191
192
# File 'lib/superhosting/controller/user.rb', line 190

def _group_pretty_add(name:)
  self._group_add(name: name) if self._group_get(name: name).nil?
end

#_group_pretty_del(name:) ⇒ Object



205
206
207
# File 'lib/superhosting/controller/user.rb', line 205

def _group_pretty_del(name:)
  self._group_del(name: name) unless self._group_get(name: name).nil?
end

#_list(container_name:) ⇒ Object



19
20
21
# File 'lib/superhosting/controller/user.rb', line 19

def _list(container_name:)
  self._group_get_users_names(name: container_name)
end

#_pretty_add_custom(name:, group:, shell: '/usr/sbin/nologin', home_dir: "/web/#{group}", uid: nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/superhosting/controller/user.rb', line 111

def _pretty_add_custom(name:, group:, shell: '/usr/sbin/nologin', home_dir: "/web/#{group}", uid: nil)
  self.debug_operation(desc: { code: :user, data: { name: name } }) do |&blk|
    if self._get(name: name)
      blk.call(code: :ok)
      {}
    else
      self._add_custom(name: name, group: group, shell: shell, home_dir: home_dir, uid: uid).tap do
        blk.call(code: :added)
      end
    end
  end
end

#_pretty_del(name:, group:) ⇒ Object



124
125
126
127
128
# File 'lib/superhosting/controller/user.rb', line 124

def _pretty_del(name:, group:)
  with_adding_group = self._group_get_users(name: group).one? ? true : false
  self._del(name: name)
  self._group_add(name: group) if with_adding_group
end

#_update_password(name:, encrypted_password:) ⇒ Object



160
161
162
163
164
165
166
167
168
169
# File 'lib/superhosting/controller/user.rb', line 160

def _update_password(name:, encrypted_password:)
  self.debug_operation(desc: { code: :user, data: { name: name } }) do |&blk|
    self.with_dry_run do |dry_run|
      resp = {}
      resp = self.command!("usermod -p '#{encrypted_password}' #{name}", debug: false) unless dry_run
      blk.call(code: :updated)
      resp
    end
  end
end

#add(name:, container_name:, ftp_dir: nil, ftp_only: false, generate: false) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/superhosting/controller/user.rb', line 23

def add(name:, container_name:, ftp_dir: nil, ftp_only: false, generate: false)
  return { error: :logical_error, code: :option_ftp_only_is_required } if ftp_dir and !ftp_only

  web_mapper = PathMapper.new("/web/#{container_name}")
  home_dir = ftp_dir.nil? ? web_mapper.path : web_mapper.f(ftp_dir).path

  if (resp = @container_controller.available_validation(name: container_name)).net_status_ok?
    if !File.exists? home_dir
      resp = { error: :logical_error, code: :incorrect_ftp_dir, data: { dir: home_dir.to_s } }
    elsif (resp = self.not_existing_validation(name: name, container_name: container_name)).net_status_ok?
      shell = ftp_only ? '/usr/sbin/nologin' : '/bin/bash'
      if (resp = self._add(name: name, container_name: container_name, home_dir: home_dir, shell: shell)).net_status_ok?
        if generate
          resp = self.passwd(name: name, container_name: container_name, generate: generate)
        end
      end
    end
  end
  resp
end

#adding_validation(name:, container_name:) ⇒ Object



239
240
241
242
# File 'lib/superhosting/controller/user.rb', line 239

def adding_validation(name:, container_name:)
  return { error: :input_error, code: :invalid_user_name, data: { name: name, regex: USER_NAME_FORMAT } } if name !~ USER_NAME_FORMAT
  self.not_existing_validation(name: name, container_name: container_name)
end

#change(name:, container_name:, ftp_dir: nil, ftp_only: false, generate: false) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/superhosting/controller/user.rb', line 67

def change(name:, container_name:, ftp_dir: nil, ftp_only: false, generate: false)
  if (resp = self.delete(name: name, container_name: container_name)).net_status_ok?
    self.add(name: name, container_name: container_name, ftp_dir: ftp_dir, ftp_only: ftp_only, generate: generate)
  else
    resp
  end
end

#delete(name:, container_name:) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/superhosting/controller/user.rb', line 55

def delete(name:, container_name:)
  if (resp = @container_controller.available_validation(name: container_name)).net_status_ok? and
      (resp = self.existing_validation(name: name, container_name: container_name)).net_status_ok?
    container_lib_mapper = @lib.containers.f(container_name)
    passwd_mapper = container_lib_mapper.config.f('etc-passwd')
    user_name = "#{container_name}_#{name}"
    self._del(name: user_name)
    passwd_mapper.remove_line!(/^#{user_name}:.*/)
  end
  resp
end

#existing_validation(name:, container_name:) ⇒ Object



244
245
246
247
# File 'lib/superhosting/controller/user.rb', line 244

def existing_validation(name:, container_name:)
  user_name = "#{container_name}_#{name}"
  PathMapper.new('/etc/passwd').check(user_name) ? {} : { error: :logical_error, code: :user_does_not_exists, data: { name: user_name } }
end

#list(container_name:) ⇒ Object



11
12
13
14
15
16
17
# File 'lib/superhosting/controller/user.rb', line 11

def list(container_name:)
  if (resp = @container_controller.available_validation(name: container_name)).net_status_ok?
    { data: self._list(container_name: container_name) }
  else
    resp
  end
end

#not_existing_validation(name:, container_name:) ⇒ Object



249
250
251
# File 'lib/superhosting/controller/user.rb', line 249

def not_existing_validation(name:, container_name:)
  self.existing_validation(name: name, container_name: container_name).net_status_ok? ? { error: :logical_error, code: :user_exists, data: { name: "#{container_name}_#{name}" } } : {}
end

#passwd(name:, container_name:, generate: false) ⇒ Object



44
45
46
47
48
49
50
51
52
53
# File 'lib/superhosting/controller/user.rb', line 44

def passwd(name:, container_name:, generate: false)
  if (resp = @container_controller.available_validation(name: container_name)).net_status_ok?
    user_name = "#{container_name}_#{name}"
    passwords = self._create_password(generate: generate)
    self._update_password(name: user_name, encrypted_password: passwords[:encrypted_password])
    generate ? { data: passwords[:password] } : {}
  else
    resp
  end
end