class Superhosting::Controller::User

Constants

USER_NAME_FORMAT

Public Class Methods

new(**kwargs) click to toggle source
Calls superclass method Superhosting::Base::new
# File lib/superhosting/controller/user.rb, line 6
def initialize(**kwargs)
  super(**kwargs)
  @container_controller = self.get_controller(Container)
end

Public Instance Methods

_add(name:, container_name:, shell: '/usr/sbin/nologin', home_dir: "/web/ click to toggle source
# 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/ click to toggle source
# 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/ click to toggle source
# 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) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# File lib/superhosting/controller/user.rb, line 75
def _get(name:)
  begin
    Etc.getpwnam(name)
  rescue ArgumentError => e
    nil
  end
end
_group_add(name:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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/ click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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) click to toggle source
# 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:) click to toggle source
# 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) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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:) click to toggle source
# 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) click to toggle source
# 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