mirror of
https://github.com/markqvist/LXMF.git
synced 2024-12-25 07:09:37 -05:00
Added readme
This commit is contained in:
parent
ac5c751bb4
commit
4589610b1f
20
LXMF.py
20
LXMF.py
@ -166,17 +166,17 @@ class LXMessage:
|
||||
self.timestamp = time.time()
|
||||
self.payload = [self.timestamp, self.title, self.content, self.fields]
|
||||
|
||||
hashed_part = b""
|
||||
hashed_part += self.__destination.hash
|
||||
hashed_part += self.__source.hash
|
||||
hashed_part += msgpack.packb(self.timestamp)
|
||||
hashed_part += msgpack.packb(self.payload)
|
||||
self.hash = RNS.Identity.fullHash(hashed_part)
|
||||
hashed_part = b""
|
||||
hashed_part += self.__destination.hash
|
||||
hashed_part += self.__source.hash
|
||||
hashed_part += msgpack.packb(self.payload)
|
||||
self.hash = RNS.Identity.fullHash(hashed_part)
|
||||
self.message_id = self.hash
|
||||
|
||||
signed_part = b""
|
||||
signed_part += hashed_part
|
||||
signed_part += self.hash
|
||||
self.signature = self.__source.sign(signed_part)
|
||||
signed_part = b""
|
||||
signed_part += hashed_part
|
||||
signed_part += self.hash
|
||||
self.signature = self.__source.sign(signed_part)
|
||||
|
||||
self.packed = b""
|
||||
self.packed += self.__destination.hash
|
||||
|
844
README.html
Normal file
844
README.html
Normal file
@ -0,0 +1,844 @@
|
||||
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><style>@font-face {
|
||||
font-family: octicons-anchor;
|
||||
src: url(https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/font/octicons.woff) format('woff');
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 980px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
color:#333;
|
||||
background:#fff;
|
||||
}
|
||||
|
||||
body .markdown-body {
|
||||
padding: 45px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
pre {
|
||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
color: #333;
|
||||
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.markdown-body a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.markdown-body a:active,
|
||||
.markdown-body a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.markdown-body strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.markdown-body code,
|
||||
.markdown-body kbd,
|
||||
.markdown-body pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown-body html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.markdown-body input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.markdown-body td,
|
||||
.markdown-body th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
font: 13px / 1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
}
|
||||
|
||||
.markdown-body a {
|
||||
color: #4078c0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body a:hover,
|
||||
.markdown-body a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
height: 0;
|
||||
margin: 15px 0;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body hr:before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body hr:after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown-body h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown-body h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-body h6 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body ol ol,
|
||||
.markdown-body ul ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
.markdown-body ul ul ol,
|
||||
.markdown-body ul ol ol,
|
||||
.markdown-body ol ul ol,
|
||||
.markdown-body ol ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
.markdown-body dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.markdown-body code {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
.markdown-body .select::-ms-expand {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.markdown-body .octicon {
|
||||
font: normal normal normal 16px/1 octicons-anchor;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.markdown-body .octicon-link:before {
|
||||
content: '\f05c';
|
||||
}
|
||||
|
||||
.markdown-body:before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body:after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body>*:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body a:not([href]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body .anchor {
|
||||
display: inline-block;
|
||||
padding-right: 2px;
|
||||
margin-left: -18px;
|
||||
}
|
||||
|
||||
.markdown-body .anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.markdown-body h1 .octicon-link,
|
||||
.markdown-body h2 .octicon-link,
|
||||
.markdown-body h3 .octicon-link,
|
||||
.markdown-body h4 .octicon-link,
|
||||
.markdown-body h5 .octicon-link,
|
||||
.markdown-body h6 .octicon-link {
|
||||
color: #000;
|
||||
vertical-align: middle;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor,
|
||||
.markdown-body h2:hover .anchor,
|
||||
.markdown-body h3:hover .anchor,
|
||||
.markdown-body h4:hover .anchor,
|
||||
.markdown-body h5:hover .anchor,
|
||||
.markdown-body h6:hover .anchor {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor .octicon-link,
|
||||
.markdown-body h2:hover .anchor .octicon-link,
|
||||
.markdown-body h3:hover .anchor .octicon-link,
|
||||
.markdown-body h4:hover .anchor .octicon-link,
|
||||
.markdown-body h5:hover .anchor .octicon-link,
|
||||
.markdown-body h6:hover .anchor .octicon-link {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 2.25em;
|
||||
line-height: 1.2;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h1 .anchor {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.75em;
|
||||
line-height: 1.225;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h2 .anchor {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.43;
|
||||
}
|
||||
|
||||
.markdown-body h3 .anchor {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.markdown-body h4 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.markdown-body h4 .anchor {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.markdown-body h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body h5 .anchor {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.markdown-body h6 {
|
||||
font-size: 1em;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.markdown-body h6 .anchor {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.markdown-body p,
|
||||
.markdown-body blockquote,
|
||||
.markdown-body ul,
|
||||
.markdown-body ol,
|
||||
.markdown-body dl,
|
||||
.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
margin: 16px 0;
|
||||
background-color: #e7e7e7;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.markdown-body ul ul,
|
||||
.markdown-body ul ol,
|
||||
.markdown-body ol ol,
|
||||
.markdown-body ol ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body li>p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.markdown-body dl {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body dl dt {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body dl dd {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
padding: 0 15px;
|
||||
color: #777;
|
||||
border-left: 4px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
word-break: normal;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.markdown-body table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body table th,
|
||||
.markdown-body table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.markdown-body table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
max-width: 100%;
|
||||
box-sizing: content-box;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.markdown-body code {
|
||||
padding: 0;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body code:before,
|
||||
.markdown-body code:after {
|
||||
letter-spacing: -0.2em;
|
||||
content: "\00a0";
|
||||
}
|
||||
|
||||
.markdown-body pre>code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
word-break: normal;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body .highlight {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre,
|
||||
.markdown-body pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre {
|
||||
margin-bottom: 0;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.markdown-body pre code {
|
||||
display: inline;
|
||||
max-width: initial;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: initial;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body pre code:before,
|
||||
.markdown-body pre code:after {
|
||||
content: normal;
|
||||
}
|
||||
|
||||
.markdown-body kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font-size: 11px;
|
||||
line-height: 10px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
background-color: #fcfcfc;
|
||||
border: solid 1px #ccc;
|
||||
border-bottom-color: #bbb;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #bbb;
|
||||
}
|
||||
|
||||
.markdown-body .pl-c {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.markdown-body .pl-c1,
|
||||
.markdown-body .pl-s .pl-v {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.markdown-body .pl-e,
|
||||
.markdown-body .pl-en {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.markdown-body .pl-s .pl-s1,
|
||||
.markdown-body .pl-smi {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ent {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.markdown-body .pl-k {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.markdown-body .pl-pds,
|
||||
.markdown-body .pl-s,
|
||||
.markdown-body .pl-s .pl-pse .pl-s1,
|
||||
.markdown-body .pl-sr,
|
||||
.markdown-body .pl-sr .pl-cce,
|
||||
.markdown-body .pl-sr .pl-sra,
|
||||
.markdown-body .pl-sr .pl-sre {
|
||||
color: #183691;
|
||||
}
|
||||
|
||||
.markdown-body .pl-v {
|
||||
color: #ed6a43;
|
||||
}
|
||||
|
||||
.markdown-body .pl-id {
|
||||
color: #b52a1d;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ii {
|
||||
background-color: #b52a1d;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.markdown-body .pl-sr .pl-cce {
|
||||
color: #63a35c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ml {
|
||||
color: #693a17;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mh,
|
||||
.markdown-body .pl-mh .pl-en,
|
||||
.markdown-body .pl-ms {
|
||||
color: #1d3e81;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mq {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mi {
|
||||
color: #333;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mb {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body .pl-md {
|
||||
background-color: #ffecec;
|
||||
color: #bd2c00;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mi1 {
|
||||
background-color: #eaffea;
|
||||
color: #55a532;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mdr {
|
||||
color: #795da3;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mo {
|
||||
color: #1d3e81;
|
||||
}
|
||||
|
||||
.markdown-body kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
line-height: 10px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
background-color: #fcfcfc;
|
||||
border: solid 1px #ccc;
|
||||
border-bottom-color: #bbb;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #bbb;
|
||||
}
|
||||
|
||||
.markdown-body .plan-price-unit {
|
||||
color: #767676;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item+.task-list-item {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item input {
|
||||
margin: 0 0.35em 0.25em -1.6em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice {
|
||||
padding: 15px;
|
||||
padding-left: 40px;
|
||||
display: block;
|
||||
border: 1px solid #e0e0e0;
|
||||
position: relative;
|
||||
font-weight: normal;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice.open {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice.open .plan-choice-seat-breakdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice-free {
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice-paid {
|
||||
border-radius: 0 0 3px 3px;
|
||||
border-top: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice-radio {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 18px;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice-exp {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.markdown-body .plan-choice-seat-breakdown {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.markdown-body :checked+.radio-label {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
border-color: #4078c0;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body .markdown-body {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style><title>README</title></head><body><article class="markdown-body"><h1>
|
||||
<a id="user-content-lightweight-extensible-message-format" class="anchor" href="#lightweight-extensible-message-format" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Lightweight Extensible Message Format</h1>
|
||||
<p>LXMF is a simple and flexible messaging format that allows a wide variety of implementations, while using as little bandwidth as possible. It is built on top of <a href="https://github.com/markqvist/reticulum">Reticulum</a> and offers zero-conf message routing, end-to-end encryption and Perfect Forward Secrecy by default.</p>
|
||||
<h2>
|
||||
<a id="user-content-structure" class="anchor" href="#structure" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Structure</h2>
|
||||
<p>LXMF messages are stored in a simple and efficient format, that's easy to parse and write.</p>
|
||||
<h5>
|
||||
<a id="user-content-the-format-follows-this-general-structure" class="anchor" href="#the-format-follows-this-general-structure" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>The format follows this general structure:</h5>
|
||||
<ul>
|
||||
<li>Destination</li>
|
||||
<li>Source</li>
|
||||
<li>RSA Signature</li>
|
||||
<li>Payload
|
||||
<ul>
|
||||
<li>Timestamp</li>
|
||||
<li>Title</li>
|
||||
<li>Content</li>
|
||||
<li>Fields</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h5>
|
||||
<a id="user-content-and-these-rules" class="anchor" href="#and-these-rules" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>And these rules:</h5>
|
||||
<ol>
|
||||
<li>
|
||||
<p>A LXMF message is identified by it's <strong>message-id</strong>, which is a SHA-256 hash of the <strong>Destination</strong>, <strong>Source</strong> and <strong>Payload</strong>. The message-id is never included directly in the message, since it can always be inferred from the message itself.</p>
|
||||
<p>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 theses cases a <em>transient-id</em> is used to identify the message while in storage or transit.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Destination</strong>, <strong>Source</strong>, <strong>Signature</strong> and <strong>Payload</strong> parts are mandatory, as is the <strong>Timestamp</strong> part of the payload.</p>
|
||||
<ul>
|
||||
<li>The <strong>Destination</strong> and <strong>Source</strong> fields are Reticulum destination hashes</li>
|
||||
<li>The <strong>Signature</strong> field is a RSA signature of the <strong>Destination</strong>, <strong>Source</strong>, <strong>Payload</strong> and <strong>message-id</strong>
|
||||
</li>
|
||||
<li>The <strong>Payload</strong> part is a list containing four items:
|
||||
<ol>
|
||||
<li>The <strong>Timestamp</strong> is double-precision floating point number representing the number of seconds since the UNIX epoch.</li>
|
||||
<li>The <strong>Title</strong> is an optional title for the message</li>
|
||||
<li>The <strong>Content</strong> is the optional content or body of the message</li>
|
||||
<li>The <strong>Fields</strong> is an optional dictionary</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>The <strong>Title</strong>, <strong>Content</strong> and <strong>Fields</strong> parts must be included in the message structure, but can be left empty.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The <strong>Fields</strong> part can be left empty, or contain a dictionary of any structure or depth.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2>
|
||||
<a id="user-content-usage-examples" class="anchor" href="#usage-examples" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Usage Examples</h2>
|
||||
<p>LXMF offers flexibility to implement many different messaging schemes, ranging from human communication to machine control and sensor monitoring. Here's a few examples:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>A messaging system for passing short, simple messages between human users, akin to SMS can be implemented using only the <strong>Content</strong> field, and leaving all other optional fields empty.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For sending full-size mail, an email-like system can be implemented using the <strong>Title</strong> and <strong>Content</strong> fields to store "subject" and "body" parts of the message, and optionally the <strong>Fields</strong> part can be used to store attachments or other metadata.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Machine-control messages or sensor readings can be implemented using command structures embedded in the <strong>Fields</strong> dictionary.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>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.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>
|
||||
<a id="user-content-propagation-nodes" class="anchor" href="#propagation-nodes" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Propagation Nodes</h2>
|
||||
<p>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.</p>
|
||||
<h2>
|
||||
<a id="user-content-the-lxm-router" class="anchor" href="#the-lxm-router" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>The LXM Router</h2>
|
||||
<p>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.</p>
|
||||
<p>Programatically, using the LXM Router to send a message is as simple as:</p>
|
||||
<div class="highlight highlight-source-python"><pre><span class="pl-k">import</span> <span class="pl-c1">LXMF</span>
|
||||
|
||||
lxm_router <span class="pl-k">=</span> <span class="pl-c1">LXMF</span>.LXMRouter()
|
||||
|
||||
message <span class="pl-k">=</span> <span class="pl-c1">LXMF</span>.LXMessage(destination, source, <span class="pl-s"><span class="pl-pds">"</span>This is a short, simple message.<span class="pl-pds">"</span></span>)
|
||||
|
||||
lxm_router.handle_outbound(message)
|
||||
</pre></div>
|
||||
<p>The LXM Router then handles the heavy lifting, such as message packing, encryption, delivery confirmation, path lookup, routing, retries and failure notifications.</p>
|
||||
<h2>
|
||||
<a id="user-content-transport-encryption" class="anchor" href="#transport-encryption" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Transport Encryption</h2>
|
||||
<p>LXMF uses encryption provided by <a href="https://github.com/markqvist/reticulum">Reticulum</a>, and thus uses end-to-end encryption by default. The delivery method of a message will influence which transport encryption scheme is used.</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>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 use <em>RSA-1024</em> asymmetric encryption.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If a message is delivered to the Reticulum GROUP destination type, the message will be transported using <em>AES-128</em> encryption.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If a message is delivered over a Reticulum link (which is the default method), the message will be encrypted with <em>ephemeral ECDH</em> on the <em>SECP256R1</em> curve. This mode offers Perfect Forward Secrecy.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>
|
||||
<a id="user-content-wire-format--overhead" class="anchor" href="#wire-format--overhead" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Wire Format & Overhead</h2>
|
||||
<p>Assuming the default Reticulum configuration, the binary wire-format is as follows:</p>
|
||||
<ul>
|
||||
<li>10 bytes destination hash</li>
|
||||
<li>10 bytes source hash</li>
|
||||
<li>128 bytes RSA signature</li>
|
||||
<li>Remaining bytes of <a href="https://msgpack.org" rel="nofollow">msgpack</a> payload data, in accordance with the structure defined above</li>
|
||||
</ul>
|
||||
<p>The complete message overhead for LXMF is only 163 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.</p>
|
||||
<h2>
|
||||
<a id="user-content-caveat-emptor" class="anchor" href="#caveat-emptor" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Caveat Emptor</h2>
|
||||
<p>As with Reticulum, LXMF is alpha software, and should be considered experimental. While it has been built with cryptography best-practices very foremost in mind, it <em>has not</em> 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.</p>
|
||||
</article></body></html>
|
100
README.md
100
README.md
@ -1,2 +1,98 @@
|
||||
# LXMF
|
||||
Lightweight Extensible Message Format for Reticulum
|
||||
Lightweight Extensible Message Format
|
||||
==========
|
||||
|
||||
LXMF is a simple and flexible messaging format that allows a wide variety of implementations, while using as little bandwidth as possible. It is built on top of [Reticulum](https://github.com/markqvist/reticulum) and offers zero-conf message routing, end-to-end encryption and Perfect Forward Secrecy by default.
|
||||
|
||||
## 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
|
||||
- RSA Signature
|
||||
- Payload
|
||||
- Timestamp
|
||||
- Title
|
||||
- Content
|
||||
- Fields
|
||||
|
||||
##### And these rules:
|
||||
|
||||
1. A LXMF message is identified by it's __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 theses 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 Reticulum destination hashes
|
||||
- The __Signature__ field is a RSA signature of the __Destination__, __Source__, __Payload__ and __message-id__
|
||||
- The __Payload__ part is a list containing four items:
|
||||
1. The __Timestamp__ is double-precision floating point number representing the number of seconds since the UNIX epoch.
|
||||
2. The __Title__ is an optional title for the message
|
||||
3. The __Content__ is the optional content or body of the message
|
||||
4. The __Fields__ is an optional dictionary
|
||||
|
||||
3. The __Title__, __Content__ 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's 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.
|
||||
|
||||
## 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://github.com/markqvist/reticulum), and thus uses end-to-end encryption by default. The delivery method of a message will influence which transport encryption scheme is used.
|
||||
|
||||
- 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 use _RSA-1024_ asymmetric encryption.
|
||||
|
||||
- If a message is delivered to the Reticulum GROUP destination type, the message will be transported using _AES-128_ encryption.
|
||||
|
||||
- If a message is delivered over a Reticulum link (which is the default method), the message will be encrypted with _ephemeral ECDH_ on the _SECP256R1_ curve. This mode offers Perfect Forward Secrecy.
|
||||
|
||||
## Wire Format & Overhead
|
||||
|
||||
Assuming the default Reticulum configuration, the binary wire-format is as follows:
|
||||
|
||||
- 10 bytes destination hash
|
||||
- 10 bytes source hash
|
||||
- 128 bytes RSA 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 163 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.
|
||||
|
||||
## Caveat Emptor
|
||||
|
||||
As with Reticulum, LXMF is alpha 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.
|
Loading…
Reference in New Issue
Block a user