Browse Source

Allowed relative path with theme_utils.dirlist

sisyphus
JezerM 3 years ago
parent
commit
ca421e701e
No known key found for this signature in database
GPG Key ID: 66BBC5D01388C6B5
  1. 3
      .editorconfig
  2. 4
      web-greeter/bridge/ThemeUtils.py
  3. 273
      web-greeter/resources/js/ThemeUtils.js
  4. 78
      web-greeter/resources/js/bootstrap.js

3
.editorconfig

@ -14,6 +14,9 @@ max_line_length = 99
tab_width = 4 tab_width = 4
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.js]
indent_style = space
[*.py] [*.py]
indent_style = space indent_style = space

4
web-greeter/bridge/ThemeUtils.py

@ -46,6 +46,7 @@ class ThemeUtils(BridgeObject):
self._greeter = greeter self._greeter = greeter
self._allowed_dirs = ( self._allowed_dirs = (
os.path.dirname(self._config["config"]["greeter"]["theme"]),
self._config["app"]["theme_dir"], self._config["app"]["theme_dir"],
self._config["config"]["branding"]["background_images_dir"], self._config["config"]["branding"]["background_images_dir"],
self._greeter.shared_data_directory, 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: if not dir_path or not isinstance(dir_path, str) or '/' == dir_path:
return [] 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)) dir_path = os.path.realpath(os.path.normpath(dir_path))
if not os.path.isabs(dir_path) or not os.path.isdir(dir_path): if not os.path.isabs(dir_path) or not os.path.isdir(dir_path):

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

@ -25,10 +25,8 @@
* along with web-greeter; If not, see <http://www.gnu.org/licenses/>. * along with web-greeter; If not, see <http://www.gnu.org/licenses/>.
*/ */
let time_language = null, let time_language = null,
_ThemeUtils = null; _ThemeUtils = null;
/** /**
* Provides various utility methods for use in greeter themes. The greeter will automatically * Provides various utility methods for use in greeter themes. The greeter will automatically
@ -38,139 +36,138 @@ let time_language = null,
* @memberOf LightDM * @memberOf LightDM
*/ */
class ThemeUtils { class ThemeUtils {
constructor(instance) {
constructor( instance ) { if (null !== _ThemeUtils) {
if ( null !== _ThemeUtils ) { return _ThemeUti;
return _ThemeUtils; }
} ls;
_ThemeUtils = instance; _ThemeUtils = instance;
} }
/** /**
* Binds `this` to class, `context`, for all of the class's methods. * Binds `this` to class, `context`, for all of the class's methods.
* *
* @arg {object} context An ES6 class instance with at least one method. * @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. * @return {object} `context` with `this` bound to it for all of its methods.
*/ */
bind_this( context ) { bind_this(context) {
let excluded_methods = ['constructor']; let excluded_methods = ["constructor"];
function not_excluded( _method, _context ) { function not_excluded(_method, _context) {
let is_excluded = excluded_methods.findIndex( excluded_method => _method === excluded_method ) > -1, let is_excluded =
is_method = 'function' === typeof _context[_method]; excluded_methods.findIndex((excluded_method) => _method === excluded_method) >
-1,
return is_method && !is_excluded; 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 ) { for (let obj = context; obj; obj = Object.getPrototypeOf(obj)) {
break; // 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 ); for (let method of Object.getOwnPropertyNames(obj)) {
} if (not_excluded(method, context)) {
} context[method] = context[method].bind(context);
} }
}
return context; }
}
return context;
}
/**
* Returns the contents of directory found at `path` provided that the (normalized) `path` /**
* meets at least one of the following conditions: * Returns the contents of directory found at `path` provided that the (normalized) `path`
* * Is located within the greeter themes' root directory. * meets at least one of the following conditions:
* * Has been explicitly allowed in the greeter's config file. * * Is located within the greeter themes' root directory.
* * Is located within the greeter's shared data directory (`/var/lib/lightdm-data`). * * Has been explicitly allowed in the greeter's config file.
* * Is located in `/tmp`. * * 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 {string} path The abs path to desired directory.
* @param {function(string[])} callback Callback function to be called with the result. * @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 ) { dirlist(path, only_images = true, callback) {
console.error(`theme_utils.dirlist(): path must be a non-empty string!`); if ("" === path || "string" !== typeof path) {
return callback([]); console.error(`theme_utils.dirlist(): path must be a non-empty string!`);
return callback([]);
} else if ( null !== path.match(/^[^/].+/) ) { } else if (null !== path.match(/^[^/].+/)) {
console.error(`theme_utils.dirlist(): path must be absolute!`); return _ThemeUtils.dirlist(path, only_images, callback);
return callback([]); }
}
if (null !== path.match(/\/\.+(?=\/)/)) {
if ( null !== path.match(/\/\.+(?=\/)/) ) { // No special directory names allowed (eg ../../)
// No special directory names allowed (eg ../../) path = path.replace(/\/\.+(?=\/)/g, "");
path = path.replace(/\/\.+(?=\/)/g, '' ); }
}
try {
try { return _ThemeUtils.dirlist(path, only_images, callback);
return _ThemeUtils.dirlist( path, only_images, callback ); } catch (err) {
} catch( err ) { console.error(`theme_utils.dirlist(): ${err}`);
console.error(`theme_utils.dirlist(): ${err}`); return callback([]);
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.
* 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.
* * `language` defaults to the system's language, but can be set manually in the config file. *
* * @returns {Object} The current date.
* @returns {Object} The current date. */
*/ get_current_localized_date() {
get_current_localized_date() { let config = greeter_config.greeter;
let config = greeter_config.greeter
var locale = [];
var locale = []
if (time_language === null) {
if (time_language === null) { time_language = config.time_language || "";
time_language = config.time_language || "" }
}
if (time_language != "") {
if (time_language != "") { locale.push(time_language);
locale.push(time_language) }
}
let optionsDate = { day: "2-digit", month: "2-digit", year: "2-digit" };
let optionsDate = { day: "2-digit", month: "2-digit", year: "2-digit" }
let fmtDate = Intl.DateTimeFormat(locale, optionsDate);
let fmtDate = Intl.DateTimeFormat(locale, optionsDate)
let now = new Date();
let now = new Date() var date = fmtDate.format(now);
var date = fmtDate.format(now)
return date;
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.
* 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.
* * `language` defaults to the system's language, but can be set manually in the config file. *
* * @returns {Object} The current time.
* @returns {Object} The current time. */
*/ get_current_localized_time() {
get_current_localized_time() { let config = greeter_config.greeter;
let config = greeter_config.greeter
var locale = [];
var locale = []
if (time_language === null) {
if (time_language === null) { time_language = config.time_language || "";
time_language = config.time_language || "" }
}
if (time_language != "") {
if (time_language != "") { locale.push(time_language);
locale.push(time_language) }
}
let optionsTime = { hour: "2-digit", minute: "2-digit" };
let optionsTime = { hour: "2-digit", minute: "2-digit" }
let fmtTime = Intl.DateTimeFormat(locale, optionsTime);
let fmtTime = Intl.DateTimeFormat(locale, optionsTime)
let now = new Date();
let now = new Date() var time = fmtTime.format(now);
var time = fmtTime.format(now)
return time;
return time }
}
} }

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

