# Copyright (C) 2006-2007, Red Hat, Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. """User settings/configuration loading. """ from gi.repository import Gio import os import logging from six.moves.configparser import ConfigParser from sugar3 import env from sugar3 import util from sugar3.graphics.xocolor import XoColor import getpass _profile = None _journal_settings = None class Profile(object): """Local user's current options/profile information The profile is also responsible for loading the user's public and private ssh keys from disk. Attributes: pubkey -- public ssh key privkey_hash -- SHA has of the child's public key """ def __init__(self, path): self._pubkey = None self._privkey_hash = None def _get_pubkey(self): if self._pubkey is None: self._pubkey = self._load_pubkey() return self._pubkey pubkey = property(fget=_get_pubkey) def _get_privkey_hash(self): if self._privkey_hash is None: self._privkey_hash = self._hash_private_key() return self._privkey_hash privkey_hash = property(fget=_get_privkey_hash) def is_valid(self): nick = get_nick_name() color = get_color() return nick != '' and \ color != '' and \ self.pubkey is not None and \ self.privkey_hash is not None def _load_pubkey(self): key_path = os.path.join(env.get_profile_path(), 'owner.key.pub') if not os.path.exists(key_path): return None try: f = open(key_path, 'r') lines = f.readlines() f.close() except IOError: logging.exception('Error reading public key') return None magic = 'ssh-dss ' for line in lines: line = line.strip() if not line.startswith(magic): continue return line[len(magic):] else: logging.error('Error parsing public key.') return None def _hash_private_key(self): key_path = os.path.join(env.get_profile_path(), 'owner.key') if not os.path.exists(key_path): return None try: f = open(key_path, 'r') lines = f.readlines() f.close() except IOError: logging.exception('Error reading private key') return None key = "" begin_found = False end_found = False for line in lines: line = line.strip() if line.startswith(('-----BEGIN DSA PRIVATE KEY-----', '-----BEGIN OPENSSH PRIVATE KEY-----')): begin_found = True continue if line.startswith(('-----END DSA PRIVATE KEY-----', '-----END OPENSSH PRIVATE KEY-----')): end_found = True continue key += line if not (len(key) and begin_found and end_found): logging.error('Error parsing public key.') return None # hash it key_hash = util.sha_data(key) return util.printable_hash(key_hash) def convert_profile(self): cp = ConfigParser() path = os.path.join(env.get_profile_path(), 'config') cp.read([path]) settings = Gio.Settings('org.sugarlabs.user') if cp.has_option('Buddy', 'NickName'): name = cp.get('Buddy', 'NickName') # decode nickname from ascii-safe chars to unicode nick = name.decode('utf-8') settings.set_string('nick', nick) if cp.has_option('Buddy', 'Color'): color = cp.get('Buddy', 'Color') settings.set_string('color', color) if cp.has_option('Jabber', 'Server'): server = cp.get('Jabber', 'Server') settings = Gio.Settings('org.sugarlabs.collaboration') settings.set_string('jabber-server', server) if cp.has_option('Date', 'Timezone'): timezone = cp.get('Date', 'Timezone') settings = Gio.Settings('org.sugarlabs.date') settings.set_string('timezone', timezone) settings = Gio.Settings('org.sugarlabs.frame') if cp.has_option('Frame', 'HotCorners'): delay = float(cp.get('Frame', 'HotCorners')) settings.set_int('corner-delay', int(delay)) if cp.has_option('Frame', 'WarmEdges'): delay = float(cp.get('Frame', 'WarmEdges')) settings.set_int('edge-delay', int(delay)) if cp.has_option('Server', 'Backup1'): backup1 = cp.get('Server', 'Backup1') settings = Gio.Settings('org.sugarlabs') settings.set_string('backup-url', backup1) if cp.has_option('Sound', 'Volume'): volume = float(cp.get('Sound', 'Volume')) settings = Gio.Settings('org.sugarlabs.sound') settings.set_int('volume', int(volume)) settings = Gio.Settings('org.sugarlabs.power') if cp.has_option('Power', 'AutomaticPM'): state = cp.get('Power', 'AutomaticPM') if state.lower() == 'true': settings.set_boolean('automatic', True) if cp.has_option('Power', 'ExtremePM'): state = cp.get('Power', 'ExtremePM') if state.lower() == 'true': settings.set_boolean('extreme', True) if cp.has_option('Shell', 'FavoritesLayout'): layout = cp.get('Shell', 'FavoritesLayout') settings = Gio.Settings('org.sugarlabs.desktop') settings.set_string('favorites-layout', layout) del cp try: os.unlink(path) except OSError: logging.error('Error removing old profile.') def get_profile(): global _profile if not _profile: path = os.path.join(env.get_profile_path(), 'config') _profile = Profile(path) return _profile def get_nick_name(): if 'org.sugarlabs.user' in Gio.Settings.list_schemas(): settings = Gio.Settings('org.sugarlabs.user') return settings.get_string('nick') else: return getpass.getuser() def get_color(): if 'org.sugarlabs.user' in Gio.Settings.list_schemas(): settings = Gio.Settings('org.sugarlabs.user') color = settings.get_string('color') return XoColor(color) else: return XoColor() def get_pubkey(): return get_profile().pubkey def _get_journal_settings_boolean(name, default): global _journal_settings if not _journal_settings: if 'org.sugarlabs.journal' not in Gio.Settings.list_schemas(): return default _journal_settings = Gio.Settings('org.sugarlabs.journal') if name not in _journal_settings.list_keys(): return default return _journal_settings.get_boolean(name) def get_save_as(): return _get_journal_settings_boolean('save-as', False)