# Lightweight Extensible Message Format
LXMF is a simple and flexible messaging format and delivery protocol that allows a wide variety of implementations, while using as little bandwidth as possible. It is built on top of [Reticulum](https://reticulum.network) and offers zero-conf message routing, end-to-end encryption and Forward Secrecy, and can be transported over any kind of medium that Reticulum supports.
LXMF is efficient enough that it can deliver messages over extremely low-bandwidth systems such as packet radio or LoRa. Encrypted LXMF messages can also be encoded as QR-codes or text-based URIs, allowing completely analog *paper message* transport.
User-facing clients built on LXMF include:
- [Sideband](https://unsigned.io/sideband)
- [MeshChat](https://github.com/liamcottle/reticulum-meshchat)
- [Nomad Network](https://unsigned.io/nomadnet)
Community-provided tools and utilities for LXMF include:
- [LXMF-Bot](https://github.com/randogoth/lxmf-bot)
- [LXMF Messageboard](https://github.com/chengtripp/lxmf_messageboard)
- [LXMEvent](https://github.com/faragher/LXMEvent)
- [RangeMap](https://github.com/faragher/RangeMap)
- [LXMF Tools](https://github.com/SebastianObi/LXMF-Tools)
## Structure
LXMF messages are stored in a simple and efficient format, that's easy to parse and write.
### The format follows this general structure:
- Destination
- Source
- Ed25519 Signature
- Payload
- Timestamp
- Content
- Title
- Fields
### And these rules:
1. A LXMF message is identified by its __message-id__, which is a SHA-256 hash of the __Destination__, __Source__ and __Payload__. The message-id is never included directly in the message, since it can always be inferred from the message itself.
In some cases the actual message-id cannot be inferred, for example when a Propagation Node is storing an encrypted message for an offline user. In these cases a _transient-id_ is used to identify the message while in storage or transit.
2. __Destination__, __Source__, __Signature__ and __Payload__ parts are mandatory, as is the __Timestamp__ part of the payload.
- The __Destination__ and __Source__ fields are 16-byte Reticulum destination hashes
- The __Signature__ field is a 64-byte Ed25519 signature of the __Destination__, __Source__, __Payload__ and __message-id__
- The __Payload__ part is a [msgpacked](https://msgpack.org) list containing four items:
1. The __Timestamp__ is a double-precision floating point number representing the number of seconds since the UNIX epoch.
2. The __Content__ is the optional content or body of the message
3. The __Title__ is an optional title for the message
4. The __Fields__ is an optional dictionary
3. The __Content__, __Title__ and __Fields__ parts must be included in the message structure, but can be left empty.
4. The __Fields__ part can be left empty, or contain a dictionary of any structure or depth.
## Usage Examples
LXMF offers flexibility to implement many different messaging schemes, ranging from human communication to machine control and sensor monitoring. Here are a few examples:
- A messaging system for passing short, simple messages between human users, akin to SMS can be implemented using only the __Content__ field, and leaving all other optional fields empty.
- For sending full-size mail, an email-like system can be implemented using the __Title__ and __Content__ fields to store "subject" and "body" parts of the message, and optionally the __Fields__ part can be used to store attachments or other metadata.
- Machine-control messages or sensor readings can be implemented using command structures embedded in the __Fields__ dictionary.
- Distributed discussion or news-groups, akin to USENET or similar systems, can be implemented using the relevant fields and LXMF Propagation Nodes. Broadcast bulletins can be implemented in a similar fashion.
## Propagation Nodes
LXM Propagation Nodes offer a way to store and forward messages to users or endpoints that are not directly reachable at the time of message emission. Propagation Nodes can also provide infrastructure for distributed bulletin, news or discussion boards.
When Propagation Nodes exist on a Reticulum network, they will by default peer with each other and synchronise messages, automatically creating an encrypted, distributed message store. Users and other endpoints can retrieve messages destined for them from any available Propagation Nodes on the network.
## The LXM Router
The LXM Router handles transporting messages over a Reticulum network, managing delivery receipts, outbound and inbound queues, and is the point of API interaction for client programs. The LXM Router also implements functionality for acting as an LXMF Propagation Node.
Programatically, using the LXM Router to send a message is as simple as:
```python
import LXMF
lxm_router = LXMF.LXMRouter()
message = LXMF.LXMessage(destination, source, "This is a short, simple message.")
lxm_router.handle_outbound(message)
```
The LXM Router then handles the heavy lifting, such as message packing, encryption, delivery confirmation, path lookup, routing, retries and failure notifications.
## Transport Encryption
LXMF uses encryption provided by [Reticulum](https://reticulum.network), and thus uses end-to-end encryption by default. The delivery method of a message will influence which transport encryption scheme is used.
- If a message is delivered over a Reticulum link (which is the default method), the message will be encrypted with ephemeral AES-128 keys derived with ECDH on Curve25519. This mode offers forward secrecy.
- A message can be delivered opportunistically, embedded in a single Reticulum packet. In this cases the message will be opportunistically routed through the network, and will be encrypted with per-packet AES-128 keys derived with ECDH on Curve25519.
- If a message is delivered to the Reticulum GROUP destination type, the message will be encrypted using the symmetric AES-128 key of the GROUP destination.
## Wire Format & Overhead
Assuming the default Reticulum configuration, the binary wire-format is as follows:
- 16 bytes destination hash
- 16 bytes source hash
- 64 bytes Ed25519 signature
- Remaining bytes of [msgpack](https://msgpack.org) payload data, in accordance with the structure defined above
The complete message overhead for LXMF is only 111 bytes, which in return gives you timestamped, digitally signed, infinitely extensible, end-to-end encrypted, zero-conf routed, minimal-infrastructure messaging that's easy to use and build applications with.
## Code Examples
Before writing your own programs using LXMF, you need to have a basic understanding of how the [Reticulum](https://reticulum.network) protocol and API works. Please see the [Reticulum Manual](https://reticulum.network/manual/). For a few simple examples of how to send and receive messages with LXMF, please see the [receiver example](./docs/example_receiver.py) and the [sender example](./docs/example_sender.py) included in this repository.
## Example Paper Message
You can try out the paper messaging functionality by using the following QR code. It is a paper message sent to the LXMF address `6b3362bd2c1dbf87b66a85f79a8d8c75`. To be able to decrypt and read the message, you will need to import the following Reticulum Identity to an LXMF messaging app:
`3BPTDTQCRZPKJT3TXAJCMQFMOYWIM3OCLKPWMG4HCF2T4CH3YZHVNHNRDU6QAZWV2KBHMWBNT2C62TQEVC5GLFM4MN25VLZFSK3ADRQ=`
The [Sideband](https://unsigned.io/sideband) application allows you to do this easily. After you have imported the identity into an app of your choice, you can scan the following QR code and open it in the app, where it will be decrypted and added as a message.
<p align="center"><img width="50%" src="./docs/paper_msg_test.png"/></p>
You can also find the entire message in <a href="lxm://azNivSwdv4e2aoX3mo2MdTAozuI7BlzrLlHULmnVgpz3dNT9CMPVwgywzCJP8FVogj5j_kU7j7ywuvBNcr45kRTrd19c3iHenmnSDe4VEd6FuGsAiT0Khzl7T81YZHPTDhRNp0FdhDE9AJ7uphw7zKMyqhHHxOxqrYeBeKF66gpPxDceqjsOApvsSwggjcuHBx9OxOBy05XmnJxA1unCKgvNfOFYc1T47luxoY3c0dLOJnJPwZuFRytx2TXlQNZzOJ28yTEygIfkDqEO9mZi5lgev7XZJ0DvgioQxMIyoCm7lBUzfq66zW3SQj6vHHph7bhr36dLOCFgk4fZA6yia2MlTT9KV66Tn2l8mPNDlvuSAJhwDA_xx2PN9zKadCjo9sItkAp8r-Ss1CzoUWZUAyT1oDw7ly6RrzGBG-e3eM3CL6u1juIeFiHby7_3cON-6VTUuk4xR5nwKlFTu5vsYMVXe5H3VahiDSS4Q1aqX7I">this link</a>:
`lxm://azNivSwdv4e2aoX3mo2MdTAozuI7BlzrLlHULmnVgpz3dNT9CMPVwgywzCJP8FVogj5j_kU7j7ywuvBNcr45kRTrd19c3iHenmnSDe4VEd6FuGsAiT0Khzl7T81YZHPTDhRNp0FdhDE9AJ7uphw7zKMyqhHHxOxqrYeBeKF66gpPxDceqjsOApvsSwggjcuHBx9OxOBy05XmnJxA1unCKgvNfOFYc1T47luxoY3c0dLOJnJPwZuFRytx2TXlQNZzOJ28yTEygIfkDqEO9mZi5lgev7XZJ0DvgioQxMIyoCm7lBUzfq66zW3SQj6vHHph7bhr36dLOCFgk4fZA6yia2MlTT9KV66Tn2l8mPNDlvuSAJhwDA_xx2PN9zKadCjo9sItkAp8r-Ss1CzoUWZUAyT1oDw7ly6RrzGBG-e3eM3CL6u1juIeFiHby7_3cON-6VTUuk4xR5nwKlFTu5vsYMVXe5H3VahiDSS4Q1aqX7I`
On operating systems that allow for registering custom URI-handlers, you can click the link, and it will be decoded directly in your LXMF client. This works with Sideband on Android.
## Installation
If you want to try out LXMF, you can install it with pip:
```bash
pip install lxmf
```
If you are using an operating system that blocks normal user package installation via `pip`,
you can return `pip` to normal behaviour by editing the `~/.config/pip/pip.conf` file,
and adding the following directive in the `[global]` section:
```text
[global]
break-system-packages = true
```
Alternatively, you can use the `pipx` tool to install Reticulum in an isolated environment:
```bash
pipx install lxmf
```
## Daemon Included
The `lxmf` package comes with the `lxmd` program, a fully functional (but lightweight) LXMF message router and propagation node daemon. After installing the `lxmf` package, you can run `lxmd --help` to learn more about the command-line options:
```text
$ lxmd --help
usage: lxmd [-h] [--config CONFIG] [--rnsconfig RNSCONFIG] [-p] [-i PATH] [-v] [-q] [-s] [--exampleconfig] [--version]
Lightweight Extensible Messaging Daemon
options:
-h, --help show this help message and exit
--config CONFIG path to alternative lxmd config directory
--rnsconfig RNSCONFIG
path to alternative Reticulum config directory
-p, --propagation-node
run an LXMF Propagation Node
-i PATH, --on-inbound PATH
executable to run when a message is received
-v, --verbose
-q, --quiet
-s, --service lxmd is running as a service and should log to file
--exampleconfig print verbose configuration example to stdout and exit
--version show program's version number and exit
```
Or run `lxmd --exampleconfig` to generate a commented example configuration documenting all the available configuration directives.
## Caveat Emptor
LXMF is beta software, and should be considered experimental. While it has been built with cryptography best practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.
## Development Roadmap
LXMF is actively being developed, and the following improvements and features are currently planned for implementation:
- ~~Update examples in readme to actually work~~
- ~~Sync affinity based on link speeds and distances, for more intelligently choosing peer sync order~~
- Sneakernet and physical transport functionality
- Content Destinations, and easy to use API for group messaging and discussion threads
- Write and release full API and protocol documentation
- Documenting and possibly expanding LXMF limits and priorities
Raw data
{
"_id": null,
"home_page": "https://github.com/markqvist/lxmf",
"name": "lxmf",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": null,
"author": "Mark Qvist",
"author_email": "mark@unsigned.io",
"download_url": "https://files.pythonhosted.org/packages/7a/8b/3bfabe7d14b369dbab7f5af037fb7c93608aa9f7cfa020216a3c942cdabf/lxmf-0.5.5.tar.gz",
"platform": null,
"description": "# Lightweight Extensible Message Format\n\nLXMF is a simple and flexible messaging format and delivery protocol that allows a wide variety of implementations, while using as little bandwidth as possible. It is built on top of [Reticulum](https://reticulum.network) and offers zero-conf message routing, end-to-end encryption and Forward Secrecy, and can be transported over any kind of medium that Reticulum supports.\n\nLXMF is efficient enough that it can deliver messages over extremely low-bandwidth systems such as packet radio or LoRa. Encrypted LXMF messages can also be encoded as QR-codes or text-based URIs, allowing completely analog *paper message* transport.\n\nUser-facing clients built on LXMF include:\n\n- [Sideband](https://unsigned.io/sideband)\n- [MeshChat](https://github.com/liamcottle/reticulum-meshchat)\n- [Nomad Network](https://unsigned.io/nomadnet)\n\nCommunity-provided tools and utilities for LXMF include:\n\n- [LXMF-Bot](https://github.com/randogoth/lxmf-bot)\n- [LXMF Messageboard](https://github.com/chengtripp/lxmf_messageboard)\n- [LXMEvent](https://github.com/faragher/LXMEvent)\n- [RangeMap](https://github.com/faragher/RangeMap)\n- [LXMF Tools](https://github.com/SebastianObi/LXMF-Tools)\n\n## Structure\n\nLXMF messages are stored in a simple and efficient format, that's easy to parse and write.\n\n### The format follows this general structure:\n\n- Destination\n- Source\n- Ed25519 Signature\n- Payload\n - Timestamp\n - Content\n - Title\n - Fields\n\n### And these rules:\n\n1. A LXMF message is identified by its __message-id__, which is a SHA-256 hash of the __Destination__, __Source__ and __Payload__. The message-id is never included directly in the message, since it can always be inferred from the message itself.\n\n In some cases the actual message-id cannot be inferred, for example when a Propagation Node is storing an encrypted message for an offline user. In these cases a _transient-id_ is used to identify the message while in storage or transit.\n\n2. __Destination__, __Source__, __Signature__ and __Payload__ parts are mandatory, as is the __Timestamp__ part of the payload.\n - The __Destination__ and __Source__ fields are 16-byte Reticulum destination hashes\n - The __Signature__ field is a 64-byte Ed25519 signature of the __Destination__, __Source__, __Payload__ and __message-id__\n - The __Payload__ part is a [msgpacked](https://msgpack.org) list containing four items:\n 1. The __Timestamp__ is a double-precision floating point number representing the number of seconds since the UNIX epoch.\n 2. The __Content__ is the optional content or body of the message\n 3. The __Title__ is an optional title for the message\n 4. The __Fields__ is an optional dictionary\n\n3. The __Content__, __Title__ and __Fields__ parts must be included in the message structure, but can be left empty.\n\n4. The __Fields__ part can be left empty, or contain a dictionary of any structure or depth.\n\n## Usage Examples\n\nLXMF offers flexibility to implement many different messaging schemes, ranging from human communication to machine control and sensor monitoring. Here are a few examples:\n\n- A messaging system for passing short, simple messages between human users, akin to SMS can be implemented using only the __Content__ field, and leaving all other optional fields empty.\n\n- For sending full-size mail, an email-like system can be implemented using the __Title__ and __Content__ fields to store \"subject\" and \"body\" parts of the message, and optionally the __Fields__ part can be used to store attachments or other metadata.\n\n- Machine-control messages or sensor readings can be implemented using command structures embedded in the __Fields__ dictionary.\n\n- Distributed discussion or news-groups, akin to USENET or similar systems, can be implemented using the relevant fields and LXMF Propagation Nodes. Broadcast bulletins can be implemented in a similar fashion.\n\n## Propagation Nodes\n\nLXM Propagation Nodes offer a way to store and forward messages to users or endpoints that are not directly reachable at the time of message emission. Propagation Nodes can also provide infrastructure for distributed bulletin, news or discussion boards.\n\nWhen Propagation Nodes exist on a Reticulum network, they will by default peer with each other and synchronise messages, automatically creating an encrypted, distributed message store. Users and other endpoints can retrieve messages destined for them from any available Propagation Nodes on the network.\n\n## The LXM Router\n\nThe LXM Router handles transporting messages over a Reticulum network, managing delivery receipts, outbound and inbound queues, and is the point of API interaction for client programs. The LXM Router also implements functionality for acting as an LXMF Propagation Node.\n\nProgramatically, using the LXM Router to send a message is as simple as:\n\n```python\nimport LXMF\n\nlxm_router = LXMF.LXMRouter()\n\nmessage = LXMF.LXMessage(destination, source, \"This is a short, simple message.\")\n\nlxm_router.handle_outbound(message)\n\n```\n\nThe LXM Router then handles the heavy lifting, such as message packing, encryption, delivery confirmation, path lookup, routing, retries and failure notifications.\n\n## Transport Encryption\n\nLXMF uses encryption provided by [Reticulum](https://reticulum.network), and thus uses end-to-end encryption by default. The delivery method of a message will influence which transport encryption scheme is used.\n\n- If a message is delivered over a Reticulum link (which is the default method), the message will be encrypted with ephemeral AES-128 keys derived with ECDH on Curve25519. This mode offers forward secrecy.\n\n- A message can be delivered opportunistically, embedded in a single Reticulum packet. In this cases the message will be opportunistically routed through the network, and will be encrypted with per-packet AES-128 keys derived with ECDH on Curve25519.\n\n- If a message is delivered to the Reticulum GROUP destination type, the message will be encrypted using the symmetric AES-128 key of the GROUP destination.\n\n## Wire Format & Overhead\n\nAssuming the default Reticulum configuration, the binary wire-format is as follows:\n\n- 16 bytes destination hash\n- 16 bytes source hash\n- 64 bytes Ed25519 signature\n- Remaining bytes of [msgpack](https://msgpack.org) payload data, in accordance with the structure defined above\n\nThe complete message overhead for LXMF is only 111 bytes, which in return gives you timestamped, digitally signed, infinitely extensible, end-to-end encrypted, zero-conf routed, minimal-infrastructure messaging that's easy to use and build applications with.\n\n## Code Examples\n\nBefore writing your own programs using LXMF, you need to have a basic understanding of how the [Reticulum](https://reticulum.network) protocol and API works. Please see the [Reticulum Manual](https://reticulum.network/manual/). For a few simple examples of how to send and receive messages with LXMF, please see the [receiver example](./docs/example_receiver.py) and the [sender example](./docs/example_sender.py) included in this repository.\n\n## Example Paper Message\n\nYou can try out the paper messaging functionality by using the following QR code. It is a paper message sent to the LXMF address `6b3362bd2c1dbf87b66a85f79a8d8c75`. To be able to decrypt and read the message, you will need to import the following Reticulum Identity to an LXMF messaging app:\n\n`3BPTDTQCRZPKJT3TXAJCMQFMOYWIM3OCLKPWMG4HCF2T4CH3YZHVNHNRDU6QAZWV2KBHMWBNT2C62TQEVC5GLFM4MN25VLZFSK3ADRQ=`\n\nThe [Sideband](https://unsigned.io/sideband) application allows you to do this easily. After you have imported the identity into an app of your choice, you can scan the following QR code and open it in the app, where it will be decrypted and added as a message.\n\n<p align=\"center\"><img width=\"50%\" src=\"./docs/paper_msg_test.png\"/></p>\n\nYou can also find the entire message in <a href=\"lxm://azNivSwdv4e2aoX3mo2MdTAozuI7BlzrLlHULmnVgpz3dNT9CMPVwgywzCJP8FVogj5j_kU7j7ywuvBNcr45kRTrd19c3iHenmnSDe4VEd6FuGsAiT0Khzl7T81YZHPTDhRNp0FdhDE9AJ7uphw7zKMyqhHHxOxqrYeBeKF66gpPxDceqjsOApvsSwggjcuHBx9OxOBy05XmnJxA1unCKgvNfOFYc1T47luxoY3c0dLOJnJPwZuFRytx2TXlQNZzOJ28yTEygIfkDqEO9mZi5lgev7XZJ0DvgioQxMIyoCm7lBUzfq66zW3SQj6vHHph7bhr36dLOCFgk4fZA6yia2MlTT9KV66Tn2l8mPNDlvuSAJhwDA_xx2PN9zKadCjo9sItkAp8r-Ss1CzoUWZUAyT1oDw7ly6RrzGBG-e3eM3CL6u1juIeFiHby7_3cON-6VTUuk4xR5nwKlFTu5vsYMVXe5H3VahiDSS4Q1aqX7I\">this link</a>:\n\n`lxm://azNivSwdv4e2aoX3mo2MdTAozuI7BlzrLlHULmnVgpz3dNT9CMPVwgywzCJP8FVogj5j_kU7j7ywuvBNcr45kRTrd19c3iHenmnSDe4VEd6FuGsAiT0Khzl7T81YZHPTDhRNp0FdhDE9AJ7uphw7zKMyqhHHxOxqrYeBeKF66gpPxDceqjsOApvsSwggjcuHBx9OxOBy05XmnJxA1unCKgvNfOFYc1T47luxoY3c0dLOJnJPwZuFRytx2TXlQNZzOJ28yTEygIfkDqEO9mZi5lgev7XZJ0DvgioQxMIyoCm7lBUzfq66zW3SQj6vHHph7bhr36dLOCFgk4fZA6yia2MlTT9KV66Tn2l8mPNDlvuSAJhwDA_xx2PN9zKadCjo9sItkAp8r-Ss1CzoUWZUAyT1oDw7ly6RrzGBG-e3eM3CL6u1juIeFiHby7_3cON-6VTUuk4xR5nwKlFTu5vsYMVXe5H3VahiDSS4Q1aqX7I`\n\nOn operating systems that allow for registering custom URI-handlers, you can click the link, and it will be decoded directly in your LXMF client. This works with Sideband on Android.\n\n## Installation\n\nIf you want to try out LXMF, you can install it with pip:\n\n```bash\npip install lxmf\n```\n\nIf you are using an operating system that blocks normal user package installation via `pip`,\nyou can return `pip` to normal behaviour by editing the `~/.config/pip/pip.conf` file,\nand adding the following directive in the `[global]` section:\n\n```text\n[global]\nbreak-system-packages = true\n```\n\nAlternatively, you can use the `pipx` tool to install Reticulum in an isolated environment:\n\n```bash\npipx install lxmf\n```\n\n## Daemon Included\n\nThe `lxmf` package comes with the `lxmd` program, a fully functional (but lightweight) LXMF message router and propagation node daemon. After installing the `lxmf` package, you can run `lxmd --help` to learn more about the command-line options:\n\n```text\n$ lxmd --help\n\nusage: lxmd [-h] [--config CONFIG] [--rnsconfig RNSCONFIG] [-p] [-i PATH] [-v] [-q] [-s] [--exampleconfig] [--version]\n\nLightweight Extensible Messaging Daemon\n\noptions:\n -h, --help show this help message and exit\n --config CONFIG path to alternative lxmd config directory\n --rnsconfig RNSCONFIG\n path to alternative Reticulum config directory\n -p, --propagation-node\n run an LXMF Propagation Node\n -i PATH, --on-inbound PATH\n executable to run when a message is received\n -v, --verbose\n -q, --quiet\n -s, --service lxmd is running as a service and should log to file\n --exampleconfig print verbose configuration example to stdout and exit\n --version show program's version number and exit\n```\n\nOr run `lxmd --exampleconfig` to generate a commented example configuration documenting all the available configuration directives.\n\n## Caveat Emptor\n\nLXMF is beta software, and should be considered experimental. While it has been built with cryptography best practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.\n\n## Development Roadmap\n\nLXMF is actively being developed, and the following improvements and features are currently planned for implementation:\n\n- ~~Update examples in readme to actually work~~\n- ~~Sync affinity based on link speeds and distances, for more intelligently choosing peer sync order~~\n- Sneakernet and physical transport functionality\n- Content Destinations, and easy to use API for group messaging and discussion threads \n- Write and release full API and protocol documentation\n- Documenting and possibly expanding LXMF limits and priorities\n",
"bugtrack_url": null,
"license": null,
"summary": "Lightweight Extensible Message Format for Reticulum",
"version": "0.5.5",
"project_urls": {
"Homepage": "https://github.com/markqvist/lxmf"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8bd59bb50062aeaf153521bc61b6549fd4bbfa00bb8d0aeb2fc67a4a7d8b6f12",
"md5": "c85139991465d9620935652f6a5f3331",
"sha256": "d6ad732880937972ba66b087d54199a8e86db40d1403d7d11fa4727b0d6bd50f"
},
"downloads": -1,
"filename": "lxmf-0.5.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c85139991465d9620935652f6a5f3331",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 44701,
"upload_time": "2024-10-06T09:07:42",
"upload_time_iso_8601": "2024-10-06T09:07:42.569886Z",
"url": "https://files.pythonhosted.org/packages/8b/d5/9bb50062aeaf153521bc61b6549fd4bbfa00bb8d0aeb2fc67a4a7d8b6f12/lxmf-0.5.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "7a8b3bfabe7d14b369dbab7f5af037fb7c93608aa9f7cfa020216a3c942cdabf",
"md5": "18dac60f950ca621153f1d957af466e0",
"sha256": "f2afe1ea9b09b08b75bb477586e4e5491bea91a14b63dce47df3db7e1ad6d66c"
},
"downloads": -1,
"filename": "lxmf-0.5.5.tar.gz",
"has_sig": false,
"md5_digest": "18dac60f950ca621153f1d957af466e0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 50639,
"upload_time": "2024-10-06T09:07:44",
"upload_time_iso_8601": "2024-10-06T09:07:44.809551Z",
"url": "https://files.pythonhosted.org/packages/7a/8b/3bfabe7d14b369dbab7f5af037fb7c93608aa9f7cfa020216a3c942cdabf/lxmf-0.5.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-06 09:07:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "markqvist",
"github_project": "lxmf",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "qrcode",
"specs": [
[
"==",
"7.4.2"
]
]
},
{
"name": "rns",
"specs": [
[
"==",
"0.7.8"
]
]
},
{
"name": "setuptools",
"specs": [
[
"==",
"70.0.0"
]
]
}
],
"lcname": "lxmf"
}