Merge pull request #6179 from keymanapp/fix/linux/6171-shared

fix(linux): Don't crash if we lack permissions
This commit is contained in:
Eberhard Beilharz 2022-02-01 08:24:35 +01:00 committed by GitHub
commit c8aaad4884
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 243 deletions

View file

@ -23,6 +23,20 @@ def _(txt):
return translation
def secure_lookup(data, key1, key2 = None):
"""
Return data[key1][key2] while dealing with data being None or key1 or key2 not existing
"""
if not data:
return None
if key1 in data:
if not key2:
return data[key1]
if key2 in data[key1]:
return data[key1][key2]
return None
gettext.bindtextdomain('keyman-config', '/usr/share/locale')
gettext.textdomain('keyman-config')

View file

@ -69,34 +69,42 @@ def extractico(kmxfile):
"""
name, ext = os.path.splitext(kmxfile)
imagefilename = name
with open(kmxfile, mode='rb') as file: # b is important -> binary
fileContent = file.read()
bitmap = None
try:
with open(kmxfile, mode='rb') as file: # b is important -> binary
fileContent = file.read()
kmxstart = struct.unpack_from("<16I", fileContent, 0)
if kmxstart[0] != 0x5354584B:
logging.debug("bad kmx identifier")
return False
bitmapOffset = kmxstart[14]
bitmapSize = kmxstart[15]
logging.debug("bitmap offset is %d", bitmapOffset)
logging.debug("bitmap size is %d", bitmapSize)
file.seek(bitmapOffset, 0)
bitmap = file.read(bitmapSize)
if not bitmap or file.tell() != bitmapOffset + bitmapSize:
logging.debug("unreadable bitmap in kmx")
return False
kmxstart = struct.unpack_from("<16I", fileContent, 0)
if kmxstart[0] != 0x5354584B:
logging.debug("bad kmx identifier")
return False
bitmapOffset = kmxstart[14]
bitmapSize = kmxstart[15]
logging.debug("bitmap offset is %d", bitmapOffset)
logging.debug("bitmap size is %d", bitmapSize)
file.seek(bitmapOffset, 0)
bitmap = file.read(bitmapSize)
if not bitmap or file.tell() != bitmapOffset + bitmapSize:
logging.debug("unreadable bitmap in kmx")
return False
except Exception as e:
logging.warning('Exception %s extracting icon %s %s', type(e), kmxfile, e.args)
return False
# Read first two bytes to determine if icon is .bmp or .ico
if bitmap.startswith(b'BM'):
imagefilename = imagefilename + ".bmp"
else:
imagefilename = imagefilename + ".ico"
# Read first two bytes to determine if icon is .bmp or .ico
if bitmap.startswith(b'BM'):
imagefilename = imagefilename + ".bmp"
else:
imagefilename = imagefilename + ".ico"
try:
with open(imagefilename, mode='wb') as imagefile:
imagefile.write(bitmap)
checkandsaveico(imagefilename)
return True
except Exception as e:
logging.warning('Exception %s writing imagefile %s %s', type(e), imagefilename, e.args)
return False
return True
def main(argv):

View file

@ -1,7 +1,9 @@
#!/usr/bin/python3
import logging
import os
import threading
from keyman_config import secure_lookup
from keyman_config.install_kmp import process_keyboard_data
from keyman_config.kmpmetadata import parsemetadata
@ -27,10 +29,15 @@ class GetInfo(object):
rather then from the download window.
"""
for kmp in self.kmp_list:
packageDir = os.path.join(kmp['areapath'], kmp['packageID'])
process_keyboard_data(kmp['packageID'], packageDir)
packageId = secure_lookup(kmp, 'packageID')
areapath = secure_lookup(kmp, 'areapath')
if not areapath or not packageId:
logging.warning('corrupt kmp list')
return
packageDir = os.path.join(areapath, packageId)
process_keyboard_data(packageId, packageDir)
info, system, options, keyboards, files = parsemetadata(packageDir, "kmp.json")
if keyboards:
for kb in keyboards:
if kb['id'] != kmp['packageID']:
if kb['id'] != packageId:
process_keyboard_data(kb['id'], packageDir)

View file

