From 5a02f50cc69ee049b0f52c0af9a0b24ae01cffb6 Mon Sep 17 00:00:00 2001 From: El Mau Date: Sun, 17 Dec 2023 23:57:30 -0600 Subject: [PATCH] Add styles --- .gitignore | 1 + CHANGELOG.md | 4 + VERSION | 2 +- docs/en/docs/img/tools_msg_01.png | Bin 0 -> 6554 bytes docs/en/docs/img/tools_msg_02.png | Bin 0 -> 7343 bytes docs/en/docs/img/tools_msg_03.png | Bin 0 -> 7822 bytes docs/en/docs/img/tools_msg_04.png | Bin 0 -> 21494 bytes docs/en/docs/img/tools_msg_05.png | Bin 0 -> 10711 bytes docs/en/docs/img/tools_msg_06.png | Bin 0 -> 10563 bytes docs/en/docs/tools/datetime.md | 177 ++++++++++++++++++++++++++++ docs/en/docs/tools/index.md | 123 ++++++++++++++++++++ docs/en/docs/tools/messages.md | 75 ++++++++++++ docs/en/mkdocs.yml | 8 +- docs/es/mkdocs.yml | 4 +- source/easymacro/constants.py | 10 ++ source/easymacro/easycalc.py | 72 ++---------- source/easymacro/easymain.py | 17 ++- source/easymacro/easystyles.py | 143 +++++++++++++++++++++++ source/easymacro/easywriter.py | 136 +++++++++++++++++++++- source/easymacro/utils.py | 185 ++++++++++++++++++++++++++++++ source/tests/test_config.py | 2 +- 21 files changed, 882 insertions(+), 77 deletions(-) create mode 100644 docs/en/docs/img/tools_msg_01.png create mode 100644 docs/en/docs/img/tools_msg_02.png create mode 100644 docs/en/docs/img/tools_msg_03.png create mode 100644 docs/en/docs/img/tools_msg_04.png create mode 100644 docs/en/docs/img/tools_msg_05.png create mode 100644 docs/en/docs/img/tools_msg_06.png create mode 100644 docs/en/docs/tools/datetime.md create mode 100644 docs/en/docs/tools/index.md create mode 100644 docs/en/docs/tools/messages.md create mode 100644 source/easymacro/constants.py create mode 100644 source/easymacro/easystyles.py create mode 100644 source/easymacro/utils.py diff --git a/.gitignore b/.gitignore index 7bb58e6..bcf84e4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ *.lock bk/ site/ +update.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a9c7a..0b24b9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v 0.6.0 [17-Dec-2023] +--------------------- + - Add control styles. + v 0.5.0 [07-Dec-2023] --------------------- - Add acctions to controls. diff --git a/VERSION b/VERSION index 8f0916f..a918a2a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/docs/en/docs/img/tools_msg_01.png b/docs/en/docs/img/tools_msg_01.png new file mode 100644 index 0000000000000000000000000000000000000000..764b7547b55a9c67c2a95b461b7246453fffaa53 GIT binary patch literal 6554 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tools_msg_02.png b/docs/en/docs/img/tools_msg_02.png new file mode 100644 index 0000000000000000000000000000000000000000..699c50138174048e5f75d0f74da7d013a4beafe3 GIT binary patch literal 7343 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 NnyR`gl}a{Y{{xqS$o2pL literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tools_msg_03.png b/docs/en/docs/img/tools_msg_03.png new file mode 100644 index 0000000000000000000000000000000000000000..0addf55cfc2d72eaa4fd29c5581a4cde7731aba3 GIT binary patch literal 7822 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 Jt3(Y0{|nyIP;LMK literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tools_msg_04.png b/docs/en/docs/img/tools_msg_04.png new file mode 100644 index 0000000000000000000000000000000000000000..5092179cacff4c86951f23c8e1f7895586952b85 GIT binary patch literal 21494 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
  • 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 + +### **today** + +Obtener la fecha actual. + +```py + d = app.dates + app.msgbox(d.today) +``` + +
    + +### **now** + +Obtener la fecha y hora actuales. + +```py + d = app.dates + app.msgbox(d.now) +``` + +
    + +### **time** + +Obtener la hora actual. + +```py + d = app.dates + app.msgbox(d.now.time()) +``` + +
    + +### **epoch** + +Obtener el [tiempo Unix][1] + +```py + d = app.dates + app.msgbox(d.epoch) +``` + +
    + +### **date** + +Devolver una fecha + +```py + d = app.dates + + date = d.date(1974, 1, 15) + app.msgbox(date) +``` + +
    + +### **time** + +Devolver una hora + +```py + d = app.dates + + time = d.time(10, 20, 15) + app.msgbox(time) +``` + +
    + +### **datetime** + +Devolver fecha y hora + +```py + d = app.dates + + dt = d.datetime(1974, 1, 15, 10, 11, 12) + app.msgbox(dt) +``` + +
    + +### **str_to_date** + +Convertir una cadena en fecha. Mira este [excelente recurso][2] + +```py + d = app.dates + + cadena = '1974-01-15' + plantilla = '%Y-%m-%d' + fecha = d.str_to_date(cadena, plantilla) + app.msgbox(fecha) + app.msgbox(type(fecha)) +``` + +Para obtener un valor válido para establecer en una celda de Calc. + +```py + d = app.dates + + cadena = '1974-01-15' + plantilla = '%Y-%m-%d' + fecha = d.str_to_date(cadena, plantilla, True) + app.msgbox(fecha) + app.msgbox(type(fecha)) +``` + +
    + +### **calc_to_date** + +Convierte el valor de una celda en una fecha Python, por ejemplo, la fecha inicial configurada en Calc. + +```py + d = app.dates + + valor_en_celda = 0 + fecha = d.calc_to_date(valor_en_celda) + app.msgbox(fecha) + app.msgbox(type(fecha)) +``` + +
    + +### **sleep** + +Pausar la ejecución por X segundos. + +!!! tip inline end "Atención" + + La pausa es bloqueante. + +```py + d = app.dates + + app.sleep(3) + app.msgbox('Fin') +``` + +
    + +### **start** y **end** + +Medir tiempo en segundos. + +```py + d = app.dates + + d.start() + app.sleep(5) + seconds = d.end() + app.msgbox(seconds) +``` + +Regresar timedelta en vez de segundos. + +```py + d = app.dates + + d.start() + app.sleep(5) + td = d.end(False) + app.msgbox(td) +``` + + +[1]: https://es.wikipedia.org/wiki/Tiempo_Unix +[2]: https://strftime.org diff --git a/docs/en/docs/tools/index.md b/docs/en/docs/tools/index.md new file mode 100644 index 0000000..6ed32ea --- /dev/null +++ b/docs/en/docs/tools/index.md @@ -0,0 +1,123 @@ +--- +title: Information +--- + +Remember, import first the library. + +```py +import easymacro as app +``` + +
    + +## About PC + +
    + +### **OS** + +Get Operate System. +```py +app.msgbox(app.OS) +``` + +
    + +### **DESKTOP** + +Get desktop type, only GNU/Linux. +```py +app.msgbox(app.DESKTOP) +``` + +
    + +### **PC** + +Get PC name. +```py +app.msgbox(app.PC) +``` + +
    + +### **USER** + +Get user name. +```py +app.msgbox(app.USER) +``` + +
    + +### **IS_WIN** + +If OS is Windows. +```py +app.msgbox(app.IS_WIN) +``` + +
    + +### **IS_MAC** + +IF OS is MAC +```py +app.msgbox(app.IS_MAC) +``` + +
    + +## About LibreOffice + +### **NAME** + +Application name. +```py +app.msgbox(app.NAME) +``` + +
    + +### **VERSION** + +Version. +```py +app.msgbox(app.VERSION) +``` + +
    + +### **LANG** + +Language +```py +app.msgbox(app.LANG) +``` + +
    + +### **LANGUAGE** + +Language with variant. +```py +app.msgbox(app.LANGUAGE) +``` + +
    + +### **IS_APPIMAGE** + +If LibreOffice use by AppImage. +```py +app.msgbox(app.IS_APPIMAGE) +``` + +
    + +### **IS_FLATPAK** + +If LibreOffice is use by FlatPak. +```py +app.msgbox(app.IS_FLATPAK) +``` diff --git a/docs/en/docs/tools/messages.md b/docs/en/docs/tools/messages.md new file mode 100644 index 0000000..6fd464e --- /dev/null +++ b/docs/en/docs/tools/messages.md @@ -0,0 +1,75 @@ +## Message Box + +### **msgbox** + +Show standard message. +```py + message = 'Fucking World' + title = 'My Macro' + app.msgbox(message, title) +``` + +![msgbox](../img/tools_msg_01.png) + +
    + +### **warning** + +Show message with warning icon. +```py + message = 'Caution, this action is dangerous' + title = 'My Macro' + app.warning(message, title) +``` + +![warning](../img/tools_msg_02.png) + +
    + +### **errorbox** + +Show message with error icon. +```py + message = 'ERROR: contact support' + title = 'My Macro' + app.errorbox(message, title) +``` + +![error](../img/tools_msg_03.png) + +
    + +### **question** + +Ask a question by showing the interrogation icon and displaying the command buttons `Yes` and `No`. The answer is always True if user select `yes` and False otherwise. +```py + message = 'Python is easy?' + title = 'My Macro' + result = app.question(message, title) + app.msgbox(result) +``` + +![question](../img/tools_msg_04.png) + +
    + +### **inputbox** + +Shows a message to user, allowing to capture an answer. +```py + message = 'Capture your name' + name = app.inputbox(message) + app.msgbox(name) +``` + +![inputbox](../img/tools_msg_05.png) + +To hide on screen what the user typing, util for request passwords. +```py + message = 'Type your password' + echochar = '*' + password = app.inputbox(message, echochar=echochar) + app.msgbox(password) +``` + +![inputbox](../img/tools_msg_06.png) \ No newline at end of file diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 00d4ccf..edbc449 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -5,6 +5,10 @@ nav: - Home: index.md - Install: install.md - Debug: debug.md + - Tools: + - tools/index.md + - Messages: tools/messages.md + - Dates and time: tools/datetime.md theme: name: material locale: en @@ -33,8 +37,8 @@ markdown_extensions: extra: alternate: - name: English - link: / + link: /easymacro lang: en - name: Español - link: /langs/es + link: /easymacro/langs/es lang: es diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml index 2392800..dfcf9e4 100644 --- a/docs/es/mkdocs.yml +++ b/docs/es/mkdocs.yml @@ -69,8 +69,8 @@ markdown_extensions: extra: alternate: - name: English - link: / + link: /easymacro lang: en - name: Español - link: /langs/es + link: /easymacro/langs/es lang: es diff --git a/source/easymacro/constants.py b/source/easymacro/constants.py new file mode 100644 index 0000000..bef7b98 --- /dev/null +++ b/source/easymacro/constants.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# ~ Is de sum of: +# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html + +from com.sun.star.sheet import CellFlags + +ONLY_DATA = 31 + +ALL = 1023 diff --git a/source/easymacro/easycalc.py b/source/easymacro/easycalc.py index 4dab252..5153660 100644 --- a/source/easymacro/easycalc.py +++ b/source/easymacro/easycalc.py @@ -16,75 +16,13 @@ from .easyevents import EventsRangeSelectionListener, LOEvents from .easyshape import LOShapes, LOShape from .easydrawpage import LODrawPage from .easyforms import LOForms +from .easystyles import LOStyleFamilies SECONDS_DAY = 60 * 60 * 24 ONLY_VALUES = CellFlags.VALUE + CellFlags.DATETIME + CellFlags.STRING -class LOCellStyle(): - - def __init__(self, obj): - self._obj = obj - - def __str__(self): - return f'CellStyle: {self.name}' - - @property - def obj(self): - return self._obj - - @property - def name(self): - return self.obj.Name - - @property - def properties(self): - properties = self.obj.PropertySetInfo.Properties - data = {p.Name: getattr(self.obj, p.Name) for p in properties} - return data - @properties.setter - def properties(self, values): - set_properties(self.obj, values) - - -class LOCellStyles(): - - def __init__(self, obj, doc): - self._obj = obj - self._doc = doc - - def __len__(self): - return len(self.obj) - - def __getitem__(self, index): - return LOCellStyle(self.obj[index]) - - def __setitem__(self, key, value): - self.obj[key] = value - - def __delitem__(self, key): - if not isinstance(key, str): - key = key.Name - del self.obj[key] - - def __contains__(self, item): - return item in self.obj - - @property - def obj(self): - return self._obj - - @property - def names(self): - return self.obj.ElementNames - - def new(self, name: str): - obj = self._doc.create_instance('com.sun.star.style.CellStyle') - self.obj[name] = obj - return LOCellStyle(obj) - - # ~ IsFiltered, # ~ IsManualPageBreak, # ~ IsStartOfNewPage @@ -939,6 +877,11 @@ class LOCalc(LODocument): """Get class events""" return LOEvents(self.obj.Events) + @property + def styles(self): + ci = self.obj.createInstance + return LOStyleFamilies(self.obj.StyleFamilies, ci) + def ranges(self): """Create ranges container""" obj = self._create_instance('com.sun.star.sheet.SheetCellRanges') @@ -1111,5 +1054,4 @@ class LOCalc(LODocument): return self.cell_styles @property def cell_styles(self): - obj = self.obj.StyleFamilies['CellStyles'] - return LOCellStyles(obj, self) + return self.styles['CellStyles'] diff --git a/source/easymacro/easymain.py b/source/easymacro/easymain.py index 6765153..9b89b75 100644 --- a/source/easymacro/easymain.py +++ b/source/easymacro/easymain.py @@ -24,6 +24,7 @@ from com.sun.star.beans import PropertyValue, NamedValue, StringPair from com.sun.star.datatransfer import XTransferable, DataFlavor from com.sun.star.ui.dialogs import TemplateDescription +from .constants import ALL from .messages import MESSAGES @@ -31,6 +32,8 @@ __all__ = [ 'ALL', 'DESKTOP', 'INFO_DEBUG', + 'IS_APPIMAGE', + 'IS_FLATPAK', 'IS_MAC', 'IS_WIN', 'LANG', @@ -63,13 +66,12 @@ PC = platform.node() USER = getpass.getuser() IS_WIN = OS == 'Windows' IS_MAC = OS == 'Darwin' - - -ALL = 1023 +IS_FLATPAK = bool(os.getenv("FLATPAK_ID", "")) +IS_APPIMAGE = bool(os.getenv("APPIMAGE", "")) LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' -LOG_DATE = '%d/%m/%Y %H:%M:%S' +LOG_DATE = '%Y/%m/%d %H:%M:%S' if IS_WIN: logging.addLevelName(logging.ERROR, 'ERROR') logging.addLevelName(logging.DEBUG, 'DEBUG') @@ -149,7 +151,6 @@ day = get_app_config(node, 'DD') DATE_OFFSET = datetime.date(year, month, day).toordinal() _info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path) -# ~ doc INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}" @@ -221,6 +222,12 @@ def set_properties(model, properties): return +def get_properties(obj): + properties = obj.PropertySetInfo.Properties + values = {p.Name: getattr(obj, p.Name) for p in properties} + return values + + # ~ https://github.com/django/django/blob/main/django/utils/functional.py#L61 class classproperty: diff --git a/source/easymacro/easystyles.py b/source/easymacro/easystyles.py new file mode 100644 index 0000000..5ea2621 --- /dev/null +++ b/source/easymacro/easystyles.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python + + +from .easymain import log, BaseObject, set_properties, get_properties + + +STYLE_FAMILIES = 'StyleFamilies' + + +class LOBaseStyles(BaseObject): + + def __init__(self, obj, create_instance=None): + super().__init__(obj) + self._create_intance = create_instance + + def __len__(self): + return self.obj.Count + + def __contains__(self, item): + return self.obj.hasByName(item) + + def __getitem__(self, index): + if index in self: + style = self.obj.getByName(index) + else: + raise IndexError + + if self.NAME == STYLE_FAMILIES: + s = LOStyles(style, index, self._create_intance) + else: + s = LOStyle(style) + return s + + def __iter__(self): + self._index = 0 + return self + + def __next__(self): + if self._index < self.obj.Count: + style = self[self.names[self._index]] + else: + raise StopIteration + + self._index += 1 + return style + + @property + def names(self): + return self.obj.ElementNames + + +class LOStyle(): + NAME = 'Style' + + def __init__(self, obj): + self._obj = obj + + def __str__(self): + return f'Style: {self.name}' + + def __contains__(self, item): + return hasattr(self.obj, item) + + def __setattr__(self, name, value): + if name != '_obj': + self.obj.setPropertyValue(name, value) + else: + super().__setattr__(name, value) + + def __getattr__(self, name): + return self.obj.getPropertyValue(name) + + @property + def obj(self): + return self._obj + + @property + def name(self): + return self.obj.Name + + @property + def is_in_use(self): + return self.obj.isInUse() + + @property + def is_user_defined(self): + return self.obj.isUserDefined() + + @property + def properties(self): + return get_properties(self.obj) + @properties.setter + def properties(self, values): + set_properties(self.obj, values) + + +class LOStyles(LOBaseStyles): + NAME = 'Styles' + + def __init__(self, obj, type_style, create_instance): + super().__init__(obj) + self._type_style = type_style + self._create_instance = create_instance + + def __str__(self): + return f'Styles: {self._type_style}' + + def __setitem__(self, key, value): + if key in self: + style = self.obj.getByName(key) + else: + name = f'com.sun.star.style.{self._type_style[:-1]}' + style = self._create_instance(name) + self.obj.insertByName(key, style) + set_properties(style, value) + + def __delitem__(self, key): + self.obj.removeByName(key) + + +class LOStyleFamilies(LOBaseStyles): + NAME = STYLE_FAMILIES + + def __init__(self, obj, create_instance): + super().__init__(obj, create_instance) + + def __str__(self): + return f'Style Families: {self.names}' + + def _validate_name(self, name): + if not name.endswith('Styles'): + name = f'{name}Styles' + return name + + def __contains__(self, item): + return self.obj.hasByName(self._validate_name(item)) + + def __getitem__(self, index): + if isinstance(index, int): + index = self.names[index] + else: + index = self._validate_name(index) + return super().__getitem__(index) diff --git a/source/easymacro/easywriter.py b/source/easymacro/easywriter.py index 1fce072..22e20df 100644 --- a/source/easymacro/easywriter.py +++ b/source/easymacro/easywriter.py @@ -1,11 +1,123 @@ #!/usr/bin/env python3 +from .easymain import log, BaseObject from .easydoc import LODocument +class LOWriterTextPortion(BaseObject): + + def __init__(self, obj): + super().__init__(obj) + + def __str__(self): + return 'Writer: TextPortion' + + @property + def string(self): + return self.obj.String + + +class LOWriterParagraph(BaseObject): + TEXT_PORTION = 'SwXTextPortion' + + def __init__(self, obj): + super().__init__(obj) + + def __str__(self): + return 'Writer: Paragraph' + + def __iter__(self): + self._iter = iter(self.obj) + return self + + def __next__(self): + obj = next(self._iter) + type_obj = obj.ImplementationName + if type_obj == self.TEXT_PORTION: + obj = LOWriterTextPortion(obj) + return obj + + @property + def string(self): + return self.obj.String + + @property + def cursor(self): + return self.obj.Text.createTextCursorByRange(self.obj) + + +class LOWriterTextRange(BaseObject): + PARAGRAPH = 'SwXParagraph' + + def __init__(self, obj): + super().__init__(obj) + + def __str__(self): + return 'Writer: TextRange' + + def __getitem__(self, index): + for i, v in enumerate(self): + if index == i: + return v + if index > i: + raise IndexError + + def __iter__(self): + self._enum = self.obj.createEnumeration() + return self + + def __next__(self): + if self._enum.hasMoreElements(): + obj = self._enum.nextElement() + type_obj = obj.ImplementationName + if type_obj == self.PARAGRAPH: + obj = LOWriterParagraph(obj) + else: + raise StopIteration + return obj + + @property + def string(self): + return self.obj.String + + @property + def cursor(self): + return self.obj.Text.createTextCursorByRange(self.obj) + + +class LOWriterTextRanges(BaseObject): + + def __init__(self, obj): + super().__init__(obj) + # ~ self._doc = doc + # ~ self._paragraphs = [LOWriterTextRange(p, doc) for p in obj] + + def __str__(self): + return 'Writer: TextRanges' + + def __len__(self): + return self.obj.Count + + def __getitem__(self, index): + return LOWriterTextRange(self.obj[index]) + + def __iter__(self): + self._index = 0 + return self + + def __next__(self): + try: + obj = LOWriterTextRange(self.obj[self._index]) + except IndexError: + raise StopIteration + + self._index += 1 + return obj + + class LOWriter(LODocument): - _type = 'writer' TEXT_RANGES = 'SwXTextRanges' + _type = 'writer' def __init__(self, obj): super().__init__(obj) @@ -17,3 +129,25 @@ class LOWriter(LODocument): @zoom.setter def zoom(self, value): self._view_settings.ZoomValue = value + + @property + def selection(self): + """Get current seleccion""" + sel = None + selection = self.obj.CurrentSelection + type_obj = selection.ImplementationName + + if type_obj == self.TEXT_RANGES: + sel = LOWriterTextRanges(selection) + if len(sel) == 1: + sel = sel[0] + else: + log.debug(type_obj) + log.debug(selection) + sel = selection + + return sel + + @property + def string(self): + return self._obj.Text.String diff --git a/source/easymacro/utils.py b/source/easymacro/utils.py new file mode 100644 index 0000000..e75677a --- /dev/null +++ b/source/easymacro/utils.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python + +# ~ https://github.com/pyca/cryptography/blob/main/src/cryptography/fernet.py#L27 + +import base64 +import binascii +import os +import time +import typing + + +_MAX_CLOCK_SKEW = 60 + + +class InvalidSignature(Exception): + pass + + +class InvalidToken(Exception): + pass + + +class Fernet: + def __init__( + self, + key: bytes | str, + backend: typing.Any = None, + ) -> None: + try: + key = base64.urlsafe_b64decode(key) + except binascii.Error as exc: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) from exc + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + + self._signing_key = key[:16] + self._encryption_key = key[16:] + + + @classmethod + def generate_key(cls) -> bytes: + return base64.urlsafe_b64encode(os.urandom(32)) + + + def encrypt(self, data: bytes) -> bytes: + return self.encrypt_at_time(data, int(time.time())) + + + def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + + def _encrypt_from_parts( + self, data: bytes, current_time: int, iv: bytes + ) -> bytes: + utils._check_bytes("data", data) + + + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher( + algorithms.AES(self._encryption_key), + modes.CBC(iv), + ).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + + basic_parts = ( + b"\x80" + + current_time.to_bytes(length=8, byteorder="big") + + iv + + ciphertext + ) + + + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + + def decrypt(self, token: bytes | str, ttl: int | None = None) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(token) + if ttl is None: + time_info = None + else: + time_info = (ttl, int(time.time())) + return self._decrypt_data(data, timestamp, time_info) + + + def decrypt_at_time( + self, token: bytes | str, ttl: int, current_time: int + ) -> bytes: + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, (ttl, current_time)) + + + def extract_timestamp(self, token: bytes | str) -> int: + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + + @staticmethod + def _get_unverified_token_data(token: bytes | str) -> tuple[int, bytes]: + if not isinstance(token, (str, bytes)): + raise TypeError("token must be bytes or str") + + + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + + if not data or data[0] != 0x80: + raise InvalidToken + + + if len(data) < 9: + raise InvalidToken + + + timestamp = int.from_bytes(data[1:9], byteorder="big") + return timestamp, data + + + def _verify_signature(self, data: bytes) -> None: + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(data[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + + def _decrypt_data( + self, + data: bytes, + timestamp: int, + time_info: tuple[int, int] | None, + ) -> bytes: + if time_info is not None: + ttl, current_time = time_info + if timestamp + ttl < current_time: + raise InvalidToken + + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + + self._verify_signature(data) + + + iv = data[9:25] + ciphertext = data[25:-32] + decryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv) + ).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() + + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded diff --git a/source/tests/test_config.py b/source/tests/test_config.py index 1cc6e69..fa9579d 100644 --- a/source/tests/test_config.py +++ b/source/tests/test_config.py @@ -9,6 +9,6 @@ USER = 'elmau' IS_WIN = False IS_MAC = False -LIBO_VERSION = '7.4' +LIBO_VERSION = '7.6' LANGUAGE = 'en-US' LANG = 'en'