Browse Source

progress on python port, passed the halfway point now.

sisyphus
Dustin Falgout 8 years ago
parent
commit
cbdb33eb97
  1. 2
      .gitignore
  2. 2
      meson.build
  3. 10
      web-greeter/bridge/Config.py
  4. 51
      web-greeter/bridge/Greeter.py
  5. 79
      web-greeter/bridge/ThemeUtils.py
  6. 28
      web-greeter/greeter.py
  7. 38
      web-greeter/interceptor.py
  8. 27
      web-greeter/meson.build
  9. 105
      web-greeter/resources/js/ThemeUtils.js
  10. 12932
      web-greeter/resources/js/_vendor/moment-with-locales.min.js
  11. 45
      web-greeter/resources/js/bootstrap.js
  12. 36
      web-greeter/resources/js/docs/Greeter.js
  13. 21
      web-greeter/resources/js/docs/GreeterConfig.js

2
.gitignore vendored

@ -1,3 +1,5 @@
bundle.js
resources.py
build/**
!build/.gitignore
!build/ci/Dockerfile

2
meson.build

@ -1,4 +1,4 @@
project('lightdm-webkit2-greeter', 'c', version: '2.2.2', license: 'GPL-3')
project('lightdm-webkit2-greeter', 'python', version: '3.0.0', license: 'GPL-3')
# ================================== #
# ------->>> Version Vars <<<------- #

10
web-greeter/bridge/Config.py

@ -27,12 +27,10 @@
# along with Web Greeter; If not, see <http://www.gnu.org/licenses/>.
# 3rd-Party Libs
from PyQt5.QtCore import QVariant
# This Application
from whither.bridge import (
BridgeObject,
bridge,
Variant,
)
@ -41,12 +39,12 @@ class Config(BridgeObject):
def __init__(self, config, *args, **kwargs):
super().__init__(name='Config', *args, **kwargs)
self._branding, self._greeter = config.branding, config.greeter
self._branding, self._greeter = config.branding.as_dict(), config.greeter.as_dict()
@bridge.prop(QVariant)
@bridge.prop(Variant)
def branding(self):
return self._branding
@bridge.prop(QVariant)
@bridge.prop(Variant)
def greeter(self):
return self._greeter

51
web-greeter/bridge/Greeter.py

@ -32,10 +32,10 @@
import gi
gi.require_version('LightDM', '1')
from gi.repository import LightDM
from PyQt5.QtCore import QVariant
from whither.bridge import (
BridgeObject,
bridge,
Variant,
)
# This Application
@ -48,24 +48,33 @@ from . import (
LightDMGreeter = LightDM.Greeter()
LightDMUserList = LightDM.UserList()
LightDMUsers = LightDM.UserList()
class Greeter(BridgeObject):
authentication_complete = bridge.signal()
autologin_timer_expired = bridge.signal()
idle = bridge.signal()
reset = bridge.signal()
show_message = bridge.signal(str, str, arguments=('text', 'type'))
show_prompt = bridge.signal(str, str, arguments=('text', 'type'))
authentication_complete = bridge.signal(LightDM.Greeter)
autologin_timer_expired = bridge.signal(LightDM.Greeter)
idle = bridge.signal(LightDM.Greeter)
reset = bridge.signal(LightDM.Greeter)
show_message = bridge.signal((LightDM.Greeter, str, str), arguments=('text', 'type'))
show_prompt = bridge.signal((LightDM.Greeter, str, str), arguments=('text', 'type'))
def __init__(self, *args, **kwargs):
def __init__(self, themes_dir, *args, **kwargs):
super().__init__(name='LightDMGreeter', *args, **kwargs)
self._shared_data_directory = ''
self._themes_directory = themes_dir
LightDMGreeter.connect_to_daemon_sync()
self._connect_signals()
self._determine_shared_data_directory_path()
def _determine_shared_data_directory_path(self):
user = LightDMUsers.get_users()[0]
user_data_dir = LightDMGreeter.ensure_shared_data_dir_sync(user.get_name())
self._shared_data_directory = user_data_dir.rpartition('/')[0]
def _connect_signals(self):
LightDMGreeter.connect('authentication-complete', self.authentication_complete.emit)
@ -131,19 +140,19 @@ class Greeter(BridgeObject):
def is_authenticated(self):
return LightDMGreeter.get_is_authenticated()
@bridge.prop(QVariant)
@bridge.prop(Variant)
def language(self):
return language_to_dict(LightDM.get_language())
@bridge.prop(list)
@bridge.prop(Variant)
def languages(self):
return [language_to_dict(lang) for lang in LightDM.get_languages()]
@bridge.prop(QVariant)
@bridge.prop(Variant)
def layout(self):
return layout_to_dict(LightDM.get_layout())
@bridge.prop(list)
@bridge.prop(Variant)
def layouts(self):
return [layout_to_dict(layout) for layout in LightDM.get_layouts()]
@ -151,7 +160,7 @@ class Greeter(BridgeObject):
def lock_hint(self):
return LightDMGreeter.get_lock_hint()
@bridge.prop(list)
@bridge.prop(Variant)
def remote_sessions(self):
return [session_to_dict(session) for session in LightDM.get_remote_sessions()]
@ -163,10 +172,14 @@ class Greeter(BridgeObject):
def select_user_hint(self):
return LightDMGreeter.get_select_user_hint() or ''
@bridge.prop(QVariant)
@bridge.prop(Variant)
def sessions(self):
return [session_to_dict(session) for session in LightDM.get_sessions()]
@bridge.prop(str)
def shared_data_directory(self):
return self._shared_data_directory
@bridge.prop(bool)
def show_manual_login_hint(self):
return LightDMGreeter.get_show_manual_login_hint()
@ -175,9 +188,13 @@ class Greeter(BridgeObject):
def show_remote_login_hint(self):
return LightDMGreeter.get_show_remote_login_hint()
@bridge.prop(QVariant)
@bridge.prop(str)
def themes_directory(self):
return self._themes_directory
@bridge.prop(Variant)
def users(self):
return [user_to_dict(user) for user in LightDMUserList.get_users()]
return [user_to_dict(user) for user in LightDMUsers.get_users()]
@bridge.method(str)
def authenticate(self, username):

79
web-greeter/bridge/ThemeUtils.py

@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ThemeUtils.py
#
# Copyright © 2017 Antergos
#
# This file is part of Web Greeter.
#
# Web Greeter is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Web Greeter is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# The following additional terms are in effect as per Section 7 of the license:
#
# The preservation of all legal notices and author attributions in
# the material or in the Appropriate Legal Notices displayed
# by works containing it is required.
#
# You should have received a copy of the GNU General Public License
# along with Web Greeter; If not, see <http://www.gnu.org/licenses/>.
# Standard Lib
import os
import os.path as path
# 3rd-Party Libs
from whither.bridge import (
BridgeObject,
bridge,
Variant,
)
class ThemeUtils(BridgeObject):
def __init__(self, greeter, config, user_config, *args, **kwargs):
super().__init__(name='ThemeUtils', *args, **kwargs)
self._config = config
self._user_config = user_config
self._greeter = greeter
@bridge.method(Variant)
def dirlist(self, dir_path):
if not dir_path or not isinstance(dir_path, str):
return []
dir_path = path.realpath(path.normpath(dir_path))
if not path.isabs(dir_path) or not path.isdir(dir_path):
return []
allowed = False
allowed_dirs = (
self._config.themes_dir,
self._user_config.branding.background_images,
self._greeter.shared_data_directory,
'/tmp/'
)
for allowed_dir in allowed_dirs:
if dir_path.startswith(allowed_dir):
allowed = True
break
if not allowed:
return []
return (path.join(dir_path, f) for f in os.listdir(dir_path))

28
web-greeter/greeter.py

@ -35,8 +35,17 @@ from whither.app import App
from whither.base.data import AttributeDict
# This Application
try:
# PyCharm quirkiness
from .resources import *
from .bridge.Greeter import Greeter
from .bridge.Config import Config
from .bridge.ThemeUtils import ThemeUtils
except ImportError:
import resources
from bridge.Greeter import Greeter
from bridge.Config import Config
from bridge.ThemeUtils import ThemeUtils
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
@ -44,17 +53,22 @@ CONFIG_FILE = os.path.join(BASE_DIR, 'whither.yml')
class WebGreeter(App):
_user_config = AttributeDict({})
_greeter = None
greeter = None
greeter_config = None
theme_utils = None
user_config = AttributeDict({})
def __init__(self, *args, **kwargs):
super().__init__('WebGreeter', config_file=CONFIG_FILE, debug=True, *args, **kwargs)
self.get_and_save_user_config()
self._greeter = Greeter()
self._web_container.bridge_objects = (self._greeter, Config(self._user_config))
self.greeter = Greeter(self.config.themes_dir)
self.greeter_config = Config(self.user_config)
self.theme_utils = ThemeUtils(self.greeter, self.config, self.user_config)
self._web_container.bridge_objects = (self.greeter, self.greeter_config, self.theme_utils)
self._web_container.initialize_bridge_objects()
self._web_container.load_script(':/_greeter/js/bundle.js', 'Web Greeter Bundle')
self.load_theme()
def get_and_save_user_config(self):
@ -63,15 +77,15 @@ class WebGreeter(App):
config.read('/etc/lightdm/web-greeter.conf')
for section in config.sections():
self._user_config[section] = {}
self.user_config[section] = {}
for key in config[section]:
self._user_config[section][key] = config[section][key]
self.user_config[section][key] = config[section][key]
def load_theme(self):
theme_url = 'file://{0}/{1}/index.html'.format(
self.config.themes_dir,
self._user_config.greeter.webkit_theme
self.user_config.greeter.webkit_theme
)
self._web_container.load(theme_url)

38
web-greeter/interceptor.py

@ -0,0 +1,38 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# interceptor.py
#
# Copyright © 2016-2017 Antergos
#
# This file is part of whither.
#
# whither is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# whither is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# The following additional terms are in effect as per Section 7 of the license:
#
# The preservation of all legal notices and author attributions in
# the material or in the Appropriate Legal Notices displayed
# by works containing it is required.
#
# You should have received a copy of the GNU General Public License
# along with whither; If not, see <http://www.gnu.org/licenses/>.
""" Url Request Interceptor """
# 3rd-Party Libs
from whither.bridge import UrlRequestInterceptor as Interceptor
class UrlRequestInterceptor(Interceptor):
def intercept_request(self, info):
self.interceptRequest(info)

27
src/meson.build → web-greeter/meson.build

@ -1,34 +1,15 @@
configure_file(output: 'config.h', configuration: conf)
with_webext_dir = get_option('with-webext-dir').split('"')
extdir = with_webext_dir[0]
# ================================ #
# ------->>> GResources <<<------- #
# ------->>> Resources <<<-------- #
# ================================ #
gresources_dir = include_directories('gresource')
gnome = import('gnome')
resource_dir = include_directories('resource')
qt5 = import('qt5')
utils = '@0@/utils.sh'.format(meson.build_root())
# Can't do it the right way until GLib 2.52 is released
# js_sources = run_command(utils, 'get-js-files').stdout().split()
js_sources = run_command(utils, 'combine-js')
#js_sources_combined = custom_target(
# 'javascript_sources',
# input: files(js_sources),
# output: 'bundle.js',
# command: [utils, 'combine-js']
#)
js_sources = run_command(utils, 'combine-js')
gresources = gnome.compile_resources(
'greeter-resources',
'gresource/greeter-resources.gresource.xml',
source_dir: 'gresource',
c_name: 'greeter_resources'
)
# ======================================= #
# ------->>> WebKit2 Extension <<<------- #

105
web-greeter/resources/js/ThemeUtils.js

@ -25,16 +25,27 @@
* along with lightdm-webkit2-greeter; If not, see <http://www.gnu.org/licenses/>.
*/
if ( 'undefined' === typeof window.navigator.languages ) {
/*if ( 'undefined' === typeof window.navigator.languages ) {
window.navigator.languages = [ window.navigator.language ];
}
}*/
moment.locale( window.navigator.languages );
let localized_invalid_date = moment('today', '!@#'),
let localized_invalid_date = null,
time_language = null,
time_format = null,
allowed_dirs = null;
allowed_dirs = null,
_ThemeUtils = null;
function _set_allowed_dirs() {
allowed_dirs = {
themes_dir: lightdm.themes_directory,
backgrounds_dir: greeter_config.branding.background_images,
lightdm_data_dir: lightdm.shared_data_directory,
tmpdir: '/tmp',
};
}
@ -46,6 +57,18 @@ let localized_invalid_date = moment('today', '!@#'),
* @memberOf LightDM
*/
class ThemeUtils {
constructor( instance ) {
if ( null !== _ThemeUtils ) {
return _ThemeUtils;
}
moment.locale( window.navigator.languages );
localized_invalid_date = moment('today', '!@#');
_ThemeUtils = instance;
}
/**
* Binds `this` to class, `context`, for all of the class's methods.
*
@ -91,15 +114,15 @@ class ThemeUtils {
* @returns {string[]} List of abs paths for the files and directories found in `path`.
*/
dirlist( path ) {
let allowed = true;
let allowed = false;
if ( '' === path || ! path instanceof String ) {
if ( '' === path || 'string' !== typeof path ) {
console.log('[ERROR] theme_utils.dirlist(): path must be a non-empty string!');
allowed = false;
return [];
} else if ( null !== path.match(/^[^/].+/) ) {
console.log('[ERROR] theme_utils.dirlist(): path must not include be absolute!');
allowed = false;
console.log('[ERROR] theme_utils.dirlist(): path must be absolute!');
return[];
}
if ( null !== path.match(/\/\.+(?=\/)/) ) {
@ -108,29 +131,16 @@ class ThemeUtils {
}
if ( null === allowed_dirs ) {
let user = lightdm.users.pop(),
user_data_dir = greeter_config.get_str( user.username, 'lightdm_data_dir' ),
lightdm_data_dir = user_data_dir.substr( 0, user_data_dir.lastIndexOf('/') );
allowed_dirs = {
themes_dir: greeter_config.get_str( 'greeter', 'themes_dir' ),
backgrounds_dir: greeter_config.get_str( 'branding', 'background_images' ),
lightdm_data_dir: lightdm_data_dir,
tmpdir: '/tmp',
};
_set_allowed_dirs();
}
if ( ! Object.keys( allowed_dirs ).some( dir => path.startsWith( allowed_dirs[dir] ) ) ) {
console.log(`[ERROR] theme_utils.dirlist(): path is not allowed: ${path}`);
allowed = false;
}
if ( ! allowed ) {
return [];
}
try {
return __ThemeUtils.dirlist( path );
return _ThemeUtils.dirlist( path );
} catch( err ) {
console.log( `[ERROR] theme_utils.dirlist(): ${err}` );
@ -192,7 +202,7 @@ class ThemeUtils {
*/
txt2html( text ) {
try {
return __ThemeUtils.txt2html( text );
return _ThemeUtils.esc_html( text );
} catch( err ) {
console.log( `[ERROR] theme_utils.dirlist(): ${err}` );
@ -200,46 +210,3 @@ class ThemeUtils {
}
}
}
const __theme_utils = new Promise( (resolve, reject) => {
let waiting = 0;
const check_window_prop = () => {
if ( waiting > 15000 ) {
return reject( 'Timeout Reached!');
}
setTimeout( () => {
waiting += 1;
if ( '__ThemeUtils' in window ) {
return resolve( (() => new ThemeUtils())() );
}
check_window_prop();
}, 0 );
};
check_window_prop();
});
/**
* Theme Utils - various utility methods for use in greeter themes.
* @name theme_utils
* @type {LightDM.ThemeUtils}
* @memberOf window
*/
__theme_utils.then( result => {
window.theme_utils = result;
/**
* ***Deprecated!*** Use {@link window.theme_utils} instead.
* @name greeterutil
* @type {LightDM.ThemeUtils}
* @memberOf window
* @deprecated
*/
window.greeterutil = window.theme_utils;
} );

12932
web-greeter/resources/js/_vendor/moment-with-locales.min.js vendored

File diff suppressed because it is too large Load Diff

45
web-greeter/resources/js/bootstrap.js vendored

@ -26,15 +26,58 @@
*/
let _channel;
const _ready_event = new Event( 'GreeterReady' );
function initialize() {
new QWebChannel( qt.webChannelTransport, channel => {
_channel = channel;
/**
* Greeter Instance
* @name lightdm
* @type {LightDM.Greeter}
* @memberOf window
*/
window.lightdm = _channel.objects.LightDMGreeter;
/**
* Greeter Config - Access values from the greeter's config file.
* @name greeter_config
* @type {LightDM.GreeterConfig}
* @memberOf window
*/
window.greeter_config = _channel.objects.Config;
/**
* ***Deprecated!*** Use {@link window.greeter_config} instead.
* @name config
* @type {LightDM.GreeterConfig}
* @memberOf window
* @deprecated
*/
window.config = window.greeter_config;
/**
* Theme Utils - various utility methods for use in greeter themes.
* @name theme_utils
* @type {LightDM.ThemeUtils}
* @memberOf window
*/
window.theme_utils = new ThemeUtils( _channel.objects.ThemeUtils );
/**
* ***Deprecated!*** Use {@link window.theme_utils} instead.
* @name greeterutil
* @type {LightDM.ThemeUtils}
* @memberOf window
* @deprecated
*/
window.greeterutil = window.theme_utils;
window.dispatchEvent( _ready_event );
});
}
$(window).on('load', initialize);
setTimeout( initialize, 50 );

36
web-greeter/resources/js/docs/Greeter.js

@ -302,42 +302,6 @@ class Greeter {
}
const __lightdm = new Promise( (resolve, reject) => {
let waiting = 0;
const check_window_prop = () => {
if ( waiting > 15000 ) {
return reject( 'Timeout Reached!');
}
setTimeout( () => {
waiting += 1;
if ( '__LightDMGreeter' in window ) {
return resolve( window.__LightDMGreeter );
}
check_window_prop();
}, 0 );
};
check_window_prop();
});
/**
* Greeter Instance
* @name lightdm
* @type {LightDM.Greeter}
* @memberOf window
*/
__lightdm.then( result => {
result.start_authentication = function( user ) { return this.authenticate( user ); };
result.start_authentication = result.start_authentication.bind(result);
window.lightdm = result
} );
/**
* Moment.js instance - Loaded and instantiated automatically by the greeter.
* @name moment

21
web-greeter/resources/js/docs/GreeterConfig.js

@ -35,7 +35,7 @@ function set_values( defaults, target_obj, method ) {
keys.forEach( prop => {
try {
target_obj[prop] = method( 'greeter', prop );
target_obj[prop] = window;
} catch(err) {
target_obj[prop] = defaults[prop];
}
@ -179,24 +179,5 @@ const __greeter_config = new Promise( (resolve, reject) => {
});
/**
* Greeter Config - Access values from the greeter's config file.
* @name greeter_config
* @type {LightDM.GreeterConfig}
* @memberOf window
*/
__greeter_config.then( result => {
window.greeter_config = result;
/**
* ***Deprecated!*** Use {@link window.greeter_config} instead.
* @name config
* @type {LightDM.GreeterConfig}
* @memberOf window
* @deprecated
*/
window.config = window.greeter_config;
} );

Loading…
Cancel
Save