@ -206,9 +206,13 @@ def download_kmp_file(url, kmpfile, cache=False):
requests_cache.uninstall_cache()
if response.status_code == 200:
with open(kmpfile, 'wb') as f:
f.write(response.content)
downloadfile = kmpfile
try:
with open(kmpfile, 'wb') as f:
f.write(response.content)
downloadfile = kmpfile
except Exception as e:
logging.warning('Exception %s writing downloaded file %s %s', type(e), kmpfile, e.args)
return None
return downloadfile

View file

@ -39,6 +39,8 @@ def _reset_gnome_shell():
def get_ibus_keyboard_id(keyboard, packageDir, language=None, ignore_language=False):
if not keyboard:
return None
kmx_file = os.path.join(packageDir, keyboard['id'] + ".kmx")
if ignore_language:
return kmx_file

View file

@ -7,7 +7,7 @@ import zipfile
from shutil import rmtree
from enum import Enum
from keyman_config import _
from keyman_config import _, secure_lookup
from keyman_config.canonical_language_code_utils import CanonicalLanguageCodeUtils
from keyman_config.fcitx_util import is_fcitx_running, restart_fcitx
from keyman_config.get_kmp import get_keyboard_data, get_keyboard_dir, get_keyman_doc_dir
@ -119,7 +119,7 @@ class InstallKmp():
info, _, _, keyboards, files = get_metadata(self.packageDir)
if keyboards:
logging.info("Installing %s", info['name']['description'])
logging.info("Installing %s", secure_lookup(info, 'name', 'description'))
if online:
process_keyboard_data(self.packageID, self.packageDir)
for kb in keyboards:
@ -199,7 +199,7 @@ class InstallKmp():
def install_keyboards(self, keyboards, packageDir, language=None):
firstKeyboard = keyboards[0]
if firstKeyboard and 'languages' in firstKeyboard and len(firstKeyboard['languages']) > 0:
if secure_lookup(firstKeyboard, 'languages') and len(firstKeyboard['languages']) > 0:
language = self._normalize_language(firstKeyboard['languages'], language)
if is_fcitx_running():
@ -249,12 +249,19 @@ def extract_kmp(kmpfile, directory):
def process_keyboard_data(keyboardID, packageDir):
kbdata = get_keyboard_data(keyboardID)
if kbdata:
if not os.path.isdir(packageDir):
os.makedirs(packageDir)
if not os.path.isdir(packageDir) and os.access(os.path.join(packageDir, os.pardir), os.X_OK | os.W_OK):
try:
os.makedirs(packageDir)
except Exception as e:
logging.warning('Exception %s creating %s %s', type(e), packageDir, e.args)
with open(os.path.join(packageDir, keyboardID + '.json'), 'w') as outfile:
json.dump(kbdata, outfile)
logging.info("Installing api data file %s.json as keyman file", keyboardID)
if os.access(packageDir, os.X_OK | os.W_OK):
try:
with open(os.path.join(packageDir, keyboardID + '.json'), 'w') as outfile:
json.dump(kbdata, outfile)
logging.info("Installing api data file %s.json as keyman file", keyboardID)
except Exception as e:
logging.warning('Exception %s writing %s/%s.json %s', type(e), packageDir, keyboardID, e.args)
# else:
# message = "install_kmp.py: error: cannot download keyboard data so not installing."
# rmtree(kbdir)

View file