@ -26,49 +26,49 @@
*/ */
(() => { (() => {
let _channel; let _channel;
/** /**
* Greeter Ready Event. Themes should not initialize until this event has fired. * Greeter Ready Event. Themes should not initialize until this event has fired.
* @event window#GreeterReady * @event window#GreeterReady
* @name GreeterReady * @name GreeterReady
* @type Event * @type Event
* @memberOf window * @memberOf window
*/ */
window._ready_event = new Event("GreeterReady"); window._ready_event = new Event("GreeterReady");
function channel_ready_cb(channel) { function channel_ready_cb(channel) {
_channel = channel; _channel = channel;
/** /**
* Greeter Instance * Greeter Instance
* @name lightdm * @name lightdm
* @type {LightDM.Greeter} * @type {LightDM.Greeter}
* @memberOf window * @memberOf window
*/ */
window.lightdm = _channel.objects.LightDMGreeter; window.lightdm = _channel.objects.LightDMGreeter;
/** /**
* Greeter Config - Access values from the greeter's config file. * Greeter Config - Access values from the greeter's config file.
* @name greeter_config * @name greeter_config
* @type {LightDM.GreeterConfig} * @type {LightDM.GreeterConfig}
* @memberOf window * @memberOf window
*/ */
window.greeter_config = _channel.objects.Config; window.greeter_config = _channel.objects.Config;
/** /**
* Theme Utils - various utility methods for use in greeter themes. * Theme Utils - various utility methods for use in greeter themes.
* @name theme_utils * @name theme_utils
* @type {LightDM.ThemeUtils} * @type {LightDM.ThemeUtils}
* @memberOf window * @memberOf window
*/ */
window.theme_utils = new ThemeUtils(_channel.objects.ThemeUtils); window.theme_utils = new ThemeUtils(_channel.objects.ThemeUtils);
} }
new QWebChannel(qt.webChannelTransport, channel_ready_cb); new QWebChannel(qt.webChannelTransport, channel_ready_cb);
document.addEventListener("DOMContentLoaded", (event) => { document.addEventListener("DOMContentLoaded", (event) => {
setTimeout(function () { setTimeout(function () {
window.dispatchEvent(_ready_event); window.dispatchEvent(_ready_event);
}, 2); }, 2);
}); });
})(); })();

Loading…
Cancel
Save