diff --git a/.editorconfig b/.editorconfig index f640174..619e2bd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,9 @@ max_line_length = 99 tab_width = 4 trim_trailing_whitespace = true +[*.js] +indent_style = space + [*.py] indent_style = space diff --git a/web-greeter/bridge/ThemeUtils.py b/web-greeter/bridge/ThemeUtils.py index fb614ba..1167b9a 100644 --- a/web-greeter/bridge/ThemeUtils.py +++ b/web-greeter/bridge/ThemeUtils.py @@ -46,6 +46,7 @@ class ThemeUtils(BridgeObject): self._greeter = greeter self._allowed_dirs = ( + os.path.dirname(self._config["config"]["greeter"]["theme"]), self._config["app"]["theme_dir"], self._config["config"]["branding"]["background_images_dir"], self._greeter.shared_data_directory, @@ -57,6 +58,9 @@ class ThemeUtils(BridgeObject): if not dir_path or not isinstance(dir_path, str) or '/' == dir_path: return [] + if (dir_path.startswith("./")): + dir_path = os.path.join(os.path.dirname(self._config["config"]["greeter"]["theme"]), dir_path) + dir_path = os.path.realpath(os.path.normpath(dir_path)) if not os.path.isabs(dir_path) or not os.path.isdir(dir_path): diff --git a/web-greeter/resources/js/ThemeUtils.js b/web-greeter/resources/js/ThemeUtils.js index e745aca..cd3e3dc 100644 --- a/web-greeter/resources/js/ThemeUtils.js +++ b/web-greeter/resources/js/ThemeUtils.js @@ -25,10 +25,8 @@ * along with web-greeter; If not, see . */ - let time_language = null, - _ThemeUtils = null; - + _ThemeUtils = null; /** * Provides various utility methods for use in greeter themes. The greeter will automatically @@ -38,139 +36,138 @@ let time_language = null, * @memberOf LightDM */ class ThemeUtils { - - constructor( instance ) { - if ( null !== _ThemeUtils ) { - return _ThemeUtils; - } - - _ThemeUtils = instance; - } - - /** - * Binds `this` to class, `context`, for all of the class's methods. - * - * @arg {object} context An ES6 class instance with at least one method. - * - * @return {object} `context` with `this` bound to it for all of its methods. - */ - bind_this( context ) { - let excluded_methods = ['constructor']; - - function not_excluded( _method, _context ) { - let is_excluded = excluded_methods.findIndex( excluded_method => _method === excluded_method ) > -1, - is_method = 'function' === typeof _context[_method]; - - return is_method && !is_excluded; - } - - for ( let obj = context; obj; obj = Object.getPrototypeOf( obj ) ) { - // Stop once we have traveled all the way up the inheritance chain - if ( 'Object' === obj.constructor.name ) { - break; - } - - for ( let method of Object.getOwnPropertyNames( obj ) ) { - if ( not_excluded( method, context ) ) { - context[method] = context[method].bind( context ); - } - } - } - - return context; - } - - - /** - * Returns the contents of directory found at `path` provided that the (normalized) `path` - * meets at least one of the following conditions: - * * Is located within the greeter themes' root directory. - * * Has been explicitly allowed in the greeter's config file. - * * Is located within the greeter's shared data directory (`/var/lib/lightdm-data`). - * * Is located in `/tmp`. - * - * @param {string} path The abs path to desired directory. - * @param {boolean} only_images Include only images in the results. Default `true`. - * @param {function(string[])} callback Callback function to be called with the result. - */ - dirlist( path, only_images = true, callback ) { - if ( '' === path || 'string' !== typeof path ) { - console.error(`theme_utils.dirlist(): path must be a non-empty string!`); - return callback([]); - - } else if ( null !== path.match(/^[^/].+/) ) { - console.error(`theme_utils.dirlist(): path must be absolute!`); - return callback([]); - } - - if ( null !== path.match(/\/\.+(?=\/)/) ) { - // No special directory names allowed (eg ../../) - path = path.replace(/\/\.+(?=\/)/g, '' ); - } - - try { - return _ThemeUtils.dirlist( path, only_images, callback ); - } catch( err ) { - console.error(`theme_utils.dirlist(): ${err}`); - return callback([]); - } - } - - /** - * Get the current date in a localized format. Local language is autodetected by default, but can be set manually in the greeter config file. - * * `language` defaults to the system's language, but can be set manually in the config file. - * - * @returns {Object} The current date. - */ - get_current_localized_date() { - let config = greeter_config.greeter - - var locale = [] - - if (time_language === null) { - time_language = config.time_language || "" - } - - if (time_language != "") { - locale.push(time_language) - } - - let optionsDate = { day: "2-digit", month: "2-digit", year: "2-digit" } - - let fmtDate = Intl.DateTimeFormat(locale, optionsDate) - - let now = new Date() - var date = fmtDate.format(now) - - return date - } - - /** - * Get the current time in a localized format. Local language is autodetected by default, but can be set manually in the greeter config file. - * * `language` defaults to the system's language, but can be set manually in the config file. - * - * @returns {Object} The current time. - */ - get_current_localized_time() { - let config = greeter_config.greeter - - var locale = [] - - if (time_language === null) { - time_language = config.time_language || "" - } - - if (time_language != "") { - locale.push(time_language) - } - - let optionsTime = { hour: "2-digit", minute: "2-digit" } - - let fmtTime = Intl.DateTimeFormat(locale, optionsTime) - - let now = new Date() - var time = fmtTime.format(now) - - return time - } + constructor(instance) { + if (null !== _ThemeUtils) { + return _ThemeUti; + } + ls; + + _ThemeUtils = instance; + } + + /** + * Binds `this` to class, `context`, for all of the class's methods. + * + * @arg {object} context An ES6 class instance with at least one method. + * + * @return {object} `context` with `this` bound to it for all of its methods. + */ + bind_this(context) { + let excluded_methods = ["constructor"]; + + function not_excluded(_method, _context) { + let is_excluded = + excluded_methods.findIndex((excluded_method) => _method === excluded_method) > + -1, + is_method = "function" === typeof _context[_method]; + + return is_method && !is_excluded; + } + + for (let obj = context; obj; obj = Object.getPrototypeOf(obj)) { + // Stop once we have traveled all the way up the inheritance chain + if ("Object" === obj.constructor.name) { + break; + } + + for (let method of Object.getOwnPropertyNames(obj)) { + if (not_excluded(method, context)) { + context[method] = context[method].bind(context); + } + } + } + + return context; + } + + /** + * Returns the contents of directory found at `path` provided that the (normalized) `path` + * meets at least one of the following conditions: + * * Is located within the greeter themes' root directory. + * * Has been explicitly allowed in the greeter's config file. + * * Is located within the greeter's shared data directory (`/var/lib/lightdm-data`). + * * Is located in `/tmp`. + * + * @param {string} path The abs path to desired directory. + * @param {boolean} only_images Include only images in the results. Default `true`. + * @param {function(string[])} callback Callback function to be called with the result. + */ + dirlist(path, only_images = true, callback) { + if ("" === path || "string" !== typeof path) { + console.error(`theme_utils.dirlist(): path must be a non-empty string!`); + return callback([]); + } else if (null !== path.match(/^[^/].+/)) { + return _ThemeUtils.dirlist(path, only_images, callback); + } + + if (null !== path.match(/\/\.+(?=\/)/)) { + // No special directory names allowed (eg ../../) + path = path.replace(/\/\.+(?=\/)/g, ""); + } + + try { + return _ThemeUtils.dirlist(path, only_images, callback); + } catch (err) { + console.error(`theme_utils.dirlist(): ${err}`); + return callback([]); + } + } + + /** + * Get the current date in a localized format. Local language is autodetected by default, but can be set manually in the greeter config file. + * * `language` defaults to the system's language, but can be set manually in the config file. + * + * @returns {Object} The current date. + */ + get_current_localized_date() { + let config = greeter_config.greeter; + + var locale = []; + + if (time_language === null) { + time_language = config.time_language || ""; + } + + if (time_language != "") { + locale.push(time_language); + } + + let optionsDate = { day: "2-digit", month: "2-digit", year: "2-digit" }; + + let fmtDate = Intl.DateTimeFormat(locale, optionsDate); + + let now = new Date(); + var date = fmtDate.format(now); + + return date; + } + + /** + * Get the current time in a localized format. Local language is autodetected by default, but can be set manually in the greeter config file. + * * `language` defaults to the system's language, but can be set manually in the config file. + * + * @returns {Object} The current time. + */ + get_current_localized_time() { + let config = greeter_config.greeter; + + var locale = []; + + if (time_language === null) { + time_language = config.time_language || ""; + } + + if (time_language != "") { + locale.push(time_language); + } + + let optionsTime = { hour: "2-digit", minute: "2-digit" }; + + let fmtTime = Intl.DateTimeFormat(locale, optionsTime); + + let now = new Date(); + var time = fmtTime.format(now); + + return time; + } } diff --git a/web-greeter/resources/js/bootstrap.js b/web-greeter/resources/js/bootstrap.js index d9a8cb6..4c7070f 100644 --- a/web-greeter/resources/js/bootstrap.js +++ b/web-greeter/resources/js/bootstrap.js @@ -26,49 +26,49 @@ */ (() => { - let _channel; + let _channel; - /** - * Greeter Ready Event. Themes should not initialize until this event has fired. - * @event window#GreeterReady - * @name GreeterReady - * @type Event - * @memberOf window - */ - window._ready_event = new Event("GreeterReady"); + /** + * Greeter Ready Event. Themes should not initialize until this event has fired. + * @event window#GreeterReady + * @name GreeterReady + * @type Event + * @memberOf window + */ + window._ready_event = new Event("GreeterReady"); - function channel_ready_cb(channel) { - _channel = channel; + function channel_ready_cb(channel) { + _channel = channel; - /** - * Greeter Instance - * @name lightdm - * @type {LightDM.Greeter} - * @memberOf window - */ - window.lightdm = _channel.objects.LightDMGreeter; + /** + * 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; + /** + * Greeter Config - Access values from the greeter's config file. + * @name greeter_config + * @type {LightDM.GreeterConfig} + * @memberOf window + */ + window.greeter_config = _channel.objects.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); - } - new QWebChannel(qt.webChannelTransport, channel_ready_cb); + /** + * 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); + } + new QWebChannel(qt.webChannelTransport, channel_ready_cb); - document.addEventListener("DOMContentLoaded", (event) => { - setTimeout(function () { - window.dispatchEvent(_ready_event); - }, 2); - }); + document.addEventListener("DOMContentLoaded", (event) => { + setTimeout(function () { + window.dispatchEvent(_ready_event); + }, 2); + }); })();