@ -16,7 +16,7 @@ gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2
from distutils.version import StrictVersion
from keyman_config import _
from keyman_config import _, secure_lookup
from keyman_config.fcitx_util import is_fcitx_running
from keyman_config.install_kmp import install_kmp, extract_kmp, get_metadata, InstallError, InstallStatus
from keyman_config.list_installed_kmp import get_kmp_version
@ -80,8 +80,8 @@ class InstallKmpWindow(Gtk.Dialog):
self.kbname = keyboardid
self.checkcontinue = True
if installed_kmp_ver and info and 'version' in info and 'description' in info['version']:
if info['version']['description'] == installed_kmp_ver:
if installed_kmp_ver and secure_lookup(info, 'version', 'description'):
if secure_lookup(info, 'version', 'description') == installed_kmp_ver:
dialog = Gtk.MessageDialog(
viewkmp, 0, Gtk.MessageType.QUESTION,
Gtk.ButtonsType.YES_NO, _("Keyboard is installed already"))
@ -100,9 +100,9 @@ class InstallKmpWindow(Gtk.Dialog):
return
else:
try:
logging.info("package version %s", info['version']['description'])
logging.info("package version %s", secure_lookup(info, 'version', 'description'))
logging.info("installed kmp version %s", installed_kmp_ver)
if StrictVersion(info['version']['description']) <= StrictVersion(installed_kmp_ver):
if StrictVersion(secure_lookup(info, 'version', 'description')) <= StrictVersion(installed_kmp_ver):
dialog = Gtk.MessageDialog(
viewkmp, 0, Gtk.MessageType.QUESTION,
Gtk.ButtonsType.YES_NO, _("Keyboard is installed already"))
@ -110,7 +110,7 @@ class InstallKmpWindow(Gtk.Dialog):
_("The {name} keyboard is already installed with a newer version {installedversion}. "
"Do you want to uninstall it and install the older version {version}?")
.format(name=self.kbname, installedversion=installed_kmp_ver,
version=info['version']['description']))
version=secure_lookup(info, 'version', 'description')))
response = dialog.run()
dialog.destroy()
if response == Gtk.ResponseType.YES:
@ -125,7 +125,7 @@ class InstallKmpWindow(Gtk.Dialog):
pass
image = Gtk.Image()
if options and "graphicFile" in options:
if secure_lookup(options, 'graphicFile'):
image.set_from_file(os.path.join(tmpdirname, options['graphicFile']))
else:
img_default = find_keyman_image("defaultpackage.gif")
@ -186,13 +186,13 @@ class InstallKmpWindow(Gtk.Dialog):
grid.attach_next_to(label3, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = label3
label = Gtk.Label()
if info and 'version' in info and 'description' in info['version']:
label.set_text(info['version']['description'])
if secure_lookup(info, 'version', 'description'):
label.set_text(secure_lookup(info, 'version', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, label3, Gtk.PositionType.RIGHT, 1, 1)
if info and 'author' in info:
if secure_lookup(info, 'author'):
author = info['author']
label4 = Gtk.Label()
label4.set_text(_("Author: "))
@ -200,17 +200,17 @@ class InstallKmpWindow(Gtk.Dialog):
grid.attach_next_to(label4, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = label4
label = Gtk.Label()
if 'url' in author and 'description' in author:
if secure_lookup(author, 'url') and secure_lookup(author, 'description'):
label.set_markup(
"<a href=\"" + author['url'] + "\" title=\"" +
author['url'] + "\">" + author['description'] + "</a>")
elif 'description' in author:
elif secure_lookup(author, 'description'):
label.set_text(author['description'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, label4, Gtk.PositionType.RIGHT, 1, 1)
if info and 'website' in info:
if secure_lookup(info, 'website'):
label5 = Gtk.Label()
# Website is optional and may be a mailto for the author
label5.set_text(_("Website: "))
@ -218,22 +218,22 @@ class InstallKmpWindow(Gtk.Dialog):
grid.attach_next_to(label5, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = label5
label = Gtk.Label()
if 'description' in info['website']:
if secure_lookup(info, 'website', 'description'):
label.set_markup(
"<a href=\"" + info['website']['description'] + "\">" +
info['website']['description'] + "</a>")
"<a href=\"" + secure_lookup(info, 'website', 'description') + "\">" +
secure_lookup(info, 'website', 'description') + "</a>")
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, label5, Gtk.PositionType.RIGHT, 1, 1)
if info and 'copyright' in info:
if secure_lookup(info, 'copyright'):
label6 = Gtk.Label()
label6.set_text(_("Copyright: "))
label6.set_halign(Gtk.Align.END)
grid.attach_next_to(label6, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
label = Gtk.Label()
if 'description' in info['copyright']:
label.set_text(info['copyright']['description'])
if secure_lookup(info, 'copyright', 'description'):
label.set_text(secure_lookup(info, 'copyright', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, label6, Gtk.PositionType.RIGHT, 1, 1)
@ -242,7 +242,7 @@ class InstallKmpWindow(Gtk.Dialog):
webview = WebKit2.WebView()
webview.connect("decide-policy", self.doc_policy)
if options and "readmeFile" in options:
if secure_lookup(options, 'readmeFile'):
self.readme = options['readmeFile']
else:
self.readme = "noreadme"

View file

@ -2,6 +2,7 @@
# Keyboard details window
import logging
import json
from os import path
import qrcode
@ -10,7 +11,7 @@ import tempfile
import gi
from gi.repository import Gtk
from keyman_config import KeymanComUrl, _
from keyman_config import KeymanComUrl, _, secure_lookup
from keyman_config.accelerators import init_accel
from keyman_config.kmpmetadata import parsemetadata
@ -61,8 +62,11 @@ class KeyboardDetailsView(Gtk.Dialog):
kbdata = None
jsonfile = path.join(packageDir, kmp['packageID'] + ".json")
if path.isfile(jsonfile):
with open(jsonfile, "r") as read_file:
kbdata = json.load(read_file)
try:
with open(jsonfile, "r") as read_file:
kbdata = json.load(read_file)
except Exception as e:
logging.warning('Exception %s reading %s %s', type(e), jsonfile, e.args)
grid = Gtk.Grid()
# grid.set_column_homogeneous(True)
@ -77,8 +81,8 @@ class KeyboardDetailsView(Gtk.Dialog):
grid.add(lbl_pkg_name)
prevlabel = lbl_pkg_name
label = Gtk.Label()
if info['name']['description']:
label.set_text(info['name']['description'])
if secure_lookup(info, 'name', 'description'):
label.set_text(secure_lookup(info, 'name', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_pkg_name, Gtk.PositionType.RIGHT, 1, 1)
@ -89,7 +93,7 @@ class KeyboardDetailsView(Gtk.Dialog):
grid.attach_next_to(lbl_pkg_id, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_pkg_id
label = Gtk.Label()
if kmp['packageID']:
if secure_lookup(kmp, 'packageID'):
label.set_text(kmp['packageID'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
@ -101,48 +105,47 @@ class KeyboardDetailsView(Gtk.Dialog):
grid.attach_next_to(lbl_pkg_vrs, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_pkg_vrs
label = Gtk.Label()
if info['version']['description']:
label.set_text(info['version']['description'])
if secure_lookup(info, 'version', 'description'):
label.set_text(secure_lookup(info, 'version', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_pkg_vrs, Gtk.PositionType.RIGHT, 1, 1)
if kbdata and kbdata.get('description'):
if secure_lookup(kbdata, 'description'):
lbl_pkg_desc = Gtk.Label()
lbl_pkg_desc.set_text(_("Package description: "))
lbl_pkg_desc.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_pkg_desc, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_pkg_desc
label = Gtk.Label()
if kbdata.get('description'):
label.set_text(kbdata.get('description'))
label.set_text(kbdata['description'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
label.set_line_wrap(80)
grid.attach_next_to(label, lbl_pkg_desc, Gtk.PositionType.RIGHT, 1, 1)
if "author" in info:
if secure_lookup(info, "author"):
lbl_pkg_auth = Gtk.Label()
lbl_pkg_auth.set_text(_("Package author: "))
lbl_pkg_auth.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_pkg_auth, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_pkg_auth
label = Gtk.Label()
if info['author']['description']:
label.set_text(info['author']['description'])
if secure_lookup(info, 'author', 'description'):
label.set_text(secure_lookup(info, 'author', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_pkg_auth, Gtk.PositionType.RIGHT, 1, 1)
if "copyright" in info:
if secure_lookup(info, "copyright"):
lbl_pkg_cpy = Gtk.Label()
lbl_pkg_cpy.set_text(_("Package copyright: "))
lbl_pkg_cpy.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_pkg_cpy, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_pkg_cpy
label = Gtk.Label()
if info['copyright']['description']:
label.set_text(info['copyright']['description'])
if secure_lookup(info, 'copyright', 'description'):
label.set_text(secure_lookup(info, 'copyright', 'description'))
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_pkg_cpy, Gtk.PositionType.RIGHT, 1, 1)
@ -165,8 +168,11 @@ class KeyboardDetailsView(Gtk.Dialog):
kbdata = None
jsonfile = path.join(packageDir, kbd['id'] + ".json")
if path.isfile(jsonfile):
with open(jsonfile, "r") as read_file:
kbdata = json.load(read_file)
try:
with open(jsonfile, "r") as read_file:
kbdata = json.load(read_file)
except Exception as e:
logging.warning('Exception %s reading %s %s', type(e), jsonfile, e.args)
# start with padding
lbl_pad = Gtk.Label()
@ -188,133 +194,132 @@ class KeyboardDetailsView(Gtk.Dialog):
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_file, Gtk.PositionType.RIGHT, 1, 1)
if kbdata:
if kbdata['id'] != kmp['packageID']:
lbl_kbd_name = Gtk.Label()
lbl_kbd_name.set_text(_("Keyboard name: "))
lbl_kbd_name.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_name, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_name
if kbdata and secure_lookup(kbdata, 'id') != secure_lookup(kmp, 'packageID'):
lbl_kbd_name = Gtk.Label()
lbl_kbd_name.set_text(_("Keyboard name: "))
lbl_kbd_name.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_name, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_name
label = Gtk.Label()
if secure_lookup(kbdata, 'name'):
label.set_text(kbdata['name'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_name, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_id = Gtk.Label()
lbl_kbd_id.set_text(_("Keyboard id: "))
lbl_kbd_id.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_id, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_id
label = Gtk.Label()
if secure_lookup(kbdata, 'id'):
label.set_text(kbdata['id'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_id, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_vrs = Gtk.Label()
lbl_kbd_vrs.set_text(_("Keyboard version: "))
lbl_kbd_vrs.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_vrs, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_vrs
label = Gtk.Label()
if secure_lookup(kbdata, 'version'):
label.set_text(kbdata['version'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_vrs, Gtk.PositionType.RIGHT, 1, 1)
if secure_lookup(info, "author"):
lbl_kbd_auth = Gtk.Label()
lbl_kbd_auth.set_text(_("Keyboard author: "))
lbl_kbd_auth.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_auth, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_auth
label = Gtk.Label()
if kbdata['name']:
label.set_text(kbdata['name'])
if secure_lookup(kbdata, 'authorName'):
label.set_text(kbdata['authorName'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_name, Gtk.PositionType.RIGHT, 1, 1)
grid.attach_next_to(label, lbl_kbd_auth, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_id = Gtk.Label()
lbl_kbd_id.set_text(_("Keyboard id: "))
lbl_kbd_id.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_id, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_id
label = Gtk.Label()
if kbdata['id']:
label.set_text(kbdata['id'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_id, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_lic = Gtk.Label()
lbl_kbd_lic.set_text(_("Keyboard license: "))
lbl_kbd_lic.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_lic, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_lic
label = Gtk.Label()
if secure_lookup(kbdata, 'license'):
label.set_text(kbdata['license'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_lic, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_vrs = Gtk.Label()
lbl_kbd_vrs.set_text(_("Keyboard version: "))
lbl_kbd_vrs.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_vrs, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_vrs
label = Gtk.Label()
if kbdata['version']:
label.set_text(kbdata['version'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_vrs, Gtk.PositionType.RIGHT, 1, 1)
lbl_kbd_desc = Gtk.Label()
lbl_kbd_desc.set_text(_("Keyboard description: "))
lbl_kbd_desc.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_desc, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_desc
label = Gtk.Label()
if secure_lookup(kbdata, 'description'):
label.set_text(kbdata['description'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
label.set_line_wrap(80)
grid.attach_next_to(label, lbl_kbd_desc, Gtk.PositionType.RIGHT, 1, 1)
if "author" in info:
lbl_kbd_auth = Gtk.Label()
lbl_kbd_auth.set_text(_("Keyboard author: "))
lbl_kbd_auth.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_auth, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_auth
label = Gtk.Label()
if kbdata['authorName']:
label.set_text(kbdata['authorName'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_auth, Gtk.PositionType.RIGHT, 1, 1)
# Padding and full width horizontal divider
lbl_pad = Gtk.Label()
lbl_pad.set_text("")
lbl_pad.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_pad, prevlabel, Gtk.PositionType.BOTTOM, 2, 1)
prevlabel = lbl_pad
lbl_kbd_lic = Gtk.Label()
lbl_kbd_lic.set_text(_("Keyboard license: "))
lbl_kbd_lic.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_lic, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_lic
label = Gtk.Label()
if kbdata['license']:
label.set_text(kbdata['license'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
grid.attach_next_to(label, lbl_kbd_lic, Gtk.PositionType.RIGHT, 1, 1)
divider_pkg = Gtk.HSeparator()
grid.attach_next_to(divider_pkg, prevlabel, Gtk.PositionType.BOTTOM, 2, 1)
lbl_kbd_desc = Gtk.Label()
lbl_kbd_desc.set_text(_("Keyboard description: "))
lbl_kbd_desc.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_kbd_desc, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
prevlabel = lbl_kbd_desc
label = Gtk.Label()
if kbdata['description']:
label.set_text(kbdata['description'])
label.set_halign(Gtk.Align.START)
label.set_selectable(True)
label.set_line_wrap(80)
grid.attach_next_to(label, lbl_kbd_desc, Gtk.PositionType.RIGHT, 1, 1)
# label7 = Gtk.Label()
# label7.set_text(_("On Screen Keyboard: "))
# label7.set_halign(Gtk.Align.END)
# grid.attach_next_to(label7, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label7
# # label = Gtk.Label()
# # label.set_text(secure_lookup(info, 'version', 'description'))
# # label.set_halign(Gtk.Align.START)
# # label.set_selectable(True)
# # grid.attach_next_to(label, label7, Gtk.PositionType.RIGHT, 1, 1)
# Padding and full width horizontal divider
lbl_pad = Gtk.Label()
lbl_pad.set_text("")
lbl_pad.set_halign(Gtk.Align.END)
grid.attach_next_to(lbl_pad, prevlabel, Gtk.PositionType.BOTTOM, 2, 1)
prevlabel = lbl_pad
# label8 = Gtk.Label()
# label8.set_text(_("Documentation: "))
# label8.set_halign(Gtk.Align.END)
# grid.attach_next_to(label8, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label8
# #TODO need to know which area keyboard is installed in to show this
# # label = Gtk.Label()
# # welcome_file = path.join("/usr/local/share/doc/keyman", kmp["id"], "welcome.htm")
# # if path.isfile(welcome_file):
# # label.set_text(_("Installed"))
# # else:
# # label.set_text(_("Not installed"))
# # label.set_halign(Gtk.Align.START)
# # label.set_selectable(True)
# # grid.attach_next_to(label, label8, Gtk.PositionType.RIGHT, 1, 1)
divider_pkg = Gtk.HSeparator()
grid.attach_next_to(divider_pkg, prevlabel, Gtk.PositionType.BOTTOM, 2, 1)
# label7 = Gtk.Label()
# label7.set_text(_("On Screen Keyboard: "))
# label7.set_halign(Gtk.Align.END)
# grid.attach_next_to(label7, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label7
# # label = Gtk.Label()
# # label.set_text(info['version']['description'])
# # label.set_halign(Gtk.Align.START)
# # label.set_selectable(True)
# # grid.attach_next_to(label, label7, Gtk.PositionType.RIGHT, 1, 1)
# label8 = Gtk.Label()
# label8.set_text(_("Documentation: "))
# label8.set_halign(Gtk.Align.END)
# grid.attach_next_to(label8, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label8
# #TODO need to know which area keyboard is installed in to show this
# # label = Gtk.Label()
# # welcome_file = path.join("/usr/local/share/doc/keyman", kmp["id"], "welcome.htm")
# # if path.isfile(welcome_file):
# # label.set_text(_("Installed"))
# # else:
# # label.set_text(_("Not installed"))
# # label.set_halign(Gtk.Align.START)
# # label.set_selectable(True)
# # grid.attach_next_to(label, label8, Gtk.PositionType.RIGHT, 1, 1)
# label9 = Gtk.Label()
# # stored in kmx
# label9.set_text(_("Message: "))
# label9.set_halign(Gtk.Align.END)
# grid.attach_next_to(label9, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label9
# label = Gtk.Label()
# label.set_line_wrap(True)
# label.set_text(
# "This keyboard is distributed under the MIT license (MIT) as described somewhere")
# #label.set_text(kmp["description"])
# label.set_halign(Gtk.Align.START)
# label.set_selectable(True)
# grid.attach_next_to(label, label9, Gtk.PositionType.RIGHT, 1, 1)
# label9 = Gtk.Label()
# # stored in kmx
# label9.set_text(_("Message: "))
# label9.set_halign(Gtk.Align.END)
# grid.attach_next_to(label9, prevlabel, Gtk.PositionType.BOTTOM, 1, 1)
# prevlabel = label9
# label = Gtk.Label()
# label.set_line_wrap(True)
# label.set_text(
# "This keyboard is distributed under the MIT license (MIT) as described somewhere")
# #label.set_text(kmp["description"])
# label.set_halign(Gtk.Align.START)
# label.set_selectable(True)
# grid.attach_next_to(label, label9, Gtk.PositionType.RIGHT, 1, 1)
# Add an entire row of padding
lbl_pad = Gtk.Label()

View file

@ -9,6 +9,8 @@ import magic
from enum import Enum
from json.decoder import JSONDecodeError
from keyman_config import secure_lookup
class KMFileTypes(Enum):
KM_ICON = 1
@ -32,18 +34,18 @@ def print_info(info):
print("---- Info ----")
if not info:
return
print("Name: ", info['name']['description'])
print("Copyright: ", info['copyright']['description'])
print("Name: ", secure_lookup(info, 'name', 'description'))
print("Copyright: ", secure_lookup(info, 'copyright', 'description'))
if 'version' in info:
print("Version: ", info['version']['description'])
print("Version: ", secure_lookup(info, 'version', 'description'))
if 'author' in info:
print("Author: ", info['author']['description'])
if 'url' in info['author']:
print("Author URL: ", info['author']['url'])
print("Author: ", secure_lookup(info, 'author', 'description'))
if secure_lookup(info, 'author', 'url'):
print("Author URL: ", secure_lookup(info, 'author', 'url'))
if 'website' in info:
print("Website description: ", info['website']['description'])
if 'url' in info['website']:
print("Website URL: ", info['website']['url'])
print("Website description: ", secure_lookup(info, 'website', 'description'))
if secure_lookup(info, 'website', 'url'):
print("Website URL: ", secure_lookup(info, 'website', 'url'))
except Exception as e:
print(type(e)) # the exception instance
print(e.args) # arguments stored in .args
@ -390,7 +392,7 @@ def parseinfdata(inffile, verbose=False):
keyboards = [{
'name': id,
'id': id,
'version': info['version']['description']
'version': secure_lookup(info, 'version', 'description')
}]
kblist = []
@ -535,8 +537,11 @@ def get_and_convert_infdata(tmpdirname):
info, system, options, keyboards, files = parseinfdata(kmpinf, False)
j = infmetadata_to_json(info, system, options, keyboards, files)
kmpjson = os.path.join(tmpdirname, "kmp.json")
with open(kmpjson, "w") as write_file:
print(j, file=write_file)
try:
with open(kmpjson, "w") as write_file:
print(j, file=write_file)
except Exception as e:
logging.warning('Exception %s writing metadata %s %s', type(e), kmpjson, e.args)
return info, system, options, keyboards, files
else:
return None, None, None, None, None

View file

@ -373,28 +373,31 @@ def output_ldml(ldmlfile, ldml):
def parse_kvk_file(kvkfile):
kvkData = KVKData()
with open(kvkfile, mode='rb') as file: # b is important -> binary
fileContent = file.read()
try:
with open(kvkfile, mode='rb') as file: # b is important -> binary
fileContent = file.read()
kvkstart = struct.unpack_from("<4s4cc", fileContent, 0)
kvkData.version = (kvkstart[1], kvkstart[2], kvkstart[3], kvkstart[4])
kvkData.flags = kvkstart[5]
kvkData.key102 = bytecheck(kvkData.flags[0], kvkk102key)
kvkData.DisplayUnderlying = bytecheck(kvkData.flags[0], kvkkDisplayUnderlying)
kvkData.UseUnderlying = bytecheck(kvkData.flags[0], kvkkUseUnderlying)
kvkData.AltGr = bytecheck(kvkData.flags[0], kvkkAltGr)
kvkstart = struct.unpack_from("<4s4cc", fileContent, 0)
kvkData.version = (kvkstart[1], kvkstart[2], kvkstart[3], kvkstart[4])
kvkData.flags = kvkstart[5]
kvkData.key102 = bytecheck(kvkData.flags[0], kvkk102key)
kvkData.DisplayUnderlying = bytecheck(kvkData.flags[0], kvkkDisplayUnderlying)
kvkData.UseUnderlying = bytecheck(kvkData.flags[0], kvkkUseUnderlying)
kvkData.AltGr = bytecheck(kvkData.flags[0], kvkkAltGr)
kvkData.AssociatedKeyboard, newoffset = get_nstring(file, fileContent, struct.calcsize("<4s4cc"))
kvkData.AnsiFont, newoffset = get_nfont(file, fileContent, newoffset)
kvkData.UnicodeFont, newoffset = get_nfont(file, fileContent, newoffset)
numkeys = struct.unpack_from("I", fileContent, newoffset)
kvkData.KeyCount = numkeys[0]
newoffset = newoffset + struct.calcsize("I")
kvkData.AssociatedKeyboard, newoffset = get_nstring(file, fileContent, struct.calcsize("<4s4cc"))
kvkData.AnsiFont, newoffset = get_nfont(file, fileContent, newoffset)
kvkData.UnicodeFont, newoffset = get_nfont(file, fileContent, newoffset)
numkeys = struct.unpack_from("I", fileContent, newoffset)
kvkData.KeyCount = numkeys[0]
newoffset = newoffset + struct.calcsize("I")
for num in range(numkeys[0]):
nkey, newoffset = get_nkey(file, fileContent, newoffset)
nkey.number = num
kvkData.Keys.append(nkey)
for num in range(numkeys[0]):
nkey, newoffset = get_nkey(file, fileContent, newoffset)
nkey.number = num
kvkData.Keys.append(nkey)
except Exception as e:
logging.warning('Exception %s parsing kvk file %s %s', type(e), kvkfile, e.args)
return kvkData

View file

@ -1,7 +1,9 @@
#!/usr/bin/python3
import logging
import os
import json
from keyman_config import secure_lookup
from keyman_config.kmpmetadata import parsemetadata, parseinfdata
from keyman_config.get_kmp import get_keyman_dir, InstallLocation
from keyman_config.deprecated_decorator import deprecated
@ -70,17 +72,20 @@ def get_installed_kmp_paths(check_paths):
has_kbjson = False
kbjson = os.path.join(keymanpath, o, o + ".json")
if os.path.isfile(kbjson):
with open(kbjson, "r") as read_file:
kbdata = json.load(read_file)
if kbdata:
if 'description' in kbdata:
description = kbdata['description']
version = kbdata['version']
name = kbdata['name']
has_kbjson = True
try:
with open(kbjson, "r") as read_file:
kbdata = json.load(read_file)
if kbdata:
if 'description' in kbdata:
description = kbdata['description']
version = kbdata['version']
name = kbdata['name']
has_kbjson = True
except Exception as e:
logging.warning('Exception %s loading %s %s', type(e), kbjson, e.args)
if info:
md_version = info['version']['description']
md_name = info['name']['description']
md_version = secure_lookup(info, 'version', 'description')
md_name = secure_lookup(info, 'name', 'description')
if keyboards:
keyboardID = keyboards[0]['id']
else:

View file

@ -4,7 +4,7 @@ import argparse
import logging
import sys
import os
from keyman_config import __version__, KeymanApiUrl
from keyman_config import __version__, KeymanApiUrl, secure_lookup
from keyman_config.uninstall_kmp import uninstall_kmp
import datetime
@ -57,11 +57,14 @@ def get_keyboard_list():
def write_kmpdirlist(kmpdirfile):
with open(kmpdirfile, 'wt') as kmpdirlist:
keyboards = get_keyboard_list()
if keyboards:
for kb in get_keyboard_list():
print(kb, file=kmpdirlist)
try:
with open(kmpdirfile, 'wt') as kmpdirlist:
keyboards = get_keyboard_list()
if keyboards:
for kb in get_keyboard_list():
print(kb, file=kmpdirlist)
except Exception as e:
logging.warning('Exception %s writing %s %s', type(e), kmpdirfile, e.args)
def list_keyboards():
@ -137,17 +140,18 @@ def main():
if not kbdata:
logging.error("km-package-install: error: Could not download keyboard data for %s", args.package)
sys.exit(3)
if installed_kmp_ver:
if kbdata['version'] == installed_kmp_ver:
kbdata_version = secure_lookup(kbdata, 'version')
if installed_kmp_ver and kbdata_version:
if kbdata_version == installed_kmp_ver:
logging.error(
"km-package-install: The %s version of the %s keyboard package is already installed.",
installed_kmp_ver, args.package)
sys.exit(1)
elif float(kbdata['version']) > float(installed_kmp_ver):
elif float(kbdata_version) > float(installed_kmp_ver):
logging.error(
"km-package-install: A newer version of %s keyboard package is available. " +
"Uninstalling old version %s then downloading and installing new version %s.",
args.package, installed_kmp_ver, kbdata['version'])
args.package, installed_kmp_ver, kbdata_version)
uninstall_kmp(args.package, args.shared)
kmpfile = get_kmp(args.package)