class Nextcloud(Site): addtoblock = [ nginx.Key('error_page', '403 /core/templates/403.php'), nginx.Key('error_page', '404 /core/templates/404.php'), nginx.Key('client_max_body_size', '10G'), nginx.Key('fastcgi_buffers', '64 4K'), nginx.Key('fastcgi_buffer_size', '64K'), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location( '= /.well-known/carddav', nginx.Key('return', '301 $scheme://$host/remote.php/dav')), nginx.Location( '= /.well-known/caldav', nginx.Key('return', '301 $scheme://$host/remote.php/dav')), nginx.Location( '/', nginx.Key('rewrite', '^ /index.php$uri'), ), nginx.Location( '~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/', nginx.Key('deny', 'all')), nginx.Location('~ ^/(?:\.|autotest|occ|issue|indie|db_|console)', nginx.Key('deny', 'all')), nginx.Location( '~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]' '|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/)', nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_split_path_info', '^(.+\.php)(/.+)$'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME ' '$document_root$fastcgi_script_name'), nginx.Key('fastcgi_param', 'PATH_INFO $fastcgi_path_info'), nginx.Key('fastcgi_param', 'modHeadersAvailable true'), nginx.Key('fastcgi_param', 'front_controller_active true'), nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_intercept_errors', 'on'), nginx.Key('fastcgi_read_timeout', '900s')), nginx.Location('~ ^/(?:updater|ocs-provider)(?:$|/)', nginx.Key('try_files', '$uri/ =404'), nginx.Key('index', 'index.php')), nginx.Location( '~* \.(?:css|js)$', nginx.Key('try_files', '$uri /index.php$uri$is_args$args'), nginx.Key('add_header', 'Cache-Control "public, max-age=7200"'), nginx.Key('add_header', 'X-Content-Type-Options nosniff'), nginx.Key('add_header', 'X-XSS-Protection "1; mode=block"'), nginx.Key('add_header', 'X-Frame-Options "SAMEORIGIN"'), nginx.Key('add_header', 'X-Robots-Tag none'), nginx.Key('add_header', 'X-Download-Options noopen'), nginx.Key('add_header', 'X-Permitted-Cross-Domain-Policies none'), nginx.Key('access_log', 'off')), nginx.Location( '~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$', nginx.Key('try_files', '$uri /index.php$uri$is_args$args'), nginx.Key('access_log', 'off')) ] def pre_install(self, extra_vars): pass def post_install(self, extra_vars, dbpasswd=""): php.open_basedir('add', '/dev') # If there is a custom path for the data directory, add to open_basedir uid, gid = users.get_system("http").uid, groups.get_system("http").gid os.makedirs(os.path.join(self.path, "data")) os.chown(os.path.join(self.path, "data"), uid, gid) if self.data_path == self.path: self.data_path = os.path.join(self.path, "data") else: try: os.makedirs(os.path.join(self.data_path)) except OSError as e: if e[0] == 17: pass else: raise os.chown(os.path.join(self.data_path), uid, gid) php.open_basedir('add', self.data_path) # Make sure that the correct PHP settings are enabled php.enable_mod('opcache', 'mysql', 'pdo_mysql', 'zip', 'gd', 'ldap', 'iconv', 'openssl', 'posix') php.enable_mod('apcu', 'apc', config_file="/etc/php/conf.d/apcu.ini") php.change_setting('apc.enable_cli', '1', config_file="/etc/php/conf.d/apcu.ini") # Make sure php-fpm has the correct settings, # otherwise Nextcloud breaks with open("/etc/php/php-fpm.conf", "r") as f: lines = f.readlines() with open("/etc/php/php-fpm.conf", "w") as f: for line in lines: if ";clear_env = " in line: line = "clear_env = no\n" f.write(line) php.change_setting("always_populate_raw_post_data", "-1") mydir = os.getcwd() os.chdir(self.path) s = shell(('php occ maintenance:install ' '--database "mysql" --database-name "{}" ' '--database-user "{}" --database-pass "{}" ' '--admin-pass "{}" --data-dir "{}"').format( self.db.id, self.db.id, dbpasswd, dbpasswd, self.data_path)) if s["code"] != 0: logger.critical("Nextcloud", s["stderr"]) raise Exception("Nextcloud database population failed") s = shell("php occ app:enable user_ldap") if s["code"] != 0: logger.critical("Nextcloud", s["stderr"]) raise Exception("Nextcloud LDAP configuration failed") os.chdir(mydir) os.chown(os.path.join(self.path, "config/config.php"), uid, gid) ldap_sql = ("REPLACE INTO oc_appconfig " "(appid, configkey, configvalue) VALUES" "('core', 'backgroundjobs_mode', 'cron')," "('user_ldap', 'ldap_uuid_attribute', 'auto')," "('user_ldap', 'ldap_host', 'localhost')," "('user_ldap', 'ldap_port', '389')," "('user_ldap', 'ldap_base', 'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_base_users', " "'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_base_groups', " "'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_tls', '0')," "('user_ldap', 'ldap_display_name', 'cn')," "('user_ldap', 'ldap_userlist_filter', " "'objectClass=mailAccount')," "('user_ldap', 'ldap_group_filter', " "'objectClass=posixGroup')," "('user_ldap', 'ldap_group_display_name', 'cn')," "('user_ldap', 'ldap_group_member_assoc_attribute', " "'uniqueMember')," "('user_ldap', 'ldap_login_filter', " "'(&(|(objectclass=posixAccount))(|(uid=%uid)))')," "('user_ldap', 'ldap_quota_attr', 'mailQuota')," "('user_ldap', 'ldap_quota_def', '')," "('user_ldap', 'ldap_email_attr', 'mail')," "('user_ldap', 'ldap_cache_ttl', '600')," "('user_ldap', 'ldap_configuration_active', '1')," "('user_ldap', 'home_folder_naming_rule', '')," "('user_ldap', 'ldap_backup_host', '')," "('user_ldap', 'ldap_dn', '')," "('user_ldap', 'ldap_agent_password', '')," "('user_ldap', 'ldap_backup_port', '')," "('user_ldap', 'ldap_nocase', '')," "('user_ldap', 'ldap_turn_off_cert_check', '')," "('user_ldap', 'ldap_override_main_server', '')," "('user_ldap', 'ldap_attributes_for_user_search', '')," "('user_ldap', 'ldap_attributes_for_group_search', '')," "('user_ldap', 'ldap_expert_username_attr', 'uid')," "('user_ldap', 'ldap_expert_uuid_attr', '');") self.db.execute(ldap_sql, commit=True) self.db.execute("DELETE FROM oc_group_user;", commit=True) self.db.execute( "INSERT INTO oc_group_user VALUES ('admin','{0}');".format( extra_vars.get("nc-admin", "admin")), commit=True) if not os.path.exists("/etc/cron.d"): os.mkdir("/etc/cron.d") with open("/etc/cron.d/nc-{0}".format(self.id), "w") as f: f.write("*/15 * * * * http php -f {0} > /dev/null 2>&1".format( os.path.join(self.path, "cron.php"))) with open(os.path.join(self.path, "config", "config.php"), "r") as f: data = f.read() while re.search("\n(\s*('|\")memcache.local.*?\n)", data, re.DOTALL): data = data.replace( re.search("\n(\s*('|\")memcache.local.*?\n)", data, re.DOTALL).group(1), "") data = data.split("\n") with open(os.path.join(self.path, "config", "config.php"), "w") as f: for x in data: if not x.endswith("\n"): x += "\n" if x.startswith(");"): f.write(" 'memcache.local' => '\OC\Memcache\APCu',\n") f.write(x) rootcerts = os.path.join(self.data_path, 'data/files_external/rootcerts.crt') if os.path.exists(rootcerts): os.chown(os.path.join(rootcerts), uid, gid) self.site_edited() def pre_remove(self): datadir = '' config_file = os.path.join(self.path, 'config', 'config.php') autoconfig_file = os.path.join(self.path, 'config', 'autoconfig.php') if os.path.exists(config_file): with open(config_file, 'r') as f: for line in f.readlines(): if 'datadirectory' in line: data = line.split("'")[1::2] datadir = data[1] elif os.path.exists(autoconfig_file): with open(autoconfig_file, 'r') as f: for line in f.readlines(): if 'directory' in line: data = line.split('"')[1::2] datadir = data[1] if datadir: shutil.rmtree(datadir) php.open_basedir('del', datadir) def post_remove(self): cronfile = "/etc/cron.d/nc-{0}".format(self.id) if os.path.exists(cronfile): os.unlink(cronfile) def enable_ssl(self, cfile, kfile): # First, force SSL in Nextcloud's config file if os.path.exists(os.path.join(self.path, 'config', 'config.php')): px = os.path.join(self.path, 'config', 'config.php') else: px = os.path.join(self.path, 'config', 'autoconfig.php') with open(px, 'r') as f: ic = f.readlines() oc = [] found = False for l in ic: if '"forcessl" =>' in l: l = '"forcessl" => true,\n' oc.append(l) found = True else: oc.append(l) if found is False: for x in enumerate(oc): if '"dbhost" =>' in x[1]: oc.insert(x[0] + 1, '"forcessl" => true,\n') with open(px, 'w') as f: f.writelines(oc) def disable_ssl(self): if os.path.exists(os.path.join(self.path, 'config', 'config.php')): px = os.path.join(self.path, 'config', 'config.php') else: px = os.path.join(self.path, 'config', 'autoconfig.php') with open(px, 'r') as f: ic = f.readlines() oc = [] found = False for l in ic: if '"forcessl" =>' in l: l = '"forcessl" => false,\n' oc.append(l) found = True else: oc.append(l) if found is False: for x in enumerate(oc): if '"dbhost" =>' in x[1]: oc.insert(x[0] + 1, '"forcessl" => false,\n') with open(px, 'w') as f: f.writelines(oc) def site_edited(self): # Remove the existing trusted_sites array # then add a new one based on the new addr if os.path.exists(os.path.join(self.path, 'config', 'config.php')): path = os.path.join(self.path, 'config', 'config.php') else: raise errors.OperationFailedError( "Nextcloud config file not found") with open(path, "r") as f: data = f.read() while re.search("\n(\s*('|\")trusted_domains.*?\).*?\n)", data, re.DOTALL): data = data.replace( re.search("\n(\s*('|\")trusted_domains.*?\).*?\n)", data, re.DOTALL).group(1), "") data = data.split("\n") with open(path, "w") as f: for x in data: if not x.endswith("\n"): x += "\n" if x.startswith(");"): f.write(" 'trusted_domains' => " "array('localhost','{0}'),\n".format(self.domain)) f.write(x)
class Website(Plugin): implements(apis.webapps.IWebapp) addtoblock = [] phpblock = [ nginx.Location( '~ ^(.+?\.php)(/.*)?$', nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME $document_root$1'), nginx.Key('fastcgi_param', 'PATH_INFO $2'), nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_read_timeout', '900s'), ) ] def pre_install(self, name, vars): if vars.getvalue('ws-dbsel', 'None') == 'None': if vars.getvalue('ws-dbname', '') != '': raise Exception( 'Must choose a database type if you want to create one') elif vars.getvalue('ws-dbpass', '') != '': raise Exception( 'Must choose a database type if you want to create one') if vars.getvalue('ws-dbsel', 'None') != 'None': if vars.getvalue('ws-dbname', '') == '': raise Exception( 'Must choose a database name if you want to create one') elif vars.getvalue('ws-dbpass', '') == '': raise Exception( 'Must choose a database password if you want to create one' ) elif ' ' in vars.getvalue('ws-dbname') or '-' in vars.getvalue( 'ws-dbname'): raise Exception( 'Database name must not contain spaces or dashes') elif vars.getvalue('ws-dbname') > 16 and vars.getvalue( 'ws-dbsel') == 'MariaDB': raise Exception( 'Database name must be shorter than 16 characters') def post_install(self, name, path, vars): # Write a basic index file showing that we are here if vars.getvalue('php', '0') == '1': php = True path = os.path.join(path, 'htdocs') os.mkdir(path) c = nginx.loadf(os.path.join('/etc/nginx/sites-available', name)) for x in c.servers: if x.filter('Key', 'root'): x.filter('Key', 'root')[0].value = path nginx.dumpf(c, os.path.join('/etc/nginx/sites-available', name)) else: php = False # Create a database if the user wants one if php: phpctl = apis.langassist(self.app).get_interface('PHP') if vars.getvalue('ws-dbsel', 'None') != 'None': dbtype = vars.getvalue('ws-dbsel', '') dbname = vars.getvalue('ws-dbname', '') passwd = vars.getvalue('ws-dbpass', '') dbase = apis.databases(self.app).get_interface(dbtype) if hasattr(dbase, 'connect'): conn = apis.databases(self.app).get_dbconn(dbtype) dbase.add(dbname, conn) dbase.usermod(dbname, 'add', passwd, conn) dbase.chperm(dbname, dbname, 'grant', conn) else: dbase.add(dbname) dbase.usermod(dbname, 'add', passwd) dbase.chperm(dbname, dbname, 'grant') if php: phpctl.enable_mod('mysql') f = open( os.path.join(path, 'index.' + ('php' if php is True else 'html')), 'w') f.write('<html>\n' '<body>\n' '<h1>Genesis - Custom Site</h1>\n' '<p>Your site is online and available at ' + path + '</p>\n' '<p>Feel free to paste your site files here</p>\n' '</body>\n' '</html>\n') f.close() # Give access to httpd shell('chown -R http:http ' + path) # Enable xcache if PHP is set if php: phpctl.enable_mod('xcache') def pre_remove(self, name, path): pass def post_remove(self, name): pass def ssl_enable(self, path, cfile, kfile): pass def ssl_disable(self, path): pass def show_opts_add(self, ui): type_sel = [UI.SelectOption(text='None', value='None')] for x in sorted(apis.databases(self.app).get_dbtypes()): type_sel.append(UI.SelectOption(text=x[0], value=x[0])) ui.appendAll('ws-dbsel', *type_sel)
class ownCloud(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Key('error_page', '403 = /core/templates/403.php'), nginx.Key('error_page', '404 = /core/templates/404.php'), nginx.Key('client_max_body_size', '10G'), nginx.Key('fastcgi_buffers', '64 4K'), nginx.Key('rewrite', '^/caldav(.*)$ /remote.php/caldav$1 redirect'), nginx.Key('rewrite', '^/carddav(.*)$ /remote.php/carddav$1 redirect'), nginx.Key('rewrite', '^/webdav(.*)$ /remote.php/webdav$1 redirect'), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off') ), nginx.Location('~ ^/(data|config|\.ht|db_structure\.xml|README)', nginx.Key('deny', 'all') ), nginx.Location('/', nginx.Key('rewrite', '^/.well-known/host-meta /public.php?service=host-meta last'), nginx.Key('rewrite', '^/.well-known/host-meta.json /public.php?service=host-meta-json last'), nginx.Key('rewrite', '^/.well-known/carddav /remote.php/carddav/ redirect'), nginx.Key('rewrite', '^/.well-known/caldav /remote.php/caldav/ redirect'), nginx.Key('rewrite', '^(/core/doc/[^\/]+/)$ $1/index.html'), nginx.Key('try_files', '$uri $uri/ index.php') ), nginx.Location('~ ^(.+?\.php)(/.*)?$', nginx.Key('try_files', '$1 = 404'), nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME $document_root$1'), nginx.Key('fastcgi_param', 'PATH_INFO $2'), nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_read_timeout', '900s') ), nginx.Location('~* ^.+\.(jpg|jpeg|gif|bmp|ico|png|css|js|swf)$', nginx.Key('expires', '30d'), nginx.Key('access_log', 'off') ) ] def pre_install(self, name, vars): if vars.getvalue('oc-username', '') == '': raise Exception('Must choose an ownCloud username') elif vars.getvalue('oc-logpasswd', '') == '': raise Exception('Must choose an ownCloud password') elif '"' in vars.getvalue('oc-logpasswd', '') or "'" in vars.getvalue('oc-logpasswd', ''): raise Exception('Your ownCloud password must not include quotes') def post_install(self, name, path, vars, dbinfo={}): phpctl = apis.langassist(self.app).get_interface('PHP') datadir = '' secret_key = hashlib.sha1(str(random.random())).hexdigest() username = vars.getvalue('oc-username') logpasswd = vars.getvalue('oc-logpasswd') # Set ownership as necessary if not os.path.exists(os.path.join(path, 'data')): os.makedirs(os.path.join(path, 'data')) shell('chown -R http:http '+path) # If there is a custom path for the data directory, do the magic if vars.getvalue('oc-ddir', '') != '': datadir = vars.getvalue('oc-ddir') if not os.path.exists(os.path.join(datadir if datadir else path, 'data')): os.makedirs(os.path.join(datadir if datadir else path, 'data')) shell('chown -R http:http '+os.path.join(datadir if datadir else path, 'data')) phpctl.open_basedir('add', datadir) # Create ownCloud automatic configuration file f = open(os.path.join(path, 'config', 'autoconfig.php'), 'w') f.write( '<?php\n' ' $AUTOCONFIG = array(\n' ' "adminlogin" => "'+username+'",\n' ' "adminpass" => "'+logpasswd+'",\n' ' "dbtype" => "mysql",\n' ' "dbname" => "'+dbinfo['name']+'",\n' ' "dbuser" => "'+dbinfo['user']+'",\n' ' "dbpass" => "'+dbinfo['passwd']+'",\n' ' "dbhost" => "localhost",\n' ' "dbtableprefix" => "",\n' ' "directory" => "'+os.path.join(datadir if datadir else path, 'data')+'",\n' ' );\n' '?>\n' ) f.close() shell('chown http:http '+os.path.join(path, 'config', 'autoconfig.php')) # Make sure that the correct PHP settings are enabled phpctl.enable_mod('mysql', 'pdo_mysql', 'zip', 'gd', 'iconv', 'openssl', 'xcache') # Make sure xcache has the correct settings, otherwise ownCloud breaks f = open('/etc/php/conf.d/xcache.ini', 'w') oc = ['extension=xcache.so\n', 'xcache.size=64M\n', 'xcache.var_size=64M\n', 'xcache.admin.enable_auth = Off\n', 'xcache.admin.user = "******"\n', 'xcache.admin.pass = "******"\n'] f.writelines(oc) f.close() # Return an explicatory message if self.app.board in ['BeagleBone Black,' 'Raspberry Pi']: return ('ownCloud takes a long time to set up on this platform. ' 'Once you open the page for the first time, it may take 5-10 ' 'minutes for the content to appear. Please do not refresh the ' 'page.') def pre_remove(self, site): datadir = '' if os.path.exists(os.path.join(site.path, 'config', 'config.php')): f = open(os.path.join(site.path, 'config', 'config.php'), 'r') for line in f.readlines(): if 'datadirectory' in line: data = line.split("'")[1::2] datadir = data[1] f.close() elif os.path.exists(os.path.join(site.path, 'config', 'autoconfig.php')): f = open(os.path.join(site.path, 'config', 'autoconfig.php'), 'r') for line in f.readlines(): if 'directory' in line: data = line.split('"')[1::2] datadir = data[1] f.close() if datadir: shutil.rmtree(datadir) phpctl = apis.langassist(self.app).get_interface('PHP') phpctl.open_basedir('del', datadir) def post_remove(self, site): pass def ssl_enable(self, path, cfile, kfile): # First, force SSL in ownCloud's config file if os.path.exists(os.path.join(path, 'config', 'config.php')): px = os.path.join(path, 'config', 'config.php') else: px = os.path.join(path, 'config', 'autoconfig.php') ic = open(px, 'r').readlines() f = open(px, 'w') oc = [] found = False for l in ic: if '"forcessl" =>' in l: l = '"forcessl" => true,\n' oc.append(l) found = True else: oc.append(l) if found == False: for x in enumerate(oc): if '"dbhost" =>' in x[1]: oc.insert(x[0] + 1, '"forcessl" => true,\n') f.writelines(oc) f.close() # Next, update the ca-certificates thing to include our cert # (if necessary) if not os.path.exists('/usr/share/ca-certificates'): try: os.makedirs('/usr/share/ca-certificates') except OSError, e: if e.errno == errno.EEXIST and os.path.isdir('/usr/share/ca-certificates'): pass else: raise shutil.copy(cfile, '/usr/share/ca-certificates/') fname = cfile.rstrip('/').split('/')[-1] ic = open('/etc/ca-certificates.conf', 'r').readlines() f = open('/etc/ca-certificates.conf', 'w') oc = [] for l in ic: if l != fname+'\n': oc.append(l) oc.append(fname+'\n') f.writelines(oc) f.close() shell('update-ca-certificates')
class ownCloud(Site): addtoblock = [ nginx.Key('error_page', '403 = /core/templates/403.php'), nginx.Key('error_page', '404 = /core/templates/404.php'), nginx.Key('client_max_body_size', '10G'), nginx.Key('fastcgi_buffers', '64 4K'), nginx.Key('rewrite', '^/caldav(.*)$ /remote.php/caldav$1 redirect'), nginx.Key('rewrite', '^/carddav(.*)$ /remote.php/carddav$1 redirect'), nginx.Key('rewrite', '^/webdav(.*)$ /remote.php/webdav$1 redirect'), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location( '~ ^/(?:\.htaccess|data|config|db_structure\.xml|README)', nginx.Key('deny', 'all')), nginx.Location( '/', nginx.Key( 'rewrite', '^/.well-known/host-meta /public.php?service=host-meta last'), nginx.Key( 'rewrite', '^/.well-known/host-meta.json /public.php?service=host-meta-json last' ), nginx.Key('rewrite', '^/.well-known/carddav /remote.php/carddav/ redirect'), nginx.Key('rewrite', '^/.well-known/caldav /remote.php/caldav/ redirect'), nginx.Key('rewrite', '^(/core/doc/[^\/]+/)$ $1/index.html'), nginx.Key('try_files', '$uri $uri/ index.php')), nginx.Location( '~ \.php(?:$|/)', nginx.Key('fastcgi_split_path_info', '^(.+\.php)(/.+)$'), nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME $document_root$fastcgi_script_name'), nginx.Key('fastcgi_param', 'PATH_INFO $fastcgi_path_info'), nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_read_timeout', '900s')), nginx.Location('~* \.(?:jpg|jpeg|gif|bmp|ico|png|css|js|swf)$', nginx.Key('expires', '30d'), nginx.Key('access_log', 'off')) ] def pre_install(self, vars): pass def post_install(self, vars, dbpasswd=""): secret_key = random_string() # If there is a custom path for the data directory, add to open_basedir uid, gid = users.get_system("http").uid, groups.get_system("http").gid if not self.data_path.startswith(self.path): os.makedirs(os.path.join(self.path, "data")) os.chown(os.path.join(self.path, "data"), uid, gid) php.open_basedir('add', self.data_path) # Create ownCloud automatic configuration file with open(os.path.join(self.path, 'config', 'autoconfig.php'), 'w') as f: f.write('<?php\n' ' $AUTOCONFIG = array(\n' ' "adminlogin" => "admin",\n' ' "adminpass" => "' + dbpasswd + '",\n' ' "dbtype" => "mysql",\n' ' "dbname" => "' + self.db.id + '",\n' ' "dbuser" => "' + self.db.id + '",\n' ' "dbpass" => "' + dbpasswd + '",\n' ' "dbhost" => "localhost",\n' ' "dbtableprefix" => "",\n' ' "directory" => "' + self.data_path + '",\n' ' );\n' '?>\n') os.chown(os.path.join(self.path, 'config', 'autoconfig.php'), uid, gid) # Make sure that the correct PHP settings are enabled php.enable_mod('mysql', 'pdo_mysql', 'zip', 'gd', 'ldap', 'iconv', 'openssl', 'xcache', 'posix') # Make sure xcache has the correct settings, otherwise ownCloud breaks with open('/etc/php/conf.d/xcache.ini', 'w') as f: f.writelines([ 'extension=xcache.so\n', 'xcache.size=64M\n', 'xcache.var_size=64M\n', 'xcache.admin.enable_auth = Off\n', 'xcache.admin.user = "******"\n', 'xcache.admin.pass = "******"\n' ]) php.change_setting("always_populate_raw_post_data", "-1") mydir = os.getcwd() os.chdir(self.path) s = shell("sudo -u http php index.php") if s["code"] != 0: raise Exception("ownCloud database population failed") s = shell("sudo -u http php occ app:enable user_ldap") if s["code"] != 0: raise Exception("ownCloud LDAP configuration failed") os.chdir(mydir) ldap_sql = ( "REPLACE INTO appconfig (appid, configkey, configvalue) VALUES" "('user_ldap', 'ldap_uuid_attribute', 'auto')," "('user_ldap', 'ldap_host', 'localhost')," "('user_ldap', 'ldap_port', '389')," "('user_ldap', 'ldap_base', 'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_base_users', 'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_base_groups', 'dc=arkos-servers,dc=org')," "('user_ldap', 'ldap_tls', '0')," "('user_ldap', 'ldap_display_name', 'cn')," "('user_ldap', 'ldap_userlist_filter', 'objectClass=mailAccount')," "('user_ldap', 'ldap_group_filter', 'objectClass=posixGroup')," "('user_ldap', 'ldap_group_display_name', 'cn')," "('user_ldap', 'ldap_group_member_assoc_attribute', 'uniqueMember')," "('user_ldap', 'ldap_login_filter', '(&(|(objectclass=posixAccount))(|(uid=%uid)))')," "('user_ldap', 'ldap_quota_attr', 'mailQuota')," "('user_ldap', 'ldap_quota_def', '')," "('user_ldap', 'ldap_email_attr', 'mail')," "('user_ldap', 'ldap_cache_ttl', '600')," "('user_ldap', 'ldap_configuration_active', '1')," "('user_ldap', 'home_folder_naming_rule', '')," "('user_ldap', 'ldap_backup_host', '')," "('user_ldap', 'ldap_dn', '')," "('user_ldap', 'ldap_agent_password', '')," "('user_ldap', 'ldap_backup_port', '')," "('user_ldap', 'ldap_nocase', '')," "('user_ldap', 'ldap_turn_off_cert_check', '')," "('user_ldap', 'ldap_override_main_server', '')," "('user_ldap', 'ldap_attributes_for_user_search', '')," "('user_ldap', 'ldap_attributes_for_group_search', '')," "('user_ldap', 'ldap_expert_username_attr', 'uid')," "('user_ldap', 'ldap_expert_uuid_attr', '');") self.db.execute(ldap_sql, commit=True) # TODO set authed user name self.db.execute("INSERT INTO group_user VALUES ('admin','testuser');", commit=True) def pre_remove(self): datadir = '' if os.path.exists(os.path.join(self.path, 'config', 'config.php')): with open(os.path.join(self.path, 'config', 'config.php'), 'r') as f: for line in f.readlines(): if 'datadirectory' in line: data = line.split("'")[1::2] datadir = data[1] elif os.path.exists(os.path.join(self.path, 'config', 'autoconfig.php')): with open(os.path.join(self.path, 'config', 'autoconfig.php'), 'r') as f: for line in f.readlines(): if 'directory' in line: data = line.split('"')[1::2] datadir = data[1] if datadir: shutil.rmtree(datadir) php.open_basedir('del', datadir) def post_remove(self): pass def enable_ssl(self, cfile, kfile): # First, force SSL in ownCloud's config file if os.path.exists(os.path.join(self.path, 'config', 'config.php')): px = os.path.join(self.path, 'config', 'config.php') else: px = os.path.join(self.path, 'config', 'autoconfig.php') with open(px, 'r') as f: ic = f.readlines() oc = [] found = False for l in ic: if '"forcessl" =>' in l: l = '"forcessl" => true,\n' oc.append(l) found = True else: oc.append(l) if found == False: for x in enumerate(oc): if '"dbhost" =>' in x[1]: oc.insert(x[0] + 1, '"forcessl" => true,\n') with open(px, 'w') as f: f.writelines(oc) # Next, update the ca-certificates thing to include our cert # (if necessary) if not os.path.exists('/usr/share/ca-certificates'): try: os.makedirs('/usr/share/ca-certificates') except OSError, e: if e.errno == errno.EEXIST and os.path.isdir( '/usr/share/ca-certificates'): pass else: raise shutil.copy(cfile, '/usr/share/ca-certificates/') fname = cfile.rstrip('/').split('/')[-1] with open('/etc/ca-certificates.conf', 'r') as f: ic = f.readlines() oc = [] for l in ic: if l != fname + '\n': oc.append(l) oc.append(fname + '\n') with open('/etc/ca-certificates.conf', 'w') as f: f.writelines(oc) shell('update-ca-certificates')
class WordPress(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('/', nginx.Key('try_files', '$uri $uri/ /index.php?$args')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf')), nginx.Location('~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off')) ] def pre_install(self, name, vars): pass def post_install(self, name, path, vars, dbinfo={}): phpctl = apis.langassist(self.app).get_interface('PHP') secret_key = hashlib.sha1(str(random.random())).hexdigest() # Use the WordPress key generators as first option # If connection fails, use the secret_key as fallback try: keysection = urllib.urlopen( 'https://api.wordpress.org/secret-key/1.1/salt/').read() except: keysection = '' if not 'define(\'AUTH_KEY' in keysection: keysection = ('define(\'AUTH_KEY\', \'' + secret_key + '\');\n' 'define(\'SECURE_AUTH_KEY\', \'' + secret_key + '\');\n' 'define(\'LOGGED_IN_KEY\', \'' + secret_key + '\');\n' 'define(\'NONCE_KEY\', \'' + secret_key + '\');\n') # Write a standard WordPress config file f = open(os.path.join(path, 'wp-config.php'), 'w') f.write('<?php\n' 'define(\'DB_NAME\', \'' + dbinfo['name'] + '\');\n' 'define(\'DB_USER\', \'' + dbinfo['user'] + '\');\n' 'define(\'DB_PASSWORD\', \'' + dbinfo['passwd'] + '\');\n' 'define(\'DB_HOST\', \'localhost\');\n' 'define(\'DB_CHARSET\', \'utf8\');\n' 'define(\'SECRET_KEY\', \'' + secret_key + '\');\n' '\n' 'define(\'WP_CACHE\', true);\n' 'define(\'FORCE_SSL_ADMIN\', false);\n' '\n' + keysection + '\n' '$table_prefix = \'wp_\';\n' '\n' '/** Absolute path to the WordPress directory. */\n' 'if ( !defined(\'ABSPATH\') )\n' ' define(\'ABSPATH\', dirname(__FILE__) . \'/\');\n' '\n' '/** Sets up WordPress vars and included files. */\n' 'require_once(ABSPATH . \'wp-settings.php\');\n') f.close() # Make sure that the correct PHP settings are enabled phpctl.enable_mod('mysql', 'xcache') # Finally, make sure that permissions are set so that Wordpress # can make adjustments and save plugins when need be. shell('chown -R http:http ' + path) def pre_remove(self, site): pass def post_remove(self, site): pass def ssl_enable(self, path, cfile, kfile): ic = open(os.path.join(path, 'wp-config.php'), 'r').readlines() f = open(os.path.join(path, 'wp-config.php'), 'w') oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found == False: oc.append('define(\'FORCE_SSL_ADMIN\', true);\n') f.writelines(oc) f.close() def ssl_disable(self, path): ic = open(os.path.join(path, 'wp-config.php'), 'r').readlines() f = open(os.path.join(path, 'wp-config.php'), 'w') oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found == False: oc.append('define(\'FORCE_SSL_ADMIN\', false);\n') f.writelines(oc) f.close()
def main(): nginx_parameter_length_limit = 4000 pythonhome_directory = "" flask_app_file_location = "" application_name = "" nginx_conf_location = "" nginx_include_location = "" module_usage_string = """ Usage: nginx_flaskapp_whitelister -r (optional) -p <pythonenvdirectory> -f <flaskappmodule> -a <flaskapplicationname> -c <nginxconfiglocation> -n <nginxincludelocation> Flags: -h Help function to display functionality and guidance to use the nginx_flaskapp_whitelister module. -r Optional: Restart Nginx to reload added configuration and for white-listing to take immediate effect. -p <pythonenvdirectory> The directory of the python environment that the Flask app is running in. The $PYTHONHOME variable. -f <flaskappmodule> The python module from where the Flask app is served. -a <flaskapplicationname> The physical name of the Flask application. -c <nginxconfiglocation> The location of the current Nginx configuration that is used to serve the Flask application. -n <nginxincludelocation> Optional: File path to where the 'include.whitelist' file will be included from within the Nginx configuration that is used to serve the Flask application. If no file path is provided, the default will be used as '/etc/nginx/'. """ # Initial parameter/flag verification and extraction if not len(sys.argv) > 1: print( 'No arguments supplied. For more information run: nginx_flaskapp_whitelister -h' ) print(module_usage_string) sys.exit(2) try: opts, args = getopt.getopt(sys.argv[1:], "hrp:f:a:c:n:", [ "pythonenvdir=", "flaskappmodule=", "applicationname=", "nginxconfiglocation=", "nginxincludelocation=" ]) except getopt.GetoptError: print(module_usage_string) sys.exit(2) for opt, arg in opts: if opt == '-h': print(module_usage_string) sys.exit() elif opt in ("-p", "--pythonenvdir"): pythonhome_directory = arg elif opt in ("-f", "--flaskappmodule"): if "/" in arg: flask_app_file_location = arg.replace("/", ".") if flask_app_file_location.startswith("."): flask_app_file_location = flask_app_file_location[1:] else: flask_app_file_location = arg elif opt in ("-a", "--applicationname"): application_name = arg elif opt in ("-c", "--nginxconfiglocation"): nginx_conf_location = arg elif opt in ("-n", "--nginxincludelocation"): nginx_include_location = arg required_arguments = [{ 'pythonenvdir': pythonhome_directory }, { 'flaskappmodule': flask_app_file_location }, { 'applicationname': application_name }, { 'nginxconfiglocation': nginx_conf_location }] missing_arg = "" for argument in required_arguments: if argument.values()[0] == "": if missing_arg == "": missing_arg = argument.keys()[0] else: missing_arg = missing_arg + ", " + argument.keys()[0] if missing_arg != "": print( 'Required arguments (' + missing_arg + ') are missing. For more information run: nginx_flaskapp_whitelister -h' ) print(module_usage_string) sys.exit(2) # Setup the PYTHONPATH variable to point to the python home and import the requested Flask app from the specified module sys.path.append(pythonhome_directory) project = importlib.import_module(flask_app_file_location) app = getattr(project, application_name) # Extract all exposed flask endpoints from the specified app links = [] for rule in app.url_map._rules: links.append(rule.rule) # Consolidate the retrieved rules from the flask app url map to only contain a list of allowed endpoints and strip # parameter sections (< >) from endpoints allowed_locations = [] for endpoint in links: if endpoint != "/": allowed_locations.append(re.sub('<[^>]+>', '', endpoint)) # Load the current NginX config used to serve the application into a config object config = nginx.loadf(nginx_conf_location) # Extract the keys and configuration from the config object that refers to the location directive that allows the access # to "location / {}" (presumed to be the most likely allowed full access route configured) original_location_object = [] original_server_list = list(config.filter('Http')[0].filter('Server')) for server in original_server_list: if server.locations != []: original_location_object.extend(server.locations) current_locations = [] for location in original_location_object: current_locations.append(location.as_dict) # Create a new NginX config object for the added included location directives for the whitelisted locations allowed_location_keys = [] whitelist_location_conf = nginx.Conf() for location in current_locations: if location.keys()[0] == 'location /': for key in location['location /']: nested_key = [] if "if (" in key.keys()[0]: for x in key[key.keys()[0]]: nested_key.append( nginx.Key(x.keys()[0], x[x.keys()[0]]).as_strings) allowed_location_keys.append( nginx.Key(key.keys()[0], '{ ' + "".join(nested_key) + ' }')) else: allowed_location_keys.append( nginx.Key(key.keys()[0], key[key.keys()[0]])) # As Nginx has a parameter limit that caps the amount of characters allowed in a directive parameter, # the allowed location endpoints are chunked accordingly into as big as possible chunks within the limit dynamic_locations_write_variable = [] for location in allowed_locations: if len("|".join(dynamic_locations_write_variable + [location])) < nginx_parameter_length_limit: dynamic_locations_write_variable.append(location) else: dynamic_locations_write_variable.append(location) whitelist_location_conf.add( nginx.Location( '~ (' + '|'.join(dynamic_locations_write_variable) + ')', nginx.Key('include', 'shared.conf'))) dynamic_locations_write_variable = [] if dynamic_locations_write_variable != []: whitelist_location_conf.add( nginx.Location( '~ (' + '|'.join(dynamic_locations_write_variable) + ')', nginx.Key('include', 'shared.conf'))) dynamic_locations_write_variable = [] whitelist_location_conf.add( nginx.Location('= /', nginx.Key('include', 'shared.conf'))) whitelist_location_conf.add( nginx.Location('~ /', nginx.Key('return', '404'))) # Create a shared Nginx config object containing the keys and configurations shared and re-used # across various location directives. This shared.conf is then included per directive, instead # of repeating code shared_conf = nginx.Conf() shared_conf.add(*allowed_location_keys) shared_conf_tmp_file = tempfile.NamedTemporaryFile(dir='/tmp/').name nginx.dumpf(shared_conf, shared_conf_tmp_file) with open(shared_conf_tmp_file, 'r') as file: shared_conf_data = file.readlines() if any("if (" in string for string in shared_conf_data): for line in shared_conf_data: if "if (" in line: shared_conf_data[shared_conf_data.index( line)] = line.replace(') "{', ') {') if '}";' in line: shared_conf_data[shared_conf_data.index( line)] = line.replace('}";', '}') with open(shared_conf_tmp_file, 'w') as file: file.writelines(shared_conf_data) whitelist_location_conf_tmp_file = tempfile.NamedTemporaryFile( dir='/tmp/').name nginx.dumpf(whitelist_location_conf, whitelist_location_conf_tmp_file) # If a specific Nginx include location is specified, the generated configuration are moved to this location, # otherwise it is moved to a default location of (/etc/nginx/). This filepath should match the path of the # include directive inserted into the main nginx.conf for enabling the nginx whitelisting. if nginx_include_location != "": os.rename(whitelist_location_conf_tmp_file, nginx_include_location + "/include.whitelist") os.rename(shared_conf_tmp_file, nginx_include_location + "/shared.conf") else: os.rename(whitelist_location_conf_tmp_file, "/etc/nginx/include.whitelist") os.rename(shared_conf_tmp_file, "/etc/nginx/shared.conf") # For the newly generated whitelisting config to take effect, the Nginx config should be reloaded and the # process restarted. If the restart flag was set by the user, Nginx will be attempted to restart as part # of the tool implementation for opt, arg in opts: if opt == '-r': nginx_restart = subprocess.check_output( ["service", "nginx", "restart"]) print(nginx_restart)
class Wallabag(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Location('~ /(db)', nginx.Key('deny', 'all'), nginx.Key('return', '404')), nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('/', nginx.Key('try_files', '$uri $uri/ /index.php?$args')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf')), nginx.Location('~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off')) ] def pre_install(self, name, vars): pass def post_install(self, name, path, vars, dbinfo={}): phpctl = apis.langassist(self.app).get_interface('PHP') secret_key = hashlib.sha1(str(random.random())).hexdigest() dbengine = 'mysql' if dbinfo['engine'] == 'MariaDB' else 'sqlite' # Write a standard Wallabag config file shutil.copy(os.path.join(path, 'inc/poche/config.inc.default.php'), os.path.join(path, 'inc/poche/config.inc.php')) ic = open(os.path.join(path, 'inc/poche/config.inc.php'), 'r').readlines() f = open(os.path.join(path, 'inc/poche/config.inc.php'), 'w') oc = [] for l in ic: if 'define (\'SALT\'' in l: l = '@define (\'SALT\', \'' + secret_key + '\');\n' oc.append(l) elif 'define (\'STORAGE\'' in l: l = '@define (\'STORAGE\', \'' + dbengine + '\');\n' oc.append(l) elif 'define (\'STORAGE_SQLITE\'' in l and dbengine == 'sqlite': l = '@define (\'STORAGE_SQLITE\', \'/var/lib/sqlite3/' + dbinfo[ 'name'] + '.db\');\n' oc.append(l) elif 'define (\'STORAGE_DB\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_DB\', \'' + dbinfo['name'] + '\');\n' oc.append(l) elif 'define (\'STORAGE_USER\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_USER\', \'' + dbinfo['user'] + '\');\n' oc.append(l) elif 'define (\'STORAGE_PASSWORD\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_PASSWORD\', \'' + dbinfo[ 'passwd'] + '\');\n' oc.append(l) else: oc.append(l) f.writelines(oc) f.close() # Make sure that the correct PHP settings are enabled phpctl.enable_mod('mysql' if dbengine == 'mysql' else 'sqlite3', 'pdo_mysql' if dbengine == 'mysql' else 'pdo_sqlite', 'zip', 'tidy', 'xcache', 'openssl') # Set up Composer and install the proper modules phpctl.composer_install(path) # Set up the database then delete the install folder if dbengine == 'mysql': dbase = apis.databases(self.app).get_interface(dbinfo['engine']) conn = apis.databases(self.app).get_dbconn(dbinfo['engine']) dbase.execute(dbinfo['name'], open(os.path.join(path, 'install/mysql.sql')).read(), conn) else: shutil.copy(os.path.join(path, 'install/poche.sqlite'), '/var/lib/sqlite3/%s.db' % dbinfo['name']) phpctl.open_basedir('add', '/var/lib/sqlite3') shell('chown http:http /var/lib/sqlite3/%s.db' % dbinfo['name']) shell('chmod 755 /var/lib/sqlite3/%s.db' % dbinfo['name']) shutil.rmtree(os.path.join(path, 'install')) # Finally, make sure that permissions are set so that Wallabag # can make adjustments and save plugins when need be. shell('chmod -R 755 ' + os.path.join(path, 'assets/') + ' ' + os.path.join(path, 'cache/') + ' ' + os.path.join(path, 'db/')) shell('chown -R http:http ' + path) def pre_remove(self, site): pass def post_remove(self, name): pass def ssl_enable(self, path, cfile, kfile): pass def ssl_disable(self, path): pass def update(self, path, pkg, ver): # General update procedure shell('tar xzf %s -C %s --strip 1' % (pkg, path)) for x in os.listdir(os.path.join(path, 'cache')): if os.path.isdir(os.path.join(path, 'cache', x)): shutil.rmtree(os.path.join(path, 'cache', x)) else: os.unlink(os.path.join(path, 'cache', x)) shutil.rmtree(os.path.join(path, 'install')) shell('chmod -R 755 ' + os.path.join(path, 'assets/') + ' ' + os.path.join(path, 'cache/') + ' ' + os.path.join(path, 'db/')) shell('chown -R http:http ' + path)
class Etherpad(Plugin): implements(apis.webapps.IWebapp) name = 'Etherpad' icon = 'gen-pen' addtoblock = [ nginx.Location('/', nginx.Key('proxy_pass', 'http://127.0.0.1:2369'), nginx.Key('proxy_set_header', 'X-Real-IP $remote_addr'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_buffering', 'off')) ] def pre_install(self, name, vars): eth_name = vars.getvalue('ether_admin', '') eth_pass = vars.getvalue('ether_pass', '') if not (eth_name and eth_pass): raise Exception('You must enter an admin name AND password' 'in the App Settings tab!') conn = apis.databases(self.app).get_dbconn('MariaDB') apis.databases(self.app).get_interface('MariaDB').validate( name, name, eth_pass, conn) def post_install(self, name, path, vars, dbinfo={}): UsersBackend(self.app).add_user('etherpad') # Create/Edit the config file cfg = { "title": "Etherpad", "favicon": "favicon.ico", "ip": "127.0.0.1", "port": "2369", "sessionKey": hashlib.sha1(str(random.random())).hexdigest(), "dbType": "mysql", "dbSettings": { "user": dbinfo['user'], "host": "localhost", "password": dbinfo['passwd'], "database": dbinfo['name'] }, "defaultPadText": ("Welcome to Etherpad on arkOS!\n\nThis pad text is " "synchronized as you type, so that everyone viewing this page " "sees the same text. This allows you to collaborate seamlessly " "on documents!\n\nGet involved with Etherpad at " "http://etherpad.org, or with arkOS at http://arkos.io\n"), "requireSession": False, "editOnly": False, "minify": True, "maxAge": 60 * 60 * 6, "abiword": None, "requireAuthentication": False, "requireAuthorization": False, "trustProxy": True, "disableIPlogging": False, "socketTransportProtocols": ["xhr-polling", "jsonp-polling", "htmlfile"], "loglevel": "INFO", "logconfig": { "appenders": [{ "type": "console" }] }, "users": { vars.getvalue('ether_admin'): { "password": vars.getvalue('ether_pass'), "is_admin": True }, }, } with open(os.path.join(path, 'settings.json'), 'w') as f: json.dump(cfg, f, indent=4) # node-gyp needs the HOME variable to be set with open(os.path.join(path, 'bin/run.sh')) as f: run_script = f.readlines() run_script.insert(1, "export HOME=%s" % path) with open(os.path.join(path, 'bin/run.sh'), 'w') as f: f.writelines(run_script) # Install deps right away if not shell(os.path.join(path, 'bin/installDeps.sh') + ' || exit 1'): raise RuntimeError("Etherpad dependencies could not be installed.") # Install selected plugins mods = list( # e.g. "ep_plugin/ep_adminpads" str(var).split("/")[1] # ^^^^^^^^^^^^ for var in vars if var.startswith('ep_plugin/') and int(vars.getvalue(var))) if mods: mod_inst_path = os.path.join(path, "node_modules") if not os.path.exists(mod_inst_path): os.mkdir(mod_inst_path) nodectl = apis.langassist(self.app).get_interface('NodeJS') nodectl.install(*mods, install_path=mod_inst_path) # Make supervisor entry s = self.app.get_backend(apis.services.IServiceManager) s.edit( 'etherpad', { 'stype': 'program', 'directory': path, 'user': '******', 'command': os.path.join(path, 'bin/run.sh'), 'autostart': 'true', 'autorestart': 'true', 'stdout_logfile': '/var/log/etherpad.log', 'stderr_logfile': '/var/log/etherpad.log' }) s.enable('etherpad', 'supervisor') # Change owner of everything in the etherpad path shell('chown -R etherpad ' + path) #TODO: user auth with nginx?? def pre_remove(self, site): pass def post_remove(self, site): UsersBackend(self.app).del_user('etherpad') self.app.get_backend(apis.services.IServiceManager).delete( 'etherpad', 'supervisor') def ssl_enable(self, path, cfile, kfile): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) self.addtoblock[0].add( nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'X-Forwarded-Proto $scheme'), ) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name) def ssl_disable(self, path): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name)
def _install(self, extra_vars, enable, nthread): nthread.title = "Installing website" msg = Notification("info", "Webs", "Preparing to install...") nthread.update(msg) # Make sure the chosen port is indeed open if not tracked_services.is_open_port(self.port, self.domain): cname = "({0})".format(self.app.id) raise errors.InvalidConfigError(cname, nthread)\ from tracked_services.PortConflictError(self.port, self.domain) # Set some metadata values specialmsg, dbpasswd = "", "" site_dir = config.get("websites", "site_dir") path = (self.path or os.path.join(site_dir, self.id)) self.path = path self.php = extra_vars.get("php") or self.php \ or self.app.uses_php or False self.version = self.app.version.rsplit("-", 1)[0] \ if self.app.website_updates else None # Classify the source package type if not self.app.download_url: ending = "" elif self.app.download_url.endswith(".tar.gz"): ending = ".tar.gz" elif self.app.download_url.endswith(".tgz"): ending = ".tgz" elif self.app.download_url.endswith(".tar.bz2"): ending = ".tar.bz2" elif self.app.download_url.endswith(".zip"): ending = ".zip" elif self.app.download_url.endswith(".git"): ending = ".git" else: raise errors.InvalidConfigError( "Invalid source archive format in {0}".format(self.app.id)) msg = "Running pre-installation..." uid, gid = users.get_system("http").uid, groups.get_system("http").gid nthread.update(Notification("info", "Webs", msg)) # Call website type's pre-install hook self.pre_install(extra_vars) # If needs DB and user didn't select an engine, choose one for them if len(self.app.database_engines) > 1 \ and extra_vars.get("dbengine", None): self.app.selected_dbengine = extra_vars.get("dbengine") if not getattr(self.app, "selected_dbengine", None)\ and self.app.database_engines: self.app.selected_dbengine = self.app.database_engines[0] # Create DB and/or DB user as necessary if getattr(self.app, "selected_dbengine", None): msg = "Creating database..." nthread.update(Notification("info", "Webs", msg)) mgr = databases.get_managers(self.app.selected_dbengine) if not mgr: estr = "No manager found for {0}" raise errors.InvalidConfigError( estr.format(self.app.selected_dbengine)) # Make sure DB daemon is running if it has one if not mgr.state: svc = services.get(mgr.meta.database_service) svc.restart() self.db = mgr.add_db(self.id) if hasattr(self.db, "path"): os.chmod(self.db.path, 0o660) os.chown(self.db.path, -1, gid) # If multiuser DB type, create user if mgr.meta.database_multiuser: dbpasswd = random_string(16) db_user = mgr.add_user(self.id, dbpasswd) db_user.chperm("grant", self.db) # Make sure the target directory exists, but is empty pkg_path = os.path.join("/tmp", self.id + ending) if os.path.isdir(self.path): shutil.rmtree(self.path) os.makedirs(self.path) # Download and extract the source repo / package msg = "Downloading website source..." nthread.update(Notification("info", "Webs", msg)) if self.app.download_url and ending == ".git": g = git.Repo.clone_from(self.app.download_url, self.path) if hasattr(self.app, "download_at_tag"): g = git.Git(self.path) g.checkout(self.app.download_git_tag) elif self.app.download_url: download(self.app.download_url, file=pkg_path, crit=True) # Format extraction command according to type msg = "Extracting source..." nthread.update(Notification("info", "Webs", msg)) if ending in [".tar.gz", ".tgz", ".tar.bz2"]: arch = tarfile.open(pkg_path, "r:gz") r = (x for x in arch.getnames() if re.match("^[^/]*$", x)) toplvl = next(r, None) if not toplvl: raise errors.OperationFailedError( "Malformed source archive") arch.extractall(site_dir) os.rename(os.path.join(site_dir, toplvl), self.path) else: arch = zipfile.ZipFile(pkg_path) r = (x for x in arch.namelist() if re.match("^[^/]*/$", x)) toplvl = next(r, None) if not toplvl: raise errors.OperationFailedError( "Malformed source archive") arch.extractall(site_dir) os.rename(os.path.join(site_dir, toplvl.rstrip("/")), self.path) os.remove(pkg_path) # Set proper starting permissions on source directory os.chmod(self.path, 0o755) os.chown(self.path, uid, gid) for r, d, f in os.walk(self.path): for x in d: os.chmod(os.path.join(r, x), 0o755) os.chown(os.path.join(r, x), uid, gid) for x in f: os.chmod(os.path.join(r, x), 0o644) os.chown(os.path.join(r, x), uid, gid) # If there is a custom path for the data directory, set it up if getattr(self.app, "website_datapaths", None) \ and extra_vars.get("datadir"): self.data_path = extra_vars["datadir"] if not os.path.exists(self.data_path): os.makedirs(self.data_path) os.chmod(self.data_path, 0o755) os.chown(self.data_path, uid, gid) elif hasattr(self, "website_default_data_subdir"): self.data_path = os.path.join(self.path, self.website_default_data_subdir) else: self.data_path = self.path # Create the nginx serverblock addtoblock = self.addtoblock or [] if extra_vars.get("addtoblock"): addtoblock += nginx.loads(extra_vars.get("addtoblock"), False) default_index = "index." + ("php" if self.php else "html") if hasattr(self.app, "website_root"): webroot = os.path.join(self.path, self.app.website_root) else: webroot = self.path block = nginx.Conf() server = nginx.Server( nginx.Key("listen", str(self.port)), nginx.Key("listen", "[::]:" + str(self.port)), nginx.Key("server_name", self.domain), nginx.Key("root", webroot), nginx.Key( "index", getattr(self.app, "website_index", None) or default_index), nginx.Location("/.well-known/acme-challenge/", nginx.Key("root", self.path))) if addtoblock: server.add(*[x for x in addtoblock]) block.add(server) nginx.dumpf(block, os.path.join("/etc/nginx/sites-available", self.id)) challenge_dir = os.path.join(self.path, ".well-known/acme-challenge/") if not os.path.exists(challenge_dir): os.makedirs(challenge_dir) # Create arkOS metadata file meta = configparser.SafeConfigParser() meta.add_section("website") meta.set("website", "id", self.id) meta.set("website", "app", self.app.id) meta.set("website", "ssl", self.cert.id if getattr(self, "cert", None) else "None") meta.set("website", "version", self.version or "None") if getattr(self.app, "website_datapaths", None) \ and self.data_path: meta.set("website", "data_path", self.data_path) meta.set("website", "dbengine", "") meta.set("website", "dbengine", getattr(self.app, "selected_dbengine", "")) with open(os.path.join(self.path, ".arkos"), "w") as f: meta.write(f) # Call site type's post-installation hook msg = "Running post-installation. This may take a few minutes..." nthread.update(Notification("info", "Webs", msg)) specialmsg = self.post_install(extra_vars, dbpasswd) # Cleanup and reload daemons msg = "Finishing..." nthread.update(Notification("info", "Webs", msg)) self.installed = True storage.websites[self.id] = self if self.port == 80: cleanup_acme_dummy(self.domain) signals.emit("websites", "site_installed", self) if enable: self.nginx_enable() if enable and self.php: php.open_basedir("add", "/srv/http/") php_reload() msg = "{0} site installed successfully".format(self.app.name) nthread.complete(Notification("success", "Webs", msg)) if specialmsg: return specialmsg
def start(args): global path global conPicDict global firstTimeNginx global firstTimeNetcat processDocker = subprocess.Popen(["docker", "start"]+ [args[1]], stdout = subprocess.PIPE) output = processDocker.communicate() #get the image_name and the Cmds processCmd = subprocess.Popen(["docker", "inspect" ,"-f","'{{.Config.Cmd}}'", ""+ args[1]], stdout = subprocess.PIPE) cmd = processCmd.communicate()[0] cmd = cmd.split("'")[1] processImageName = subprocess.Popen(["docker", "inspect" ,"-f","'{{.Config.Image}}'", ""+ args[1]], stdout = subprocess.PIPE) imageName = processImageName.communicate()[0] imageName = imageName.split("'")[1] #conPicDict[args[1]] = ["docker","start"] + [args[1]] conPicDict[args[1]] = [imageName,cmd] + [args[1]] #args[1] is gonna be the worker name, ex: worker1 isNginx = False if(imageName == 'nginx:alpine'): isNginx = True #if both firstimes are false we add the server to both upstreams so it runs c = nginx.loadf(path+'/load-balancer/nginx.conf') HttpFilter = ((c.filter('Http')[0])) if(isNginx): if(firstTimeNginx == False): #make upstream make worker add worker to upstream add upstream #to the http nginxUpstream = nginx.Upstream('nginx') worker = nginx.Key('server', args[1]+":80") nginxUpstream.add(worker) HttpFilter.add(nginxUpstream) #when we make upstream for first time we also make server server s = nginx.Server() s.add(nginx.Key('listen','8100'),nginx.Location('/' , nginx.Key('proxy_pass','http://nginx'), nginx.Key('proxy_redirect','off'),nginx.Key('proxy_set_header','Host $host'), nginx.Key('proxy_set_header','X-Real_IP $remote_addr'), nginx.Key('proxy_set_header','X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header','X-Forwarded-Host $server_name'))) HttpFilter.add(s) #dumping firstTimeNginx = True nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: upstreamSearch = HttpFilter.filter('Upstream') j = 0 found = False for key in upstreamSearch: if(((key.as_dict).keys())[0] == 'upstream nginx'): found = True break j = j + 1 worker = nginx.Key('server', args[1]+":80") if(found): upstreamSearch[j].add(worker) nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: if(firstTimeNetcat == False): #make upstream make worker add worker to upstream add upstream #to the http nginxUpstream = nginx.Upstream('netcat') worker = nginx.Key('server', args[1]+":80") nginxUpstream.add(worker) HttpFilter.add(nginxUpstream) #when we make upstream for first time we also make server server s = nginx.Server() s.add(nginx.Key('listen','8101'),nginx.Location('/' , nginx.Key('proxy_pass','http://netcat'), nginx.Key('proxy_redirect','off'),nginx.Key('proxy_set_header','Host $host'), nginx.Key('proxy_set_header','X-Real_IP $remote_addr'), nginx.Key('proxy_set_header','X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header','X-Forwarded-Host $server_name'))) HttpFilter.add(s) #dumping firstTimeNetcat = True nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: upstreamSearch = HttpFilter.filter('Upstream') j = 0 found = False for key in upstreamSearch: if(((key.as_dict).keys())[0] == 'upstream netcat'): found = True break j = j + 1 worker = nginx.Key('server', args[1]+":80") if(found): upstreamSearch[j].add(worker) nginx.dumpf(c, path+'/load-balancer/nginx.conf') #now kill,rm,build,run loadBalReset()
def run(args): global conPicDict global workerCounter global firstTimeNginx global firstTimeNetcat global path #args[1] is image name #args[2] is container name #args[3]+ is the commands processDocker = subprocess.Popen(["docker","run","--name", "worker"+str(workerCounter)] + args[1:], stdout = subprocess.PIPE) output = processDocker.communicate() #connect container to network bridge conNet processNetConnect = subprocess.Popen(["docker","network","connect", "conNet","worker"+str(workerCounter)], stdout = subprocess.PIPE) output = processNetConnect.communicate() #get the image_name and the Cmds processCmd = subprocess.Popen(["docker", "inspect" ,"-f","'{{.Config.Cmd}}'", "worker"+str(workerCounter)], stdout = subprocess.PIPE) cmd = processCmd.communicate()[0] cmd = cmd.split("'")[1] processImageName = subprocess.Popen(["docker", "inspect" ,"-f","'{{.Config.Image}}'", "worker"+str(workerCounter)], stdout = subprocess.PIPE) imageName = processImageName.communicate()[0] imageName = imageName.split("'")[1] conPicDict["worker"+str(workerCounter)] = [imageName,cmd] + ["worker"+str(workerCounter)] conPicDict['count'] = workerCounter #everytime we run a container we add it to the load balancer by editing #the nginx.conf file then we have to kill, rm, rebuild and rerun loadBal #checks if its nginx or netcat(anything else) isNginx = False if(imageName == 'nginx:alpine'): isNginx = True #if both firstimes are false we add the server to both upstreams so it runs c = nginx.loadf(path+'/load-balancer/nginx.conf') HttpFilter = ((c.filter('Http')[0])) if(isNginx): if(firstTimeNginx == False): #make upstream make worker add worker to upstream add upstream #to the http nginxUpstream = nginx.Upstream('nginx') worker = nginx.Key('server', "worker"+str(workerCounter)+":80") nginxUpstream.add(worker) HttpFilter.add(nginxUpstream) #when we make upstream for first time we also make server server s = nginx.Server() s.add(nginx.Key('listen','8100'),nginx.Location('/' , nginx.Key('proxy_pass','http://nginx'), nginx.Key('proxy_redirect','off'),nginx.Key('proxy_set_header','Host $host'), nginx.Key('proxy_set_header','X-Real_IP $remote_addr'), nginx.Key('proxy_set_header','X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header','X-Forwarded-Host $server_name'))) HttpFilter.add(s) #dumping firstTimeNginx = True nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: upstreamSearch = HttpFilter.filter('Upstream') j = 0 found = False for key in upstreamSearch: if(((key.as_dict).keys())[0] == 'upstream nginx'): found = True break j = j + 1 worker = nginx.Key('server', "worker"+str(workerCounter)+":80") if(found): upstreamSearch[j].add(worker) nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: if(firstTimeNetcat == False): #make upstream make worker add worker to upstream add upstream #to the http nginxUpstream = nginx.Upstream('netcat') worker = nginx.Key('server', "worker"+str(workerCounter)+":80") nginxUpstream.add(worker) HttpFilter.add(nginxUpstream) #when we make upstream for first time we also make server server s = nginx.Server() s.add(nginx.Key('listen','8101'),nginx.Location('/' , nginx.Key('proxy_pass','http://netcat'), nginx.Key('proxy_redirect','off'),nginx.Key('proxy_set_header','Host $host'), nginx.Key('proxy_set_header','X-Real_IP $remote_addr'), nginx.Key('proxy_set_header','X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header','X-Forwarded-Host $server_name'))) HttpFilter.add(s) #dumping firstTimeNetcat = True nginx.dumpf(c, path+'/load-balancer/nginx.conf') else: upstreamSearch = HttpFilter.filter('Upstream') j = 0 found = False for key in upstreamSearch: if(((key.as_dict).keys())[0] == 'upstream netcat'): found = True break j = j + 1 worker = nginx.Key('server', "worker"+str(workerCounter)+":80") if(found): upstreamSearch[j].add(worker) nginx.dumpf(c, path+'/load-balancer/nginx.conf') #now kill,rm,build,run loadBalReset() #increment workerCounter workerCounter = workerCounter + 1
import nginx from settings import Settings settings = Settings('settings.yml') project_name = settings.get('project_name') nginx_settings = settings.get('nginx') listen = nginx_settings.get('listen') server_name = nginx_settings.get('server_name') location = nginx_settings.get('location') include = nginx_settings.get('location_keys').get('include') uwsgi_pass = nginx_settings.get('location_keys').get('uwsgi_pass') uwsgi_pass = uwsgi_pass.replace('{{project_name}}', project_name) c = nginx.Conf() s = nginx.Server() s.add( nginx.Key('listen', listen), #nginx.Comment('Yes, python-nginx can read/write comments!'), nginx.Key('server_name', server_name), nginx.Location( location, nginx.Key('include', include), nginx.Key('uwsgi_pass', uwsgi_pass), )) c.add(s) nginx.dumpf(c, 'test/' + project_name)
class Paperword(Site): addtoblock = [ nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Key('try_files', '$uri $uri/ @rewrite'), nginx.Location('@rewrite', nginx.Key('rewrite', '^/(.*)$ /index.php?_url=/$1')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_split_path_info', '^(.+\.php)(/.+)$'), nginx.Key('fastcgi_param', 'PATH_INFO $fastcgi_path_info'), nginx.Key('fastcgi_param', 'PATH_TRANSLATED ' '$document_root$fastcgi_path_info'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME ' '$document_root$fastcgi_script_name')), nginx.Location('~ /\.ht', nginx.Key('deny', 'all')) ] def pre_install(self, extra_vars): pass def post_install(self, extra_vars, dbpasswd=""): # Get around top-level zip restriction (FIXME 0.7.2) if "paperwork-master" in os.listdir(self.path): tmp_path = os.path.abspath(os.path.join(self.path, "../pwrk-tmp")) os.rename(os.path.join(self.path, "paperwork-master/frontend"), tmp_path) os.rename(os.path.join(self.path, ".arkos"), os.path.join(tmp_path, ".arkos")) shutil.rmtree(self.path) os.rename(tmp_path, self.path) # Make sure that the correct PHP settings are enabled php.enable_mod('gd', 'opcache', 'mysql', 'pdo_mysql', 'mcrypt') php.enable_mod('apcu', config_file="/etc/php/conf.d/apcu.ini") dbstr = "mysql, localhost, 3389, {0}, {1}, {0}"\ .format(self.id, dbpasswd) with open(os.path.join(self.path, 'app/storage/db_settings'), 'w') as f: f.write(dbstr) php.composer_install(self.path) nodejs.install("gulp", as_global=True) nodejs.install_from_package(self.path, stat=None) cwd = os.getcwd() os.chdir(self.path) s = shell("bower install --allow-root", stdin='y\n') if s["code"] != 0: raise Exception("Failed to run bower: {0}".format(s["stderr"])) s = shell("gulp") if s["code"] != 0: raise Exception("Failed to run gulp: {0}".format(s["stderr"])) s = shell("php artisan migrate --force") if s["code"] != 0: raise Exception("Failed to run artisan: {0}".format(s["stderr"])) os.chdir(cwd) # Make sure the webapps config points to the public directory. c = nginx.loadf(os.path.join('/etc/nginx/sites-available', self.id)) for x in c.servers: if x.filter('Key', 'root'): x.filter('Key', 'root')[0].value = \ os.path.join(self.path, 'public') nginx.dumpf(c, os.path.join('/etc/nginx/sites-available', self.id)) uid, gid = users.get_system("http").uid, groups.get_system("http").gid for r, d, f in os.walk(os.path.join(self.path, 'app')): for x in d: os.chmod(os.path.join(r, x), 0o755) os.chown(os.path.join(r, x), uid, gid) for x in f: os.chmod(os.path.join(r, x), 0o644) os.chown(os.path.join(r, x), uid, gid) if os.path.exists(os.path.join(self.path, 'app/storage/setup')): os.unlink(os.path.join(self.path, 'app/storage/setup')) def pre_remove(self): pass def post_remove(self): pass def enable_ssl(self, cfile, kfile): pass def disable_ssl(self): pass def site_edited(self): pass def update(self, pkg, ver): pass
class WordPress(Site): addtoblock = [ nginx.Location( '= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off') ), nginx.Location( '= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off') ), nginx.Location( '/', nginx.Key('try_files', '$uri $uri/ /index.php?$args') ), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf') ), nginx.Location( '~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off') )] def pre_install(self, extra_vars): pass def post_install(self, extra_vars, dbpasswd=""): secret_key = random_string() # Use the WordPress key generators as first option # If connection fails, use the secret_key as fallback try: keysection = requests.get( 'https://api.wordpress.org/secret-key/1.1/salt/').text except: keysection = '' if 'define(\'AUTH_KEY' not in keysection: keysection = ( 'define(\'AUTH_KEY\', \'{0}\');\n' 'define(\'SECURE_AUTH_KEY\', \'{0}\');\n' 'define(\'LOGGED_IN_KEY\', \'{0}\');\n' 'define(\'NONCE_KEY\', \'{0}\');\n'.format(secret_key) ) # Write a standard WordPress config file with open(os.path.join(self.path, 'wp-config.php'), 'w') as f: f.write('<?php\n' 'define(\'DB_NAME\', \'{0}\');\n' 'define(\'DB_USER\', \'{0}\');\n' 'define(\'DB_PASSWORD\', \'{1}\');\n' 'define(\'DB_HOST\', \'localhost\');\n' 'define(\'DB_CHARSET\', \'utf8\');\n' 'define(\'SECRET_KEY\', \'{2}\');\n' '\n' 'define(\'WP_CACHE\', true);\n' 'define(\'FORCE_SSL_ADMIN\', false);\n' '\n' '{3}' '\n' '$table_prefix = \'wp_\';\n' '\n' '/** Absolute path to the WordPress directory. */\n' 'if ( !defined(\'ABSPATH\') )\n' ' define(\'ABSPATH\', dirname(__FILE__) . \'/\');\n' '\n' '/** Sets up WordPress vars and included files. */\n' 'require_once(ABSPATH . \'wp-settings.php\');\n' .format(self.db.id, dbpasswd, secret_key, keysection) ) # Make sure that the correct PHP settings are enabled php.enable_mod('mysqli', 'opcache') php.enable_mod('apcu', config_file="/etc/php/conf.d/apcu.ini") # Finally, make sure that permissions are set so that Wordpress # can make adjustments and save plugins when need be. uid, gid = users.get_system("http").uid, groups.get_system("http").gid for r, d, f in os.walk(self.path): for x in d: os.chown(os.path.join(r, x), uid, gid) for x in f: os.chown(os.path.join(r, x), uid, gid) def pre_remove(self): pass def post_remove(self): pass def enable_ssl(self, cfile, kfile): with open(os.path.join(self.path, 'wp-config.php'), 'r') as f: ic = f.readlines() oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found is False: oc.append('define(\'FORCE_SSL_ADMIN\', true);\n') with open(os.path.join(self.path, 'wp-config.php'), 'w') as f: f.writelines(oc) def disable_ssl(self): with open(os.path.join(self.path, 'wp-config.php'), 'r') as f: ic = f.readlines() oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found is False: oc.append('define(\'FORCE_SSL_ADMIN\', false);\n') with open(os.path.join(self.path, 'wp-config.php'), 'w') as f: f.writelines(oc) def site_edited(self): if not self.db: return url = "http" url += ("s://" if self.cert else "://") url += self.addr url += ((":"+str(self.port)) if self.port not in [80, 443] else "") self.db.execute("UPDATE wp_options SET option_value = '{0}' " "WHERE option_name = 'siteurl';" .format(url), commit=True) self.db.execute("UPDATE wp_options SET option_value = '{0}' " "WHERE option_name = 'home';".format(url), commit=True)
def setup(self, addr, port): # Make sure Radicale is installed and ready pyctl = apis.langassist(self.app).get_interface('Python') users = UsersBackend(self.app) if not pyctl.is_installed('Radicale'): pyctl.install('radicale') # due to packaging bugs, make extra sure perms are readable st = os.stat('/usr/lib/python2.7/site-packages/radicale') for r, d, f in os.walk('/usr/lib/python2.7/site-packages/radicale'): for x in d: os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP) for x in f: os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP) if not os.path.exists('/etc/radicale/config'): if not os.path.isdir('/etc/radicale'): os.mkdir('/etc/radicale') open('/etc/radicale/config', 'w').write(self.default_config) if not os.path.isdir('/usr/lib/radicale'): os.mkdir('/usr/lib/radicale') # Add the site process users.add_user('radicale') users.add_group('radicale') users.add_to_group('radicale', 'radicale') wsgi_file = 'import radicale\n' wsgi_file += 'radicale.log.start()\n' wsgi_file += 'application = radicale.Application()\n' open('/etc/radicale/radicale.wsgi', 'w').write(wsgi_file) os.chmod('/etc/radicale/radicale.wsgi', 0766) s = self.app.get_backend(apis.services.IServiceManager) s.edit( 'radicale', { 'stype': 'program', 'directory': '/etc/radicale', 'user': '******', 'command': 'uwsgi -s /tmp/radicale.sock -C --plugin python2 --wsgi-file radicale.wsgi', 'stdout_logfile': '/var/log/radicale.log', 'stderr_logfile': '/var/log/radicale.log' }) s.enable('radicale', 'supervisor') block = [ nginx.Location( '/', nginx.Key('auth_basic', '"Genesis Calendar Server (Radicale)"'), nginx.Key('auth_basic_user_file', '/etc/radicale/users'), nginx.Key('include', 'uwsgi_params'), nginx.Key('uwsgi_pass', 'unix:///tmp/radicale.sock'), ) ] if not os.path.exists('/etc/radicale/users'): open('/etc/radicale/users', 'w').write('') os.chmod('/etc/radicale/users', 0766) WebappControl(self.app).add_reverse_proxy('radicale', '/usr/lib/radicale', addr, port, block) apis.networkcontrol(self.app).add_webapp( ('radicale', 'ReverseProxy', port)) c = self.app.get_config(RadicaleConfig(self.app)) c.first_run_complete = True c.save()
def _ssl_enable(self): # Get server-preferred ciphers if config.get("certificates", "ciphers"): ciphers = config.get("certificates", "ciphers") else: config.set("certificates", "ciphers", ciphers) config.save() block = nginx.loadf( os.path.join("/etc/nginx/sites-available/", self.id)) # If the site is on port 80, setup an HTTP redirect to new port 443 server = block.server listens = server.filter("Key", "listen") for listen in listens: httport = "80" sslport = "443" if listen.value.startswith("[::]"): # IPv6 httport = "[::]:80" sslport = "[::]:443" if listen.value == httport: listen.value = (sslport + " ssl http2") block.add( nginx.Server( nginx.Key("listen", httport), nginx.Key("server_name", self.domain), nginx.Location( "/", nginx.Key("return", "301 https://$host$request_uri")), nginx.Location("/.well-known/acme-challenge/", nginx.Key("root", self.path)))) for x in block.servers: if " ssl" in x.filter("Key", "listen")[0].value: server = x break else: listen.value = listen.value.split(" ssl")[0] + " ssl http2" # Clean up any pre-existing SSL directives that no longer apply to_remove = [x for x in server.keys if x.name.startswith("ssl_")] server.remove(*to_remove) # Add the necessary SSL directives to the serverblock and save server.add( nginx.Key("ssl_certificate", self.cert.cert_path), nginx.Key("ssl_certificate_key", self.cert.key_path), nginx.Key("ssl_protocols", "TLSv1 TLSv1.1 TLSv1.2"), nginx.Key("ssl_ciphers", ciphers), nginx.Key("ssl_session_timeout", "5m"), nginx.Key("ssl_prefer_server_ciphers", "on"), nginx.Key("ssl_dhparam", "/etc/arkos/ssl/dh_params.pem"), nginx.Key("ssl_session_cache", "shared:SSL:50m"), ) nginx.dumpf(block, os.path.join("/etc/nginx/sites-available/", self.id)) # Set the certificate name in the metadata file if not os.path.exists(os.path.join(self.path, ".arkos")): raise errors.InvalidConfigError("Could not find metadata file") meta = configparser.SafeConfigParser() meta.read(os.path.join(self.path, ".arkos")) meta.set("website", "ssl", self.cert.id) with open(os.path.join(self.path, ".arkos"), "w") as f: meta.write(f) # Call the website type's SSL enable hook self.enable_ssl(self.cert.cert_path, self.cert.key_path)
class Wallabag(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Location('~ /(db)', nginx.Key('deny', 'all'), nginx.Key('return', '404')), nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('/', nginx.Key('try_files', '$uri $uri/ /index.php?$args')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf')), nginx.Location('~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off')) ] def pre_install(self, name, vars): dbname = vars.getvalue('wb-dbname', '') dbpasswd = vars.getvalue('wb-dbpasswd', '') if dbname and dbpasswd: apis.databases(self.app).get_interface('MariaDB').validate( dbname, dbname, dbpasswd) elif dbname: raise Exception( 'You must enter a database password if you specify a database name!' ) elif dbpasswd: raise Exception( 'You must enter a database name if you specify a database password!' ) def post_install(self, name, path, vars): # Get the database object, and determine proper values phpctl = apis.langassist(self.app).get_interface('PHP') dbase = apis.databases(self.app).get_interface('MariaDB') conn = apis.databases(self.app).get_dbconn('MariaDB') if vars.getvalue('wb-dbname', '') == '': dbname = name else: dbname = vars.getvalue('wb-dbname') secret_key = hashlib.sha1(str(random.random())).hexdigest() if vars.getvalue('wb-dbpasswd', '') == '': passwd = secret_key[0:8] else: passwd = vars.getvalue('wb-dbpasswd') # Request a database and user to interact with it dbase.add(dbname, conn) dbase.usermod(dbname, 'add', passwd, conn) dbase.chperm(dbname, dbname, 'grant', conn) # Write a standard Wallabag config file shutil.copy(os.path.join(path, 'inc/poche/config.inc.php.new'), os.path.join(path, 'inc/poche/config.inc.php')) ic = open(os.path.join(path, 'inc/poche/config.inc.php'), 'r').readlines() f = open(os.path.join(path, 'inc/poche/config.inc.php'), 'w') oc = [] for l in ic: if 'define (\'SALT\'' in l: l = 'define (\'SALT\', \'' + secret_key + '\');\n' oc.append(l) elif 'define (\'STORAGE\'' in l: l = 'define (\'STORAGE\', \'mysql\');\n' oc.append(l) elif 'define (\'STORAGE_DB\'' in l: l = 'define (\'STORAGE_DB\', \'' + dbname + '\');\n' oc.append(l) elif 'define (\'STORAGE_USER\'' in l: l = 'define (\'STORAGE_USER\', \'' + dbname + '\');\n' oc.append(l) elif 'define (\'STORAGE_PASSWORD\'' in l: l = 'define (\'STORAGE_PASSWORD\', \'' + passwd + '\');\n' oc.append(l) else: oc.append(l) f.writelines(oc) f.close() # Make sure that the correct PHP settings are enabled phpctl.enable_mod('mysql', 'pdo_mysql', 'zip', 'tidy', 'xcache', 'openssl') # Set up Composer and install the proper modules phpctl.composer_install(path) # Finish setting up the database then delete the install folder dbase.execute(dbname, open(os.path.join(path, 'install/mysql.sql')).read(), conn) shutil.rmtree(os.path.join(path, 'install')) # Finally, make sure that permissions are set so that Poche # can make adjustments and save plugins when need be. shell('chmod -R 755 ' + os.path.join(path, 'assets/') + ' ' + os.path.join(path, 'cache/') + ' ' + os.path.join(path, 'db/')) shell('chown -R http:http ' + path) def pre_remove(self, name, path): f = open(os.path.join(path, 'inc/poche/config.inc.php'), 'r') for line in f.readlines(): if 'STORAGE_DB' in line: data = line.split('\'')[1::2] dbname = data[1] break f.close() dbase = apis.databases(self.app).get_interface('MariaDB') conn = apis.databases(self.app).get_dbconn('MariaDB') dbase.remove(dbname, conn) dbase.usermod(dbname, 'del', '', conn) def post_remove(self, name): pass def ssl_enable(self, path, cfile, kfile): pass def ssl_disable(self, path): pass
def _edit(self, newname): site_dir = config.get("websites", "site_dir") block = nginx.loadf(os.path.join("/etc/nginx/sites-available", self.id)) # If SSL is enabled and the port is changing to 443, # create the port 80 redirect server = block.server if self.cert and self.port == 443: for x in block.servers: if "443 ssl" in x.filter("Key", "listen")[0].value: server = x if self.port != 443: for x in block.servers: if "ssl" not in x.filter("Key", "listen")[0].value\ and x.filter("key", "return"): block.remove(x) elif self.port == 443: block.add( nginx.Server( nginx.Key("listen", "80"), nginx.Key("listen", "[::]:80"), nginx.Key("server_name", self.domain), nginx.Location( "/", nginx.Key("return", "301 https://$host$request_uri")), nginx.Location("/.well-known/acme-challenge/", nginx.Key("root", self.path)))) # If the name was changed... if newname and self.id != newname: # rename the folder and files... self.path = os.path.join(site_dir, newname) if os.path.exists(self.path): shutil.rmtree(self.path) self.nginx_disable(reload=False) shutil.move(os.path.join(site_dir, self.id), self.path) os.unlink(os.path.join("/etc/nginx/sites-available", self.id)) signals.emit("websites", "site_removed", self) self.id = newname # then update the site's arkOS metadata file with the new name meta = configparser.SafeConfigParser() meta.read(os.path.join(self.path, ".arkos")) meta.set("website", "id", self.id) with open(os.path.join(self.path, ".arkos"), "w") as f: meta.write(f) self.nginx_enable(reload=False) # Pass any necessary updates to the nginx serverblock and save port = "{0} ssl".format(self.port) if self.cert else str(self.port) for listen in server.filter("Key", "listen"): if listen.value.startswith("[::]:"): listen.value = "[::]:" + str(port) else: listen.value = str(port) if hasattr(self.app, "website_root") and self.app.website_root: webroot = os.path.join(self.path, self.app.website_root) else: webroot = self.path server.filter("Key", "server_name")[0].value = self.domain server.filter("Key", "root")[0].value = webroot server.filter("Key", "index")[0].value = "index.php" \ if getattr(self, "php", False) else "index.html" nginx.dumpf(block, os.path.join("/etc/nginx/sites-available", self.id)) # Call the site's edited hook, if it has one, then reload nginx signals.emit("websites", "site_loaded", self) if hasattr(self, "site_edited"): self.site_edited() nginx_reload()
class WordPress(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('/', nginx.Key('try_files', '$uri $uri/ /index.php?$args')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf')), nginx.Location('~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off')) ] def pre_install(self, name, vars): dbname = vars.getvalue('wp-dbname', '') dbpasswd = vars.getvalue('wp-dbpasswd', '') if dbname and dbpasswd: apis.databases(self.app).get_interface('MariaDB').validate( dbname, dbname, dbpasswd) elif dbname: raise Exception( 'You must enter a database password if you specify a database name!' ) elif dbpasswd: raise Exception( 'You must enter a database name if you specify a database password!' ) def post_install(self, name, path, vars): # Get the database object, and determine proper values phpctl = apis.langassist(self.app).get_interface('PHP') dbase = apis.databases(self.app).get_interface('MariaDB') conn = apis.databases(self.app).get_dbconn('MariaDB') if vars.getvalue('wp-dbname', '') == '': dbname = name else: dbname = vars.getvalue('wp-dbname') secret_key = hashlib.sha1(str(random.random())).hexdigest() if vars.getvalue('wp-dbpasswd', '') == '': passwd = secret_key[0:8] else: passwd = vars.getvalue('wp-dbpasswd') # Request a database and user to interact with it dbase.add(dbname, conn) dbase.usermod(dbname, 'add', passwd, conn) dbase.chperm(dbname, dbname, 'grant', conn) # Use the WordPress key generators as first option # If connection fails, use the secret_key as fallback try: keysection = urllib.urlopen( 'https://api.wordpress.org/secret-key/1.1/salt/').read() except: keysection = '' if not 'define(\'AUTH_KEY' in keysection: keysection = ('define(\'AUTH_KEY\', \'' + secret_key + '\');\n' 'define(\'SECURE_AUTH_KEY\', \'' + secret_key + '\');\n' 'define(\'LOGGED_IN_KEY\', \'' + secret_key + '\');\n' 'define(\'NONCE_KEY\', \'' + secret_key + '\');\n') # Write a standard WordPress config file f = open(os.path.join(path, 'wp-config.php'), 'w') f.write('<?php\n' 'define(\'DB_NAME\', \'' + dbname + '\');\n' 'define(\'DB_USER\', \'' + dbname + '\');\n' 'define(\'DB_PASSWORD\', \'' + passwd + '\');\n' 'define(\'DB_HOST\', \'localhost\');\n' 'define(\'DB_CHARSET\', \'utf8\');\n' 'define(\'SECRET_KEY\', \'' + secret_key + '\');\n' '\n' 'define(\'WP_CACHE\', true);\n' 'define(\'FORCE_SSL_ADMIN\', false);\n' '\n' + keysection + '\n' '$table_prefix = \'wp_\';\n' '\n' '/** Absolute path to the WordPress directory. */\n' 'if ( !defined(\'ABSPATH\') )\n' ' define(\'ABSPATH\', dirname(__FILE__) . \'/\');\n' '\n' '/** Sets up WordPress vars and included files. */\n' 'require_once(ABSPATH . \'wp-settings.php\');\n') f.close() # Make sure that the correct PHP settings are enabled phpctl.enable_mod('mysql', 'xcache') # Finally, make sure that permissions are set so that Wordpress # can make adjustments and save plugins when need be. shell('chown -R http:http ' + path) def pre_remove(self, name, path): f = open(os.path.join(path, 'wp-config.php'), 'r') for line in f.readlines(): if 'DB_NAME' in line: data = line.split('\'')[1::2] dbname = data[1] break f.close() dbase = apis.databases(self.app).get_interface('MariaDB') conn = apis.databases(self.app).get_dbconn('MariaDB') dbase.remove(dbname, conn) dbase.usermod(dbname, 'del', '', conn) def post_remove(self, name): pass def ssl_enable(self, path, cfile, kfile): ic = open(os.path.join(path, 'wp-config.php'), 'r').readlines() f = open(os.path.join(path, 'wp-config.php'), 'w') oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found == False: oc.append('define(\'FORCE_SSL_ADMIN\', true);\n') f.writelines(oc) f.close() def ssl_disable(self, path): ic = open(os.path.join(path, 'wp-config.php'), 'r').readlines() f = open(os.path.join(path, 'wp-config.php'), 'w') oc = [] found = False for l in ic: if 'define(\'FORCE_SSL_ADMIN\'' in l: l = 'define(\'FORCE_SSL_ADMIN\', false);\n' oc.append(l) found = True else: oc.append(l) if found == False: oc.append('define(\'FORCE_SSL_ADMIN\', false);\n') f.writelines(oc) f.close()
def _install(self, extra_vars, enable, nthread): # Set metadata values site_dir = config.get("websites", "site_dir") path = (self.path or os.path.join(site_dir, self.id)) self.path = path if os.path.isdir(self.path): shutil.rmtree(self.path) os.makedirs(self.path) # If extra data is passed in, set up the serverblock accordingly uwsgi_block = [ nginx.Location( extra_vars.get("lregex", "/"), nginx.Key("{0}_pass".format(extra_vars.get("type")), extra_vars.get("pass", "")), nginx.Key("include", "{0}_params".format(extra_vars.get("type")))) ] default_block = [ nginx.Location(extra_vars.get("lregex", "/"), nginx.Key("proxy_pass", extra_vars.get("pass", "")), nginx.Key("proxy_redirect", "off"), nginx.Key("proxy_buffering", "off"), nginx.Key("proxy_set_header", "Host $host")) ] if extra_vars: if not extra_vars.get("type") or not extra_vars.get("pass"): raise errors.InvalidConfigError( "Must enter ReverseProxy type and location to pass to") elif extra_vars.get("type") in ["fastcgi", "uwsgi"]: self.block = uwsgi_block else: self.block = default_block if extra_vars.get("xrip"): self.block[0].add( nginx.Key("proxy_set_header", "X-Real-IP $remote_addr")) if extra_vars.get("xff") == "1": xff_key = "X-Forwarded-For $proxy_add_x_forwarded_for" self.block[0].add(nginx.Key("proxy_set_header", xff_key)) # Create the nginx serverblock and arkOS metadata files block = nginx.Conf() server = nginx.Server( nginx.Key("listen", self.port), nginx.Key("listen", "[::]:" + str(self.port)), nginx.Key("server_name", self.domain), nginx.Key("root", self.base_path or self.path), nginx.Location("/.well-known/acme-challenge/", nginx.Key("root", self.path))) server.add(*[x for x in self.block]) block.add(server) nginx.dumpf(block, os.path.join("/etc/nginx/sites-available", self.id)) challenge_dir = os.path.join(self.path, ".well-known/acme-challenge/") if not os.path.exists(challenge_dir): os.makedirs(challenge_dir) meta = configparser.SafeConfigParser() ssl = self.cert.id if getattr(self, "cert", None) else "None" meta.add_section("website") meta.set("website", "id", self.id) meta.set("website", "app", self.app.id if self.app else "None") meta.set("website", "version", "None") meta.set("website", "ssl", ssl) with open(os.path.join(self.path, ".arkos"), "w") as f: meta.write(f) # Track port and reload daemon self.installed = True storage.websites[self.id] = self signals.emit("websites", "site_installed", self) self.nginx_enable()
class Wallabag(Site): addtoblock = [ nginx.Location("/", nginx.Key("try_files", "$uri /app.php$is_args$args")), nginx.Location( "~ ^/app\.php(/|$)", nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_split_path_info', "^(.+\.php)(/.*)$"), nginx.Key('include', 'fastcgi.conf'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME $realpath_root$fastcgi_script_name'), nginx.Key('fastcgi_param', 'DOCUMENT_ROOT $realpath_root')) ] def pre_install(self, extra_vars): pass def post_install(self, extra_vars, dbpasswd=""): secret_key = random_string() dbengine = 'mysql' \ if self.app.selected_dbengine == 'db-mariadb' \ else 'sqlite' # Write a standard Wallabag config file config_file = os.path.join(self.path, 'app/config/parameters.yml') with open(config_file + ".dist", 'r') as f: ic = f.readlines() with open(config_file, 'w') as f: for l in ic: if "database_driver: " in l: pdo = "pdo_mysql" if dbengine == "mysql" else "pdo_sqlite" l = " database_driver: {0}\n".format(pdo) elif "database_path: " in l and dbengine == 'sqlite': l = " database_path: {0}\n".format(self.db.path) elif "database_name: " in l and dbengine == 'mysql': l = " database_name: {0}\n".format(self.db.id) elif "database_user: "******" database_user: {0}\n".format(self.db.id) elif "database_password: "******"{0}"\n'.format(dbpasswd) elif "secret: " in l: l = " secret: {0}\n".format(secret_key) f.write(l) # Make sure that the correct PHP settings are enabled php.enable_mod('sqlite3', 'bcmath', 'pdo_mysql' if dbengine == 'mysql' else 'pdo_sqlite', 'zip', 'tidy') php.open_basedir('add', '/usr/bin/php') uid, gid = users.get_system("http").uid, groups.get_system("http").gid # Set up the database then delete the install folder if dbengine == 'sqlite3': php.open_basedir('add', '/var/lib/sqlite3') cwd = os.getcwd() os.chdir(self.path) s = shell("php bin/console wallabag:install --env=prod -n") if s["code"] != 0: logger.error("Websites", s["stderr"].decode()) raise errors.OperationFailedError( "Failed to populate database. See logs for more info") os.chdir(cwd) if dbengine == 'sqlite3': os.chown("/var/lib/sqlite3/{0}.db".format(self.db.id), -1, gid) os.chmod("/var/lib/sqlite3/{0}.db".format(self.db.id), 0o660) # Finally, make sure that permissions are set so that Wallabag # can make adjustments and save plugins when need be. for r, d, f in os.walk(self.path): for x in d: os.chown(os.path.join(r, x), uid, gid) for x in f: os.chown(os.path.join(r, x), uid, gid) def pre_remove(self): pass def post_remove(self): pass def enable_ssl(self, cfile, kfile): pass def disable_ssl(self): pass def update(self, pkg, ver): # General update procedure if semver.Version.coerce(ver) > semver.Version('2.0.0'): raise Exception( "Cannot automatically update from 1.x to 2.x. Please see " "Wallabag documentation for more information.") os.rename(os.path.join(self.path, 'app/config/parameters.yml'), '/tmp/_wb_parameters.yml') shell('tar xzf {0} -C {1} --strip 1'.format(pkg, self.path)) os.rename('/tmp/_wb_parameters.yml', os.path.join(self.path, 'app/config/parameters.yml')) cachepath = os.path.join(self.path, 'var/cache') for x in os.listdir(cachepath): fpath = os.path.join(cachepath, x) if os.path.isdir(fpath): shutil.rmtree(fpath) else: os.unlink(fpath) uid, gid = users.get_system("http").uid, groups.get_system("http").gid for r, d, f in os.walk(self.path): for x in d: os.chown(os.path.join(r, x), uid, gid) for x in f: os.chown(os.path.join(r, x), uid, gid)
def rebuild_sites(self): """ Turns jack's site json files into useable nginx configuration files """ for uuid, site_config in self.configs.items(): maintenance_mode = 'maintenance' in site_config and site_config['maintenance'] nginx_config = nginx.Conf() # Add some comments so anyone who looks in the nginx config # knows what's going on nginx_config.add(nginx.Comment('Generated by Prism CP. Any changes will be overwritten!')) nginx_config.add(nginx.Comment('Site ID: %s' % site_config['id'])) server_block = nginx.Server() if 'listen' in site_config: for port in site_config['listen']: server_block.add(nginx.Key('listen', port)) if 'hostname' in site_config: server_block.add(nginx.Key('server_name', site_config['hostname'])) site_folder = os.path.join(self._jack_plugin.site_files_location, uuid) # Sets the root and logs to the site's folder server_block.add(nginx.Key('access_log', os.path.join(site_folder, 'access.log'))) server_block.add(nginx.Key('error_log', os.path.join(site_folder, 'error.log'))) if 'root' in site_config: root_folder = os.path.join(site_folder, site_config['root']) if not os.path.exists(root_folder): os.makedirs(root_folder) server_block.add(nginx.Key('root', root_folder)) if 'index' in site_config: server_block.add(nginx.Key('index', site_config['index'])) # If the site is in maintenance mode, redirect everything to 503 if maintenance_mode: server_block.add(nginx.Location('/', nginx.Key('return', 503))) else: for path, items in site_config['locations'].items(): location_items = [] for item, content in items.items(): if isinstance(content, tuple) or isinstance(content, list): for c in content: location_items.append(nginx.Key(item, c)) else: location_items.append(nginx.Key(item, content)) server_block.add(nginx.Location(path, *location_items)) # Error page blocks server_block.add(nginx.Key('error_page', '400 /error/400.html')) server_block.add(nginx.Key('error_page', '403 /error/403.html')) server_block.add(nginx.Key('error_page', '404 /error/404.html')) server_block.add(nginx.Key('error_page', '408 /error/408.html')) server_block.add(nginx.Key('error_page', '500 /error/500.html')) server_block.add(nginx.Key('error_page', '502 /error/502.html')) server_block.add(nginx.Key('error_page', '503 /error/503.html')) server_block.add(nginx.Location('^~ /error/', nginx.Key('root', self.sites_default), nginx.Key('internal', ''))) nginx_config.add(server_block) # Dump to nginx's config location nginx.dumpf(nginx_config, os.path.join(self.config_location, site_config['uuid'] + '.conf')) # Reload nginx so it picks up the changes prism.os_command('systemctl reload nginx.service')
class Ghost(Plugin): implements(apis.webapps.IWebapp) name = 'Ghost' icon = 'gen-earth' addtoblock = [ nginx.Location('/', nginx.Key('proxy_pass', 'http://127.0.0.1:2368'), nginx.Key('proxy_set_header', 'X-Real-IP $remote_addr'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_buffering', 'off')) ] def pre_install(self, name, vars): pass def post_install(self, name, path, vars, dbinfo={}): nodectl = apis.langassist(self.app).get_interface('NodeJS') users = UsersBackend(self.app) if not os.path.exists('/usr/bin/python') and os.path.exists( '/usr/bin/python'): os.symlink('/usr/bin/python2', '/usr/bin/python') d = json.loads(open(os.path.join(path, 'package.json'), 'r').read()) del d['dependencies']['bcryptjs'] d['dependencies']['bcrypt'] = '0.7.8' open(os.path.join(path, 'package.json'), 'w').write(json.dumps(d)) d = open(os.path.join(path, 'core/server/models/user.js'), 'r').read() d = d.replace('bcryptjs', 'bcrypt') open(os.path.join(path, 'core/server/models/user.js'), 'w').write(d) nodectl.install_from_package(path, 'production', { 'sqlite': '/usr/bin', 'python': '/usr/bin/python2' }) users.add_user('ghost') s = self.app.get_backend(apis.services.IServiceManager) s.edit( 'ghost', { 'stype': 'program', 'directory': path, 'user': '******', 'command': 'node %s' % os.path.join(path, 'index.js'), 'autostart': 'true', 'autorestart': 'true', 'environment': 'NODE_ENV="production"', 'stdout_logfile': '/var/log/ghost.log', 'stderr_logfile': '/var/log/ghost.log' }) s.enable('ghost', 'supervisor') addr = vars.getvalue('addr', 'localhost') port = vars.getvalue('port', '80') # Get Mail settings mail_settings = { 'transport': vars.getvalue('ghost-transport', ''), 'service': vars.getvalue('ghost-service', ''), 'mail_user': vars.getvalue('ghost-mail-user', ''), 'mail_pass': vars.getvalue('ghost-mail-pass', ''), 'from_address': vars.getvalue('ghost-from-address', '') } # Create/Edit the Ghost config file f = open(os.path.join(path, 'config.example.js'), 'r').read() with open(os.path.join(path, 'config.js'), 'w') as config_file: f = f.replace( 'http://my-ghost-blog.com', 'http://' + addr + (':' + port if port != '80' else '')) if len(set(mail_settings.values())) != 1 and\ mail_settings['transport'] != '': # If the mail settings exist, add them f = f.replace( "mail: {},",\ 'mail: {\n' "\tfromaddress: '" + mail_settings['from_address'] + "',\n" "\ttransport: '" + mail_settings['transport'] + "',\n" "\t\toptions: {\n" "\t\t\tservice: '" + mail_settings['service'] + "',\n" "\t\t\tauth: {\n" "\t\t\t\tuser: '******'mail_user'] + "',\n" "\t\t\t\tpass: '******'mail_pass'] + "'\n" "\t\t\t}\n" "\t\t}\n" "},\n" ) config_file.write(f) config_file.close() # Finally, make sure that permissions are set so that Ghost # can make adjustments and save plugins when need be. shell('chown -R ghost ' + path) def pre_remove(self, site): pass def post_remove(self, site): users = UsersBackend(self.app) users.del_user('ghost') s = self.app.get_backend(apis.services.IServiceManager) s.delete('ghost', 'supervisor') def ssl_enable(self, path, cfile, kfile): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) self.addtoblock[0].add( nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'X-Forwarded-Proto $scheme'), ) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name) f = open(os.path.join(path, 'config.js'), 'r').read() with open(os.path.join(path, 'config.js'), 'w') as config_file: f = f.replace('production: {\n url: \'http://', 'production: {\n url: \'https://') config_file.write(f) config_file.close() s = self.app.get_backend(apis.services.IServiceManager) s.restart('ghost', 'supervisor') def ssl_disable(self, path): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name) f = open(os.path.join(path, 'config.js'), 'r').read() with open(os.path.join(path, 'config.js'), 'w') as config_file: f = f.replace('production: {\n url: \'https://', 'production: {\n url: \'http://') config_file.write(f) config_file.close() s = self.app.get_backend(apis.services.IServiceManager) s.restart('ghost', 'supervisor')
def setup(addr, port): # Make sure Radicale is installed and ready if not python.is_installed('Radicale'): python.install('radicale') # due to packaging bugs, make extra sure perms are readable pver = "{0}.{1}".format(sys.version_info.major, sys.version_info.minor) raddir = '/usr/lib/python{0}/site-packages/radicale'.format(pver) st = os.stat(raddir) for r, d, f in os.walk(raddir): for x in d: os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP) for x in f: os.chmod(os.path.join(r, x), st.st_mode | stat.S_IROTH | stat.S_IRGRP) if not os.path.exists('/etc/radicale/config'): if not os.path.isdir('/etc/radicale'): os.mkdir('/etc/radicale') with open('/etc/radicale/config', 'w') as f: f.write(default_config) if not os.path.isdir('/usr/lib/radicale'): os.mkdir('/usr/lib/radicale') # Add the site process u = users.SystemUser("radicale") u.add() g = groups.SystemGroup("radicale", users=["radicale"]) g.add() wsgi_file = 'import radicale\n' wsgi_file += 'radicale.log.start()\n' wsgi_file += 'application = radicale.Application()\n' with open('/etc/radicale/radicale.wsgi', 'w') as f: f.write(wsgi_file) os.chmod('/etc/radicale/radicale.wsgi', 0o766) cfg = { 'directory': '/etc/radicale', 'user': '******', 'command': 'uwsgi -s /tmp/radicale.sock -C ' '--plugin python --wsgi-file radicale.wsgi', 'stdout_logfile': '/var/log/radicale.log', 'stderr_logfile': '/var/log/radicale.log' } s = services.Service("radicale", "supervisor", cfg=cfg) s.add() block = [ nginx.Location( '/', nginx.Key('include', 'uwsgi_params'), nginx.Key('uwsgi_pass', 'unix:///tmp/radicale.sock'), ) ] s = websites.get("radicale") if s: s.remove() a = applications.get('radicale') s = websites.ReverseProxy(app=a, id="radicale", domain=addr, port=int(port), base_path="/usr/lib/radicale", block=block) s.install()
def BuildNginxConfiguration(self, server, api_services, clients, identity_services): print("Configuring Nginx Server") serverConfig = server['config'] config = nginx.Conf() # Add Root Configurations for key, value in serverConfig.items(): if (not isinstance(value, dict)): config.add(nginx.Key(key, value)) events = nginx.Events() httpConf = nginx.Http() # Add Event Configurations if ('events' in serverConfig): for key, value in serverConfig['events'].items(): events.add(nginx.Key(key, value)) config.add(events) # Add Http Configurations if ('http' in serverConfig): for key, value in serverConfig['http'].items(): httpConf.add(nginx.Key(key, value)) # Add Services To Http for api_service in api_services: nginxServer = nginx.Server( nginx.Key('listen', '80'), nginx.Key('server_name', str.lower(api_service['name']) + '.localhost'), ) proxy_pass = '******' + api_service['name'] + ':' + str( api_service['port']) + '/' location = nginx.Location( '/', nginx.Key('proxy_http_version', '1.1'), nginx.Key('proxy_set_header', 'Upgrade $http_upgrade'), nginx.Key('proxy_set_header', 'Connection keep-alive'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-NginX-Proxy true'), nginx.Key('proxy_pass', proxy_pass)) nginxServer.add(location) httpConf.add(nginxServer) for i_service in identity_services: nginxServer = nginx.Server( nginx.Key('listen', '80'), nginx.Key('server_name', str.lower(i_service['name']) + '.localhost'), ) #pylint: disable-msg=E1121 proxy_pass = '******' + i_service['name'] + ':' + str( i_service['port']) + '/' location = nginx.Location( '/', nginx.Key('proxy_http_version', '1.1'), nginx.Key('proxy_set_header', 'Upgrade $http_upgrade'), nginx.Key('proxy_set_header', 'Connection keep-alive'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-NginX-Proxy true'), nginx.Key('proxy_pass', proxy_pass)) nginxServer.add(location) httpConf.add(nginxServer) for client in clients: nginxServer = nginx.Server( nginx.Key('listen', '80'), nginx.Key('server_name', str.lower(client['name']) + '.localhost'), ) #pylint: disable-msg=E1121 proxy_pass = '******' + client['name'] + ':' + str( client['port']) + '/' location = nginx.Location( '/', nginx.Key('proxy_http_version', '1.1'), nginx.Key('proxy_set_header', 'Upgrade $http_upgrade'), nginx.Key('proxy_set_header', 'Connection keep-alive'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-NginX-Proxy true'), nginx.Key('proxy_pass', proxy_pass)) nginxServer.add(location) httpConf.add(nginxServer) config.add(httpConf) return config
class Wallabag(Site): addtoblock = [ nginx.Location('~ /(db)', nginx.Key('deny', 'all'), nginx.Key('return', '404')), nginx.Location('= /favicon.ico', nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('= /robots.txt', nginx.Key('allow', 'all'), nginx.Key('log_not_found', 'off'), nginx.Key('access_log', 'off')), nginx.Location('/', nginx.Key('try_files', '$uri $uri/ /index.php?$args')), nginx.Location( '~ \.php$', nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), nginx.Key('fastcgi_index', 'index.php'), nginx.Key('include', 'fastcgi.conf')), nginx.Location('~* \.(js|css|png|jpg|jpeg|gif|ico)$', nginx.Key('expires', 'max'), nginx.Key('log_not_found', 'off')) ] def pre_install(self, vars): if not vars.get('wb-username'): raise Exception('Must choose a Wallabag username') elif not vars.get('wb-passwd'): raise Exception('Must choose a Wallabag password') elif '"' in vars.get('wb-passwd') or "'" in vars.get('wb-passwd'): raise Exception('Your Wallabag password must not include quotes') def post_install(self, vars, dbpasswd=""): secret_key = random_string() dbengine = 'mysql' if self.meta.selected_dbengine == 'db-mariadb' else 'sqlite' username = vars.get("wb-username") passwd = vars.get("wb-passwd") + username + secret_key passwd = hashlib.sha1(passwd).hexdigest() # Write a standard Wallabag config file shutil.copy( os.path.join(self.path, 'inc/poche/config.inc.default.php'), os.path.join(self.path, 'inc/poche/config.inc.php')) with open(os.path.join(self.path, 'inc/poche/config.inc.php'), 'r') as f: ic = f.readlines() oc = [] for l in ic: if 'define (\'SALT\'' in l: l = '@define (\'SALT\', \'' + secret_key + '\');\n' oc.append(l) elif 'define (\'STORAGE\'' in l: l = '@define (\'STORAGE\', \'' + dbengine + '\');\n' oc.append(l) elif 'define (\'STORAGE_SQLITE\'' in l and dbengine == 'sqlite': l = '@define (\'STORAGE_SQLITE\', \'/var/lib/sqlite3/' + self.db.id + '.db\');\n' oc.append(l) elif 'define (\'STORAGE_DB\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_DB\', \'' + self.db.id + '\');\n' oc.append(l) elif 'define (\'STORAGE_USER\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_USER\', \'' + self.db.id + '\');\n' oc.append(l) elif 'define (\'STORAGE_PASSWORD\'' in l and dbengine == 'mysql': l = '@define (\'STORAGE_PASSWORD\', \'' + dbpasswd + '\');\n' oc.append(l) else: oc.append(l) with open(os.path.join(self.path, 'inc/poche/config.inc.php'), 'w') as f: f.writelines(oc) # Make sure that the correct PHP settings are enabled php.enable_mod('mysql' if dbengine == 'mysql' else 'sqlite3', 'pdo_mysql' if dbengine == 'mysql' else 'pdo_sqlite', 'zip', 'tidy', 'xcache', 'openssl') # Set up Composer and install the proper modules php.composer_install(self.path) uid, gid = users.get_system("http").uid, groups.get_system("http").gid # Set up the database then delete the install folder if dbengine == 'mysql': with open(os.path.join(self.path, 'install/mysql.sql')) as f: self.db.execute(f.read()) self.db.execute( "INSERT INTO users (username, password, name, email) VALUES ('%s', '%s', '%s', '');" % (username, passwd, username), commit=True) lid = int(self.db.manager.connection.insert_id()) self.db.execute( "INSERT INTO users_config (user_id, name, value) VALUES (%s, 'pager', '10');" % lid, commit=True) self.db.execute( "INSERT INTO users_config (user_id, name, value) VALUES (%s, 'language', 'en_EN.UTF8');" % lid, commit=True) else: shutil.copy(os.path.join(self.path, 'install/poche.sqlite'), '/var/lib/sqlite3/%s.db' % self.db.id) php.open_basedir('add', '/var/lib/sqlite3') os.chown("/var/lib/sqlite3/%s.db" % self.db.id, -1, gid) os.chmod("/var/lib/sqlite3/%s.db", 0664) self.db.execute( "INSERT INTO users (username, password, name, email) VALUES ('%s', '%s', '%s', '');" % (username, passwd, username)) self.db.execute( "INSERT INTO users_config (user_id, name, value) VALUES (1, 'pager', '10');" ) self.db.execute( "INSERT INTO users_config (user_id, name, value) VALUES (1, 'language', 'en_EN.UTF8');" ) shutil.rmtree(os.path.join(self.path, 'install')) # Finally, make sure that permissions are set so that Wallabag # can make adjustments and save plugins when need be. for r, d, f in os.walk(self.path): for x in d: if d in ["assets", "cache", "db"]: os.chmod(os.path.join(r, d), 0755) os.chown(os.path.join(r, x), uid, gid) for x in f: os.chown(os.path.join(r, x), uid, gid) def pre_remove(self): pass def post_remove(self): pass def enable_ssl(self, cfile, kfile): pass def disable_ssl(self): pass def update(self, pkg, ver): # General update procedure shell('tar xzf %s -C %s --strip 1' % (pkg, self.path)) for x in os.listdir(os.path.join(self.path, 'cache')): if os.path.isdir(os.path.join(self.path, 'cache', x)): shutil.rmtree(os.path.join(self.path, 'cache', x)) else: os.unlink(os.path.join(self.path, 'cache', x)) shutil.rmtree(os.path.join(self.path, 'install')) shell('chmod -R 755 ' + os.path.join(self.path, 'assets/') + ' ' + os.path.join(self.path, 'cache/') + ' ' + os.path.join(self.path, 'db/')) shell('chown -R http:http ' + self.path)
def _execute(command): config = FileUtils.get_instance('config.ini') nginx_conf_dir = config.get_prop("nginx-config", "nginx_conf_dir") nginx_conf_dir_bak = config.get_prop("nginx-config", "nginx_conf_dir_bak") os.system('mkdir -p ' + nginx_conf_dir) os.system('cp -r ' + nginx_conf_dir + nginx_conf_dir_bak) os.system('rm -rf ' + nginx_conf_dir + '*') state = '0' try: for k1 in command: upstreamName = k1["upstreamName"] upstreamNode = json.loads(k1["upstreamNode"]) fileName = nginx_conf_dir + upstreamName + '.conf' os.system('touch ' + fileName) c = nginx.Conf() LogUtil.info("Node信息:%s" % (upstreamNode)) t = '' for k2 in range(len(upstreamNode)): if (k2 == 0): t = 'server' + ' ' + upstreamNode[k2][ "ipAdress"] + ' ' + upstreamNode[k2]["strategy"] + ';\n' if (0 < k2 < len(upstreamNode) - 1): t = t + ' ' + 'server' + ' ' + upstreamNode[k2][ "ipAdress"] + ' ' + upstreamNode[k2]["strategy"] + ';\n' if (k2 == len(upstreamNode) - 1): t = t + ' ' + 'server' + ' ' + upstreamNode[k2][ "ipAdress"] + ' ' + upstreamNode[k2]["strategy"] ipHash = k1["ipHash"] if (ipHash == '1'): u = nginx.Upstream(upstreamName, nginx.Key('', t), nginx.Key('', 'ip_hash')) c.add(u) if (ipHash == '0'): u = nginx.Upstream(upstreamName, nginx.Key('', t)) c.add(u) s = nginx.Server() s.add( nginx.Key('listen', k1["nginxListenPort"]), nginx.Key('server_name', k1["nginxServerName"]), nginx.Key('access_log', k1["accessLog"]), nginx.Location( '= /', nginx.Key('proxy_pass', 'http://' + k1["upstreamName"]), nginx.Key('proxy_redirect', 'off'), nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-Real-IP $remote_addr'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'))) c.add(s) nginx.dumpf(c, fileName) LogUtil.info("完成Nginx配置") output = os.popen('service nginx restart').read() state = '1' param = [ "{\"mac\":\"" + MachineUtil.get_mac_address() + "\",\"state\":\"" + state + "\",\"msg\":\"" + output + "\"}" ] os.system('rm -rf ' + nginx_conf_dir_bak) AosServerService.route_service("ThriftApiService", "nginxLog", param) except Exception, ex: LogUtil.error(ex) os.system('rm -rf ' + nginx_conf_dir) os.system('mv ' + nginx_conf_dir_bak + nginx_conf_dir) os.system('service nginx restart') output = ex.message state = '2' param = [ "{\"mac\":\"" + MachineUtil.get_mac_address() + "\",\"state\":\"" + state + "\",\"msg\":\"" + output + "\"}" ] AosServerService.route_service("ThriftApiService", "nginxLog", param)
def set_conf(request, proxy): config = nginx.Conf() serverHTTP = nginx.Server() serverHTTPS = nginx.Server() print(proxy.domain) print(proxy.ssl) print(proxy.letsencrypt) print(proxy.rewriteHTTPS) print(proxy.proxypass) serverHTTP.add( nginx.Key('listen', '*:80'), nginx.Key('server_name', proxy.domain), ) if proxy.rewriteHTTPS: serverHTTP.add( nginx.Key('return', '302 https://$server_name$request_uri'), ) else: serverHTTP.add( nginx.Location( '/', nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-Real-IP $remote_addr'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'Upgrade $http_upgrade'), nginx.Key('proxy_set_header', 'Connection '"upgrade"), nginx.Key('proxy_http_version', '1.1'), nginx.Key('proxy_pass', proxy.proxypass), ) ) if proxy.ssl: letsencrypt.generate_cert(request, proxy) serverHTTPS.add( nginx.Key('server_name', proxy.domain), nginx.Key('listen', '*:443 ssl'), nginx.Key('ssl_protocols', 'TLSv1 TLSv1.1 TLSv1.2'), nginx.Key('ssl_certificate', '/etc/letsencrypt/live/'+proxy.domain+'/fullchain.pem'), nginx.Key('ssl_certificate_key', '/etc/letsencrypt/live/'+proxy.domain+'/privkey.pem'), ) serverHTTPS.add( nginx.Location( '/', nginx.Key('proxy_set_header', 'Host $host'), nginx.Key('proxy_set_header', 'X-Real-IP $remote_addr'), nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'Upgrade $http_upgrade'), nginx.Key('proxy_set_header', 'Connection '"upgrade"), nginx.Key('proxy_http_version', '1.1'), nginx.Key('proxy_pass', proxy.proxypass), ) ) config.add(serverHTTP) config.add(serverHTTPS) nginx.dumpf(config, '/etc/nginx/conf.d/' + proxy.domain + '.conf') shell.restart_nginx(request) return True
class Gitweb(Plugin): implements(apis.webapps.IWebapp) addtoblock = [ nginx.Location('/', nginx.Key('index', 'gitweb.cgi'), nginx.Key('include', 'fastcgi_params'), nginx.Key('gzip', 'off'), nginx.Key('fastcgi_param', 'GITWEB_CONFIG /etc/conf.d/gitweb.conf'), nginx.If('($uri ~ "/gitweb.cgi")', nginx.Key('fastcgi_pass', 'unix:/var/run/fcgiwrap.sock') ) ) ] def pre_install(self, name, vars): # Write a standard Gitweb config file if not os.path.exists('/etc/conf.d'): os.makedirs('/etc/conf.d') f = open('/etc/conf.d/gitweb.conf', 'w') oc = ['our $git_temp = "/tmp";\n', 'our $projectroot = "'+vars.getvalue('gw-proot', '')+'";\n', 'our @git_base_url_list = qw(git://'+vars.getvalue('hostname', '')+' http://git@'+vars.getvalue('hostname', '')+');\n' ] f.writelines(oc) f.close() def post_install(self, name, path, vars, dbinfo={}): svc = self.app.get_backend(apis.services.IServiceManager) f = open('/usr/lib/systemd/system/fcgiwrap.service', 'w') oc = ['[Unit]\n', 'Description=Simple server for running CGI applications over FastCGI\n', 'After=syslog.target network.target\n', '\n', '[Service]\n', 'Type=forking\n', 'Restart=on-abort\n', 'PIDFile=/var/run/fcgiwrap.pid\n', 'ExecStart=/usr/bin/spawn-fcgi -s /var/run/fcgiwrap.sock -P /var/run/fcgiwrap.pid -u http -g http -- /usr/sbin/fcgiwrap\n', 'ExecStop=/usr/bin/kill -15 $MAINPID\n', '\n', '[Install]\n', 'WantedBy=multi-user.target\n' ] f.writelines(oc) f.close() svc.enable('fcgiwrap') svc.start('fcgiwrap') if os.path.exists(os.path.join('/srv/http/webapps', name)): if os.path.isdir(os.path.join('/srv/http/webapps', name)): shutil.rmtree(os.path.join('/srv/http/webapps', name)) else: os.unlink(os.path.join('/srv/http/webapps', name)) os.symlink('/usr/share/gitweb', os.path.join('/srv/http/webapps', name)) def pre_remove(self, site): pass def post_remove(self, name): pass def ssl_enable(self, path, cfile, kfile): pass def ssl_disable(self, path): pass def update(self, path, pkg, ver): pass
class DokuWiki(Site): addtoblock = [ nginx.Location( '/', nginx.Key('try_files', '$uri $uri/ @dokuwiki'), ), nginx.Location('~ /(data|conf|bin|inc)/', nginx.Key('deny', 'all')), nginx.Location(r'~ /\.ht', nginx.Key('deny', 'all')), nginx.Location( '@dokuwiki', nginx.Key('rewrite', '^/_media/(.*) /lib/exe/fetch.php?media=$1 last'), nginx.Key('rewrite', '^/_detail/(.*) /lib/exe/detail.php?media=$1 last'), nginx.Key( 'rewrite', '^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last'), nginx.Key('rewrite', '^/(.*) /doku.php?id=$1 last'), ), nginx.Location( r'~ \.php$', nginx.Key('include', 'fastcgi_params'), nginx.Key('fastcgi_param', 'SCRIPT_FILENAME $document_root$fastcgi_script_name'), nginx.Key('fastcgi_pass', 'unix:/run/php-fpm/php-fpm.sock'), ), ] def pre_install(self, name, vars): pass def post_install(self, name, path, vars, dbinfo={}): # UPDATE: Config DB info and enable modules index_php = os.path.join(path, 'index.php') os.remove(index_php) with open(index_php, "w") as f: f.write(switching_index) # see below shell('chown -R http ' + path) def pre_remove(self, site): pass def post_remove(self, site): pass def ssl_enable(self, path, cfile, kfile): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) self.addtoblock[0].add( nginx.Key('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for'), nginx.Key('proxy_set_header', 'X-Forwarded-Proto $scheme'), ) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name) def ssl_disable(self, path): name = os.path.basename(path) n = nginx.loadf('/etc/nginx/sites-available/%s' % name) for x in n.servers: if x.filter('Location', '/'): x.remove(x.filter('Location', '/')[0]) x.add(self.addtoblock[0]) nginx.dumpf(n, '/etc/nginx/sites-available/%s' % name) def update(self, path, pkg, ver): pass