├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── aj ├── custom-web-ui ├── plugins ├── plugins_custom ├── .gitignore └── customizations │ ├── __init__.py │ ├── plugin.yml │ ├── requirements.txt │ └── resources │ ├── build │ ├── all.css │ └── all.js │ ├── css │ └── styles.css │ ├── img │ ├── favicon.png │ ├── logo-full.png │ └── logo-small.png │ └── js │ └── module.js └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-* 2 | .~lock.* 3 | *~ 4 | *.pyc 5 | *.gz 6 | *.whl 7 | *.egg* 8 | *.asc 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ajenti-dev-multitool --build 3 | 4 | run: 5 | ./custom-web-ui 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Customized Web-UI demo 2 | 3 | This a demo of custom Web-UI built with Ajenti Core. 4 | 5 | Entry point is the [``custom-web-ui``](https://github.com/ajenti/demo-customized/blob/master/custom-web-ui) script. 6 | 7 | If you'd like to play with JS/CSS resource files, don't forget to rebuild them afterwards with ``make``. This requires the dev multitool (``sudo pip install -U ajenti-dev-multitool``). -------------------------------------------------------------------------------- /aj: -------------------------------------------------------------------------------- 1 | ../ajenti-ng/ajenti-core/aj -------------------------------------------------------------------------------- /custom-web-ui: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import getopt 3 | import logging 4 | import os 5 | import sys 6 | import yaml 7 | 8 | import aj 9 | import aj.config 10 | import aj.core 11 | import aj.log 12 | import aj.plugins 13 | 14 | 15 | class ConfigFile(aj.config.BaseConfig): 16 | default_content = { 17 | 'auth': { 18 | 'allow_sudo': False, 19 | 'provider': 'users', 20 | 'users': { 21 | 'root': { 22 | # 'admin' 23 | 'password': '73637279707400100000000800000001f77e545afaeced51bdc33d16311ae24d900fbd462f444bce13d3c2aec489f90996523b8f779955a0f67708e0164de989c91a9a8093cd422fd5f5727018bb790f8aa36363273f5415660e7ff5c9fb9432e1f8ef5a3e35604ab9f2549aa85dbf2ca842573d25c02753bee5f0dd9c542b5ec51d58b443ad9f5e2b8dd9de8bd63a70908a1283c290bc7ccab30a3a88553ef23f5a6c25ccbe82e9f2b9ea656a6e373c33897e7b6376992de5cd00e78ed940486cd7bf0634ab1a1be2cf2f14ba2beabd55f82f5f3859ee9eea350c0a9fa9495749f0d0d6db21c5c17c742263e0e5bfb5c1c964edec1579c92ea538566151581bd06756564c21796eb61a0dd6d42b95ea5b1cdf667e0b06450622882fbf0bc7c9274903fd920368742769ee70e24a6d917afe6ba28faca235bcb83a1e22f37ee867d843b023424885623470940dd17c244a8f0ef998f29e5b680721d656c2a610609534e47ece10ea164b884d11ce983148aacf84044c5336bbc167fd28f45438', 24 | 'uid': 0 25 | } 26 | } 27 | }, 28 | 'bind': { 29 | 'host': '0.0.0.0', 'mode': 'tcp', 'port': 8000 30 | }, 31 | 'max_sessions': 1, 32 | 'name': 'Embedded System', 33 | } 34 | 35 | def __init__(self, path): 36 | aj.config.BaseConfig.__init__(self) 37 | self.data = None 38 | self.path = os.path.abspath(path) 39 | 40 | def __unicode__(self): 41 | return self.path 42 | 43 | def load(self): 44 | if not os.path.exists(self.path): 45 | self.data = self.default_content 46 | else: 47 | # harden permissions on the file 48 | if os.geteuid() == 0: 49 | os.chmod(self.path, 0600) 50 | self.data = yaml.load(open(self.path)) 51 | 52 | def save(self): 53 | with open(self.path, 'w') as f: 54 | f.write(yaml.safe_dump( 55 | self.data, 56 | default_flow_style=False, 57 | encoding='utf-8', 58 | allow_unicode=True 59 | )) 60 | 61 | 62 | def usage(): 63 | print """ 64 | Usage: %s [options] 65 | Options: 66 | -v - Debug/verbose logging 67 | -d, --daemon - Run in background (daemon mode) 68 | -h, --help - This help 69 | """ % sys.argv[0] 70 | 71 | 72 | if __name__ == '__main__': 73 | log_level = logging.INFO 74 | daemonize = False 75 | debug_mode = False 76 | 77 | try: 78 | opts, args = getopt.getopt( 79 | sys.argv[1:], 80 | 'hdv', 81 | ['help', 'daemon'] 82 | ) 83 | except getopt.GetoptError as e: 84 | print str(e) 85 | usage() 86 | sys.exit(2) 87 | 88 | for o, a in opts: 89 | if o in ('-h', '--help'): 90 | usage() 91 | sys.exit(0) 92 | elif o in ('-v',): 93 | log_level = logging.DEBUG 94 | debug_mode = True 95 | elif o in ('-d', '--start'): 96 | daemonize = True 97 | 98 | aj.log.init_console(log_level) 99 | aj.core.start( 100 | config=ConfigFile('/etc/custom-web-ui.yml'), 101 | product_name='ajenti', 102 | daemonize=daemonize, 103 | debug_mode=debug_mode, 104 | # pick a suitable plugin provider 105 | plugin_providers=[ 106 | #aj.plugins.PythonPathPluginProvider(), # plugins installed with PIP 107 | aj.plugins.DirectoryPluginProvider('./plugins'), # plugins from a directory 108 | aj.plugins.DirectoryPluginProvider('./plugins_custom'), # plugins from a directory 109 | ], 110 | ) 111 | -------------------------------------------------------------------------------- /plugins: -------------------------------------------------------------------------------- 1 | ../ajenti-ng/plugins -------------------------------------------------------------------------------- /plugins_custom/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.sublime-* 3 | .~lock.* 4 | .bowerrc 5 | -------------------------------------------------------------------------------- /plugins_custom/customizations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajenti/demo-customized/04f0a7a89f25d7bea663f62148a9b289a2cee610/plugins_custom/customizations/__init__.py -------------------------------------------------------------------------------- /plugins_custom/customizations/plugin.yml: -------------------------------------------------------------------------------- 1 | name: customizations 2 | author: ACME Inc 3 | email: g.orsay@acme.com 4 | url: http://acme.com 5 | version: '0.1' 6 | title: 'Customizations' 7 | icon: cog 8 | dependencies: 9 | - !!python/object:aj.plugins.PluginDependency { plugin_name: core } 10 | resources: 11 | - 'resources/css/styles.css' 12 | - 'resources/js/module.js' 13 | - 'ng:branding' 14 | -------------------------------------------------------------------------------- /plugins_custom/customizations/requirements.txt: -------------------------------------------------------------------------------- 1 | aj 2 | ajenti.plugin.core 3 | -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/build/all.css: -------------------------------------------------------------------------------- 1 | html body.customized #loading-bar .bar { 2 | background: #CC2A00; 3 | } 4 | 5 | html body.customized .container > .row > .sidebar .sidebar-item.active > div > .expander, 6 | html body.customized .container > .row > .sidebar .sidebar-item.active > div > .link , 7 | html body.customized .container > .sidebar .sidebar-item.active > div > .expander, 8 | html body.customized .container > .sidebar .sidebar-item.active > div > .link { 9 | background: #CC2A00; 10 | } 11 | 12 | html body.customized .container > .row > .sidebar .sidebar-item h5, 13 | html body.customized .container > .sidebar .sidebar-item h5 { 14 | color: #CC2A00; 15 | } 16 | 17 | html body.customized .form-control:focus { 18 | border-bottom-color: #CC2A00; 19 | } 20 | 21 | html body.customized .form-control:focus + .input-group-addon { 22 | border-bottom-color: #CC2A00; 23 | a i { color: #CC2A00; } 24 | } 25 | 26 | html body.customized .navbar-brand .title { 27 | color: #CC2A00; 28 | } 29 | 30 | html body.customized .navbar-brand.navigation-toggle { 31 | color: #CC2A00; 32 | } 33 | 34 | html body.customized .btn-primary { 35 | background: #CC2A00; 36 | border: #AA1A00; 37 | } 38 | 39 | html body.customized .btn-flat { 40 | color: #CC2A00; 41 | } 42 | 43 | html body.customized *[checkbox].active i.on { 44 | color: #CC2A00; 45 | } 46 | 47 | html body.customized smart-progress .progress .progress-bar { 48 | background: #CC2A00; 49 | } 50 | 51 | html body.customized progress-spinner .one { 52 | border-left-color: #CC2A00; 53 | border-top-color: #CC2A00; 54 | } 55 | 56 | html body.customized .nav-tabs > li.active > a, 57 | html body.customized .nav-tabs > li.active > a:hover { 58 | border-bottom: 1px solid #CC2A00; 59 | color: #CC2A00; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/build/all.js: -------------------------------------------------------------------------------- 1 | angular.module('branding', [ 2 | 'core', 3 | ]); 4 | 5 | angular.module('branding').run(function (customization) { 6 | customization.plugins.core.startupURL = '/view/settings'; 7 | customization.plugins.core.bodyClass = 'customized'; 8 | customization.plugins.core.title = 'Lipsum 9000'; 9 | customization.plugins.core.faviconURL = '/resources/customizations/resources/img/favicon.png'; 10 | customization.plugins.core.logoURL = '/resources/customizations/resources/img/logo-small.png'; 11 | customization.plugins.core.bigLogoURL = '/resources/customizations/resources/img/logo-full.png'; 12 | customization.plugins.core.hidePersonaLogin = true; 13 | 14 | //customization.plugins.settings.hideMachineSettings = true; 15 | //customization.plugins.settings.hideMachineName = true; 16 | customization.plugins.settings.hideMachineColor = true; 17 | 18 | //customization.plugins.settings.hideBindingSettings = true; 19 | //customization.plugins.settings.hideAuthSettings = true; 20 | 21 | //customization.plugins.settings.hideSSLSettings = true; 22 | //customization.plugins.settings.hideSSLClientAuthSettings = true; 23 | 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/css/styles.css: -------------------------------------------------------------------------------- 1 | html body.customized #loading-bar .bar { 2 | background: #CC2A00; 3 | } 4 | 5 | html body.customized .container > .row > .sidebar .sidebar-item.active > div > .expander, 6 | html body.customized .container > .row > .sidebar .sidebar-item.active > div > .link , 7 | html body.customized .container > .sidebar .sidebar-item.active > div > .expander, 8 | html body.customized .container > .sidebar .sidebar-item.active > div > .link { 9 | background: #CC2A00; 10 | } 11 | 12 | html body.customized .container > .row > .sidebar .sidebar-item h5, 13 | html body.customized .container > .sidebar .sidebar-item h5 { 14 | color: #CC2A00; 15 | } 16 | 17 | html body.customized .form-control:focus { 18 | border-bottom-color: #CC2A00; 19 | } 20 | 21 | html body.customized .form-control:focus + .input-group-addon { 22 | border-bottom-color: #CC2A00; 23 | a i { color: #CC2A00; } 24 | } 25 | 26 | html body.customized .navbar-brand .title { 27 | color: #CC2A00; 28 | } 29 | 30 | html body.customized .navbar-brand.navigation-toggle { 31 | color: #CC2A00; 32 | } 33 | 34 | html body.customized .btn-primary { 35 | background: #CC2A00; 36 | border: #AA1A00; 37 | } 38 | 39 | html body.customized .btn-flat { 40 | color: #CC2A00; 41 | } 42 | 43 | html body.customized *[checkbox].active i.on { 44 | color: #CC2A00; 45 | } 46 | 47 | html body.customized smart-progress .progress .progress-bar { 48 | background: #CC2A00; 49 | } 50 | 51 | html body.customized progress-spinner .one { 52 | border-left-color: #CC2A00; 53 | border-top-color: #CC2A00; 54 | } 55 | 56 | html body.customized .nav-tabs > li.active > a, 57 | html body.customized .nav-tabs > li.active > a:hover { 58 | border-bottom: 1px solid #CC2A00; 59 | color: #CC2A00; 60 | } 61 | -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajenti/demo-customized/04f0a7a89f25d7bea663f62148a9b289a2cee610/plugins_custom/customizations/resources/img/favicon.png -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/img/logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajenti/demo-customized/04f0a7a89f25d7bea663f62148a9b289a2cee610/plugins_custom/customizations/resources/img/logo-full.png -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/img/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajenti/demo-customized/04f0a7a89f25d7bea663f62148a9b289a2cee610/plugins_custom/customizations/resources/img/logo-small.png -------------------------------------------------------------------------------- /plugins_custom/customizations/resources/js/module.js: -------------------------------------------------------------------------------- 1 | angular.module('branding', [ 2 | 'core', 3 | ]); 4 | 5 | angular.module('branding').run(function (customization) { 6 | customization.plugins.core.startupURL = '/view/settings'; 7 | customization.plugins.core.bodyClass = 'customized'; 8 | customization.plugins.core.title = 'Lipsum 9000'; 9 | customization.plugins.core.faviconURL = '/resources/customizations/resources/img/favicon.png'; 10 | customization.plugins.core.logoURL = '/resources/customizations/resources/img/logo-small.png'; 11 | customization.plugins.core.bigLogoURL = '/resources/customizations/resources/img/logo-full.png'; 12 | customization.plugins.core.hidePersonaLogin = true; 13 | 14 | //customization.plugins.settings.hideMachineSettings = true; 15 | //customization.plugins.settings.hideMachineName = true; 16 | customization.plugins.settings.hideMachineColor = true; 17 | 18 | //customization.plugins.settings.hideBindingSettings = true; 19 | //customization.plugins.settings.hideAuthSettings = true; 20 | 21 | //customization.plugins.settings.hideSSLSettings = true; 22 | //customization.plugins.settings.hideSSLClientAuthSettings = true; 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aj>=2.0.34 2 | pyyaml 3 | ajenti.plugin.core 4 | ajenti.plugin.settings 5 | ajenti.plugin.filemanager 6 | ajenti.plugin.notepad 7 | --------------------------------------------------------------------------------