This commit is contained in:
brent s 2017-05-12 23:00:17 -04:00
parent 0b971e7b4f
commit 07d1efb607
1 changed files with 133 additions and 3 deletions

View File

@ -7,12 +7,15 @@ except ImportError:
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html
lxml_avail = False lxml_avail = False
import argparse import argparse
import crypt
import datetime import datetime
import errno import errno
import ipaddress import ipaddress
import getpass
import os import os
import pydoc # a dirty hack we use for pagination import pydoc # a dirty hack we use for pagination
import re import re
import readline
import sys import sys
import urllib.request as urlrequest import urllib.request as urlrequest
import urllib.parse as urlparse import urllib.parse as urlparse
@ -21,6 +24,19 @@ from ftplib import FTP_TLS


xsd = 'https://aif.square-r00t.net/aif.xsd' xsd = 'https://aif.square-r00t.net/aif.xsd'


# Ugh. You kids and your colors and bolds and crap.
class color(object):
PURPLE = '\033[95m'
CYAN = '\033[96m'
DARKCYAN = '\033[36m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
END = '\033[0m'

class aifgen(object): class aifgen(object):
def __init__(self, args): def __init__(self, args):
self.args = args self.args = args
@ -104,11 +120,113 @@ class aifgen(object):
exit(' !! ERROR: {0} is not a valid resolver address.'.format(rslvaddr)) exit(' !! ERROR: {0} is not a valid resolver address.'.format(rslvaddr))
else: else:
ifaces[ifacein] = {'address': 'auto', 'proto': ipver, 'gw': False, 'resolvers': False} ifaces[ifacein] = {'address': 'auto', 'proto': ipver, 'gw': False, 'resolvers': False}
moreIfacesin = input('Would you like to add more interfaces? ((y)es/(N)O) ') moreIfacesin = input('Would you like to add more interfaces? (y/{0}n{1}) '.format(color.BOLD, color.END))
if not re.match('^y(es)?$', moreIfacesin.lower()): if not re.match('^y(es)?$', moreIfacesin.lower()):
moreIfaces = False moreIfaces = False
return(ifaces) return(ifaces)
def genPassHash(user):
passin = getpass.getpass('* Please enter the password you want to use for {0} (will not echo back): '.format(user))
if passin not in ('', '!'):
salt = crypt.mksalt(crypt.METHOD_SHA512)
salthash = crypt.crypt(passin, salt)
else:
salthash = passin
return(salthash)
def userPrompt(syshelp):
users = {}
moreUsers = True
while moreUsers:
user = chkPrompt('What username would you like to add? ', syshelp)
if len(user) > 32:
exit(' !! ERROR: Usernames must be less than 32 characters.')
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', user):
exit(' !! ERROR: Your username does not match a valid pattern. See the man page for useradd (\'CAVEATS\').')
users[user] = {}
sudoin = chkPrompt('* Should {0} have (full!) sudo access? (y/{0}n{1}) '.format(user, color.BOLD, color.END), syshelp)
if re.match('^y(es)?$', sudoin.lower()):
users[user]['sudo'] = True
else:
users[user]['sudo'] = False
users[user]['password'] = genPassHash(user)
users[user]['comment'] = chkPrompt(('* What comment should {0} have? ' +
'(Typically this is the user\'s full name) ').format(user), syshelp)
uidin = chkPrompt(('* What UID should {0} have? Leave this blank if you don\'t care ' +
'(should be fine for most cases): ').format(user), syshelp)
if uidin != '':
try:
users[user]['uid'] = int(uidin)
except:
exit(' !! ERROR: The UID must be an integer.')
else:
users[user]['uid'] = False
grpin = chkPrompt(('* What group name would you like to use for {0}\'s primary group? ' +
'(You\'ll be able to add additional groups in a moment.)\n' +
'\tThe default, if left blank, is to simply create a group named {0} ' +
'(which is what you probably want): ').format(user), syshelp)
if len(grpin) > 32:
exit(' !! ERROR: Group names must be less than 32 characters.')
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', grpin):
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
users[user]['group'] = grpin
gidin = chkPrompt(('* What GID should {0} have? Leave this blank if you don\'t care ' +
'(should be fine for most cases): ').format(grpin), syshelp)
if gidin != '':
try:
users[user]['gid'] = int(gidin)
except:
exit(' !! ERROR: The GID must be an integer.')
else:
users[user]['gid'] = False
syshelp.append('https://aif.square-r00t.net/#code_home_code')
homein = chkPrompt(('* What directory should {0} use for its home? Leave blank if you don\'t care ' +
'(should be fine for most cases): ').format(user), syshelp)
if homein != '':
if not re.match('^/([^/\x00\s]+(/)?)+)$', homein):
exit('!! ERROR: Path {0} does not seem to be valid.'.format(homein))
users[user]['home'] = homein
else:
users[user]['home'] = False
homecrt = chkPrompt('* Do we need to create {0}? (y/{1}n{2}) '.format(homein, color.BOLD, color.END), syshelp)
if re.match('^y(es)?$', homecrt):
users[user]['homecreate'] = True
else:
users[user]['homecreate'] = False
del(syshelp[-1])
xgrouphelp = 'https://aif.square-r00t.net/#code_xgroup_code'
if xgrouphelp not in syshelp:
syshelp.append(xgrouphelp)
xgroupin = chkPrompt('* Would you like to add extra groups for {0}? (y/{1}n{2}) '.format(user, color.BOLD, color.END), syshelp)
if re.match('^y(es)?$', xgroupin.lower()):
morexgroups = True
users[user]['xgroups'] = {}
else:
morexgroups = False
users[user]['xgroups'] = False
while morexgroups:
xgrp = chkPrompt('** What is the name of the group you would like to add? ', syshelp)
if len(xgrp) > 32:
exit(' !! ERROR: Group names must be less than 32 characters.')
if not re.match('^[a-z_][a-z0-9_-]*[$]?$', xgrp):
exit(' !! ERROR: Your group name does not match a valid pattern. See the man page for groupadd (\'CAVEATS\').')
users[user]['xgroups'][xgrp] = {}
xgrpcrt = chkPrompt('** Does {0} need to be created? (y/{1}n{2} '.format(xgrp, color.BOLD, color.END), syshelp)
if re.match('^y(es)?$', xgrpcrt.lower()):
users[user]['xgroups'][xgrp]['create'] = True
else:
users[user]['xgroups'][xgrp]['create'] = False
xgrpgid = chkPrompt(('** What GID should {0} be? If the group will already exist on the new system or ' +
'don\'t care,\nleave this blank (should be fine for most cases): ').format(xgrp), syshelp)
if xrpgid != '':
try:
users[user]['xgroups'][xgrp]['gid'] = int(xgrpid)
except:
exit(' !! ERROR: The GID must be an integer.')
else:
users[user]['xgroups'][xgrp]['gid'] = False
moreusersin = input('\nWould you like to add more groups for {0}? (y/{1}n{2}) '.format(user, color.BOLD, color.END))
if not re.match('^y(es)?$', moreusersin.lower()):
morexgroups = False
return(users)
conf = {} conf = {}
print('[{0}] Beginning configuration...'.format(datetime.datetime.now())) print('[{0}] Beginning configuration...'.format(datetime.datetime.now()))
print('You may reply with \'wikihelp\' on the first prompt of a question for the relevant link(s) in the Arch wiki ' + print('You may reply with \'wikihelp\' on the first prompt of a question for the relevant link(s) in the Arch wiki ' +
@ -246,12 +364,24 @@ class aifgen(object):
if kbdin == '': if kbdin == '':
kbdin = 'US' kbdin = 'US'
del(syshelp[1]) del(syshelp[1])
rbtin = chkPrompt('* Would you like to reboot the host system after installation completes? ((Y)ES/(n)o): ', syshelp) rbtin = chkPrompt('* Would you like to reboot the host system after installation completes? ({0}y{1}/n): '.format(color.BOLD, color.END), syshelp)
if not re.match('^no?$', rbtin.lower()): if not re.match('^no?$', rbtin.lower()):
rebootme = True rebootme = True
else: else:
rebootme = False rebootme = False
conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rebootme} conf['system'] = {'timezone': tzin, 'locale': localein, 'chrootpath': chrootpathin, 'kbd': kbdin, 'reboot': rebootme}
syshelp[1] = 'https://aif.square-r00t.net/#code_users_code'
print('\nNow let\'s handle some user accounts. For passwords, you can either enter the password you want to use,\n' +
'a \'!\' (in which case TTY login will be disabled but e.g. SSH will still work), or just hit enter to leave it blank\n' +
'(which is HIGHLY not recommended - it means anyone can login by just pressing enter at the login!)\n')
print('Let\'s configure the root user.')
conf['system']['rootpass'] = genPassHash(root)
moreusers = input('Would you like to add one or more regular user(s)? (y/{0}n{1}) '.format(color.BOLD, color.END)
if re.match('^y(es)?$', moreusers.lower()):
syshelp.append('https://aif.square-r00t.net/#code_user_code')
conf['system']['users'] = userPrompt(syshelp)
else:
conf['system']['users'] = False
if self.args['verbose']: if self.args['verbose']:
import pprint import pprint
pprint.pprint(conf) pprint.pprint(conf)