Onionr/docs/html/onionr/onionrblocks/insert.html

386 lines
20 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="generator" content="pdoc 0.6.3" />
<title>onionr.onionrblocks.insert API documentation</title>
<meta name="description" content="" />
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase;cursor:pointer}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
</head>
<body>
<main>
<article id="content">
<header>
<h1 class="title">Module <code>onionr.onionrblocks.insert</code></h1>
</header>
<section id="section-intro">
<details class="source">
<summary>Source code</summary>
<pre><code class="python">from typing import Union
import json
from onionrutils import bytesconverter, epoch
import filepaths, onionrstorage
from . import storagecounter
from onionrplugins import onionrevents as events
from etc import powchoice, onionrvalues
import config, onionrcrypto as crypto, onionrexceptions
from onionrusers import onionrusers
from onionrutils import localcommand, blockmetadata, stringvalidators
import coredb
import onionrproofs
from onionrproofs import subprocesspow
import logger
def insert_block(data: Union[str, bytes], header: str =&#39;txt&#39;,
sign: bool =False, encryptType:str =&#39;&#39;, symKey:str =&#39;&#39;,
asymPeer:str =&#39;&#39;, meta:dict = {},
expire:Union[int, None] =None, disableForward:bool =False)-&gt;Union[str,bool]:
&#34;&#34;&#34;
Inserts a block into the network
encryptType must be specified to encrypt a block
&#34;&#34;&#34;
use_subprocess = powchoice.use_subprocess(config)
storage_counter = storagecounter.StorageCounter()
allocationReachedMessage = &#39;Cannot insert block, disk allocation reached.&#39;
if storage_counter.is_full():
logger.error(allocationReachedMessage)
raise onionrexceptions.DiskAllocationReached
retData = False
if type(data) is None:
raise ValueError(&#39;Data cannot be none&#39;)
createTime = epoch.get_epoch()
dataNonce = bytesconverter.bytes_to_str(crypto.hashers.sha3_hash(data))
try:
with open(filepaths.data_nonce_file, &#39;r&#39;) as nonces:
if dataNonce in nonces:
return retData
except FileNotFoundError:
pass
# record nonce
with open(filepaths.data_nonce_file, &#39;a&#39;) as nonceFile:
nonceFile.write(dataNonce + &#39;\n&#39;)
if type(data) is bytes:
data = data.decode()
data = str(data)
plaintext = data
plaintextMeta = {}
plaintextPeer = asymPeer
retData = &#39;&#39;
signature = &#39;&#39;
signer = &#39;&#39;
metadata = {}
# metadata is full block metadata, meta is internal, user specified metadata
# only use header if not set in provided meta
meta[&#39;type&#39;] = str(header)
if encryptType in (&#39;asym&#39;, &#39;sym&#39;):
metadata[&#39;encryptType&#39;] = encryptType
else:
if not encryptType in (&#39;&#39;, None):
raise onionrexceptions.InvalidMetadata(&#39;encryptType must be asym or sym, or blank&#39;)
try:
data = data.encode()
except AttributeError:
pass
if encryptType == &#39;asym&#39;:
meta[&#39;rply&#39;] = createTime # Duplicate the time in encrypted messages to prevent replays
if not disableForward and sign and asymPeer != crypto.pub_key:
try:
forwardEncrypted = onionrusers.OnionrUser(asymPeer).forwardEncrypt(data)
data = forwardEncrypted[0]
meta[&#39;forwardEnc&#39;] = True
expire = forwardEncrypted[2] # Expire time of key. no sense keeping block after that
except onionrexceptions.InvalidPubkey:
pass
#onionrusers.OnionrUser(self, asymPeer).generateForwardKey()
fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey()
#fsKey = onionrusers.OnionrUser(self, asymPeer).getGeneratedForwardKeys().reverse()
meta[&#39;newFSKey&#39;] = fsKey
jsonMeta = json.dumps(meta)
plaintextMeta = jsonMeta
if sign:
signature = crypto.signing.ed_sign(jsonMeta.encode() + data, key=crypto.priv_key, encodeResult=True)
signer = crypto.pub_key
if len(jsonMeta) &gt; 1000:
raise onionrexceptions.InvalidMetadata(&#39;meta in json encoded form must not exceed 1000 bytes&#39;)
# encrypt block metadata/sig/content
if encryptType == &#39;sym&#39;:
raise NotImplementedError(&#34;not yet implemented&#34;)
elif encryptType == &#39;asym&#39;:
if stringvalidators.validate_pub_key(asymPeer):
# Encrypt block data with forward secrecy key first, but not meta
jsonMeta = json.dumps(meta)
jsonMeta = crypto.encryption.pub_key_encrypt(jsonMeta, asymPeer, encodedData=True).decode()
data = crypto.encryption.pub_key_encrypt(data, asymPeer, encodedData=False)#.decode()
signature = crypto.encryption.pub_key_encrypt(signature, asymPeer, encodedData=True).decode()
signer = crypto.encryption.pub_key_encrypt(signer, asymPeer, encodedData=True).decode()
try:
onionrusers.OnionrUser(asymPeer, saveUser=True)
except ValueError:
# if peer is already known
pass
else:
raise onionrexceptions.InvalidPubkey(asymPeer + &#39; is not a valid base32 encoded ed25519 key&#39;)
# compile metadata
metadata[&#39;meta&#39;] = jsonMeta
if len(signature) &gt; 0: # I don&#39;t like not pattern
metadata[&#39;sig&#39;] = signature
metadata[&#39;signer&#39;] = signer
metadata[&#39;time&#39;] = createTime
# ensure expire is integer and of sane length
if type(expire) is not type(None):
if not len(str(int(expire))) &lt; 20: raise ValueError(&#39;expire must be valid int less than 20 digits in length&#39;)
metadata[&#39;expire&#39;] = expire
# send block data (and metadata) to POW module to get tokenized block data
if use_subprocess:
payload = subprocesspow.SubprocessPOW(data, metadata).start()
else:
payload = onionrproofs.POW(metadata, data).waitForResult()
if payload != False:
try:
retData = onionrstorage.set_data(payload)
except onionrexceptions.DiskAllocationReached:
logger.error(allocationReachedMessage)
retData = False
else:
# Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult
if localcommand.local_command(&#39;/ping&#39;, maxWait=10) == &#39;pong!&#39;:
if config.get(&#39;general.security_level&#39;, 1) == 0:
localcommand.local_command(&#39;/waitforshare/&#39; + retData, post=True, maxWait=5)
coredb.daemonqueue.daemon_queue_add(&#39;uploadBlock&#39;, retData)
else:
pass
coredb.blockmetadb.add.add_to_block_DB(retData, selfInsert=True, dataSaved=True)
if expire is None:
coredb.blockmetadb.update_block_info(retData, &#39;expire&#39;, createTime + onionrvalues.DEFAULT_EXPIRE)
else:
coredb.blockmetadb.update_block_info(retData, &#39;expire&#39;, expire)
blockmetadata.process_block_metadata(retData)
if retData != False:
if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:
events.event(&#39;insertdeniable&#39;, {&#39;content&#39;: plaintext, &#39;meta&#39;: plaintextMeta, &#39;hash&#39;: retData, &#39;peer&#39;: bytesconverter.bytes_to_str(asymPeer)}, threaded = True)
else:
events.event(&#39;insertblock&#39;, {&#39;content&#39;: plaintext, &#39;meta&#39;: plaintextMeta, &#39;hash&#39;: retData, &#39;peer&#39;: bytesconverter.bytes_to_str(asymPeer)}, threaded = True)
coredb.daemonqueue.daemon_queue_add(&#39;remove_from_insert_list&#39;, data=dataNonce)
return retData</code></pre>
</details>
</section>
<section>
</section>
<section>
</section>
<section>
<h2 class="section-title" id="header-functions">Functions</h2>
<dl>
<dt id="onionr.onionrblocks.insert.insert_block"><code class="name flex">
<span>def <span class="ident">insert_block</span></span>(<span>data, header='txt', sign=False, encryptType='', symKey='', asymPeer='', meta={}, expire=None, disableForward=False)</span>
</code></dt>
<dd>
<section class="desc"><p>Inserts a block into the network
encryptType must be specified to encrypt a block</p></section>
<details class="source">
<summary>Source code</summary>
<pre><code class="python">def insert_block(data: Union[str, bytes], header: str =&#39;txt&#39;,
sign: bool =False, encryptType:str =&#39;&#39;, symKey:str =&#39;&#39;,
asymPeer:str =&#39;&#39;, meta:dict = {},
expire:Union[int, None] =None, disableForward:bool =False)-&gt;Union[str,bool]:
&#34;&#34;&#34;
Inserts a block into the network
encryptType must be specified to encrypt a block
&#34;&#34;&#34;
use_subprocess = powchoice.use_subprocess(config)
storage_counter = storagecounter.StorageCounter()
allocationReachedMessage = &#39;Cannot insert block, disk allocation reached.&#39;
if storage_counter.is_full():
logger.error(allocationReachedMessage)
raise onionrexceptions.DiskAllocationReached
retData = False
if type(data) is None:
raise ValueError(&#39;Data cannot be none&#39;)
createTime = epoch.get_epoch()
dataNonce = bytesconverter.bytes_to_str(crypto.hashers.sha3_hash(data))
try:
with open(filepaths.data_nonce_file, &#39;r&#39;) as nonces:
if dataNonce in nonces:
return retData
except FileNotFoundError:
pass
# record nonce
with open(filepaths.data_nonce_file, &#39;a&#39;) as nonceFile:
nonceFile.write(dataNonce + &#39;\n&#39;)
if type(data) is bytes:
data = data.decode()
data = str(data)
plaintext = data
plaintextMeta = {}
plaintextPeer = asymPeer
retData = &#39;&#39;
signature = &#39;&#39;
signer = &#39;&#39;
metadata = {}
# metadata is full block metadata, meta is internal, user specified metadata
# only use header if not set in provided meta
meta[&#39;type&#39;] = str(header)
if encryptType in (&#39;asym&#39;, &#39;sym&#39;):
metadata[&#39;encryptType&#39;] = encryptType
else:
if not encryptType in (&#39;&#39;, None):
raise onionrexceptions.InvalidMetadata(&#39;encryptType must be asym or sym, or blank&#39;)
try:
data = data.encode()
except AttributeError:
pass
if encryptType == &#39;asym&#39;:
meta[&#39;rply&#39;] = createTime # Duplicate the time in encrypted messages to prevent replays
if not disableForward and sign and asymPeer != crypto.pub_key:
try:
forwardEncrypted = onionrusers.OnionrUser(asymPeer).forwardEncrypt(data)
data = forwardEncrypted[0]
meta[&#39;forwardEnc&#39;] = True
expire = forwardEncrypted[2] # Expire time of key. no sense keeping block after that
except onionrexceptions.InvalidPubkey:
pass
#onionrusers.OnionrUser(self, asymPeer).generateForwardKey()
fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey()
#fsKey = onionrusers.OnionrUser(self, asymPeer).getGeneratedForwardKeys().reverse()
meta[&#39;newFSKey&#39;] = fsKey
jsonMeta = json.dumps(meta)
plaintextMeta = jsonMeta
if sign:
signature = crypto.signing.ed_sign(jsonMeta.encode() + data, key=crypto.priv_key, encodeResult=True)
signer = crypto.pub_key
if len(jsonMeta) &gt; 1000:
raise onionrexceptions.InvalidMetadata(&#39;meta in json encoded form must not exceed 1000 bytes&#39;)
# encrypt block metadata/sig/content
if encryptType == &#39;sym&#39;:
raise NotImplementedError(&#34;not yet implemented&#34;)
elif encryptType == &#39;asym&#39;:
if stringvalidators.validate_pub_key(asymPeer):
# Encrypt block data with forward secrecy key first, but not meta
jsonMeta = json.dumps(meta)
jsonMeta = crypto.encryption.pub_key_encrypt(jsonMeta, asymPeer, encodedData=True).decode()
data = crypto.encryption.pub_key_encrypt(data, asymPeer, encodedData=False)#.decode()
signature = crypto.encryption.pub_key_encrypt(signature, asymPeer, encodedData=True).decode()
signer = crypto.encryption.pub_key_encrypt(signer, asymPeer, encodedData=True).decode()
try:
onionrusers.OnionrUser(asymPeer, saveUser=True)
except ValueError:
# if peer is already known
pass
else:
raise onionrexceptions.InvalidPubkey(asymPeer + &#39; is not a valid base32 encoded ed25519 key&#39;)
# compile metadata
metadata[&#39;meta&#39;] = jsonMeta
if len(signature) &gt; 0: # I don&#39;t like not pattern
metadata[&#39;sig&#39;] = signature
metadata[&#39;signer&#39;] = signer
metadata[&#39;time&#39;] = createTime
# ensure expire is integer and of sane length
if type(expire) is not type(None):
if not len(str(int(expire))) &lt; 20: raise ValueError(&#39;expire must be valid int less than 20 digits in length&#39;)
metadata[&#39;expire&#39;] = expire
# send block data (and metadata) to POW module to get tokenized block data
if use_subprocess:
payload = subprocesspow.SubprocessPOW(data, metadata).start()
else:
payload = onionrproofs.POW(metadata, data).waitForResult()
if payload != False:
try:
retData = onionrstorage.set_data(payload)
except onionrexceptions.DiskAllocationReached:
logger.error(allocationReachedMessage)
retData = False
else:
# Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult
if localcommand.local_command(&#39;/ping&#39;, maxWait=10) == &#39;pong!&#39;:
if config.get(&#39;general.security_level&#39;, 1) == 0:
localcommand.local_command(&#39;/waitforshare/&#39; + retData, post=True, maxWait=5)
coredb.daemonqueue.daemon_queue_add(&#39;uploadBlock&#39;, retData)
else:
pass
coredb.blockmetadb.add.add_to_block_DB(retData, selfInsert=True, dataSaved=True)
if expire is None:
coredb.blockmetadb.update_block_info(retData, &#39;expire&#39;, createTime + onionrvalues.DEFAULT_EXPIRE)
else:
coredb.blockmetadb.update_block_info(retData, &#39;expire&#39;, expire)
blockmetadata.process_block_metadata(retData)
if retData != False:
if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:
events.event(&#39;insertdeniable&#39;, {&#39;content&#39;: plaintext, &#39;meta&#39;: plaintextMeta, &#39;hash&#39;: retData, &#39;peer&#39;: bytesconverter.bytes_to_str(asymPeer)}, threaded = True)
else:
events.event(&#39;insertblock&#39;, {&#39;content&#39;: plaintext, &#39;meta&#39;: plaintextMeta, &#39;hash&#39;: retData, &#39;peer&#39;: bytesconverter.bytes_to_str(asymPeer)}, threaded = True)
coredb.daemonqueue.daemon_queue_add(&#39;remove_from_insert_list&#39;, data=dataNonce)
return retData</code></pre>
</details>
</dd>
</dl>
</section>
<section>
</section>
</article>
<nav id="sidebar">
<h1>Index</h1>
<div class="toc">
<ul></ul>
</div>
<ul id="index">
<li><h3>Super-module</h3>
<ul>
<li><code><a title="onionr.onionrblocks" href="index.html">onionr.onionrblocks</a></code></li>
</ul>
</li>
<li><h3><a href="#header-functions">Functions</a></h3>
<ul class="">
<li><code><a title="onionr.onionrblocks.insert.insert_block" href="#onionr.onionrblocks.insert.insert_block">insert_block</a></code></li>
</ul>
</li>
</ul>
</nav>
</main>
<footer id="footer">
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.6.3</a>.</p>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad()</script>
</body>
</html>