added sound notification support and forward secery setting finished

master
Kevin Froman 2020-02-17 06:13:57 -06:00
parent 23782dcb8f
commit aea4815fbd
11 changed files with 76 additions and 42 deletions

View File

@ -1,9 +1,17 @@
''' """Onionr - Private P2P Communication.
Onionr - Private P2P Communication
Create blocks with the client api server Create blocks with the client api server
''' """
''' import json
import threading
from flask import Blueprint, Response, request, g
import onionrblocks
from onionrcrypto import hashers
from onionrutils import bytesconverter
from onionrutils import mnemonickeys
from onionrtypes import JSONSerializable
"""
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -16,20 +24,15 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' """
import json, threading
from flask import Blueprint, Response, request, g
import onionrblocks
from onionrcrypto import hashers
from onionrutils import bytesconverter
from onionrutils import mnemonickeys
ib = Blueprint('insertblock', __name__) ib = Blueprint('insertblock', __name__)
@ib.route('/insertblock', methods=['POST']) @ib.route('/insertblock', methods=['POST'])
def client_api_insert_block(): def client_api_insert_block():
encrypt = False encrypt: bool = False
bData = request.get_json(force=True) insert_data: JSONSerializable = request.get_json(force=True)
message = bData['message'] message = insert_data['message']
message_hash = bytesconverter.bytes_to_str(hashers.sha3_hash(message)) message_hash = bytesconverter.bytes_to_str(hashers.sha3_hash(message))
# Detect if message (block body) is not specified # Detect if message (block body) is not specified
@ -37,40 +40,48 @@ def client_api_insert_block():
return 'failure due to unspecified message', 400 return 'failure due to unspecified message', 400
# Detect if block with same message is already being inserted # Detect if block with same message is already being inserted
if message_hash in g.too_many.get_by_string("OnionrCommunicatorDaemon").generating_blocks: if message_hash in g.too_many.get_by_string(
"OnionrCommunicatorDaemon").generating_blocks:
return 'failure due to duplicate insert', 400 return 'failure due to duplicate insert', 400
else: else:
g.too_many.get_by_string("OnionrCommunicatorDaemon").generating_blocks.append(message_hash) g.too_many.get_by_string(
"OnionrCommunicatorDaemon").generating_blocks.append(message_hash)
subject = 'temp' encrypt_type = ''
encryptType = ''
sign = True sign = True
meta = {} meta = {}
to = '' to = ''
try: try:
if bData['encrypt']: if insert_data['encrypt']:
to = bData['to'].strip() to = insert_data['to'].strip()
if "-" in to: if "-" in to:
to = mnemonickeys.get_base32(to) to = mnemonickeys.get_base32(to)
encrypt = True encrypt_type = 'asym'
encryptType = 'asym'
except KeyError: except KeyError:
pass pass
try: try:
if not bData['sign']: if not insert_data['sign']:
sign = False sign = False
except KeyError: except KeyError:
pass pass
try: try:
bType = bData['type'] bType = insert_data['type']
except KeyError: except KeyError:
bType = 'bin' bType = 'bin'
try: try:
meta = json.loads(bData['meta']) meta = json.loads(insert_data['meta'])
except KeyError: except KeyError:
pass pass
try:
# The setting in the UI is for if forward secrecy is enabled, not disabled
disable_forward_secrecy = not insert_data['forward']
except KeyError:
disable_forward_secrecy = False
threading.Thread( threading.Thread(
target=onionrblocks.insert, args=(message,), target=onionrblocks.insert, args=(message,),
kwargs={'header': bType, 'encryptType': encryptType, kwargs={'header': bType, 'encryptType': encrypt_type,
'sign':sign, 'asymPeer': to, 'meta': meta, 'disableForward': bData['forward']}).start() 'sign': sign, 'asymPeer': to, 'meta': meta,
'disableForward': disable_forward_secrecy}).start()
return Response('success') return Response('success')

View File

@ -2,6 +2,8 @@
Desktop notification wrapper Desktop notification wrapper
""" """
from subprocess import Popen
try: try:
import simplenotifications as simplenotify import simplenotifications as simplenotify
except ImportError: except ImportError:
@ -9,6 +11,7 @@ except ImportError:
else: else:
notifications_enabled = True notifications_enabled = True
from utils.readstatic import get_static_dir
import config import config
""" """
@ -29,9 +32,18 @@ import config
if not config.get('general.show_notifications', True): if not config.get('general.show_notifications', True):
notifications_enabled = False notifications_enabled = False
notification_sound_file = get_static_dir() + "sounds/notification1.mp3"
def notify(title: str = "Onionr", message: str = ""): def notify(title: str = "Onionr", message: str = ""):
"""Cross platform method to show a notification.""" """Cross platform method to show a notification."""
if not notifications_enabled: if not notifications_enabled:
return return
simplenotify.notify(title, message) simplenotify.notify(title, message)
def notification_with_sound(sound = '', **kwargs):
try:
Popen(["mpv", notification_sound_file])
except FileNotFoundError:
pass
notify(**kwargs)

View File

@ -132,7 +132,7 @@ def insert_block(data: Union[str, bytes], header: str = 'txt',
if encryptType == 'asym': if encryptType == 'asym':
meta['rply'] = createTime # Duplicate the time in encrypted messages to prevent replays meta['rply'] = createTime # Duplicate the time in encrypted messages to prevent replays
if not disableForward and sign and asymPeer != our_pub_key: if sign and asymPeer != our_pub_key:
try: try:
forwardEncrypted = onionrusers.OnionrUser(asymPeer).forwardEncrypt(data) forwardEncrypted = onionrusers.OnionrUser(asymPeer).forwardEncrypt(data)
data = forwardEncrypted[0] data = forwardEncrypted[0]
@ -140,9 +140,8 @@ def insert_block(data: Union[str, bytes], header: str = 'txt',
expire = forwardEncrypted[2] # Expire time of key. no sense keeping block after that expire = forwardEncrypted[2] # Expire time of key. no sense keeping block after that
except onionrexceptions.InvalidPubkey: except onionrexceptions.InvalidPubkey:
pass pass
#onionrusers.OnionrUser(self, asymPeer).generateForwardKey() if not disableForward:
fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey() fsKey = onionrusers.OnionrUser(asymPeer).generateForwardKey()
#fsKey = onionrusers.OnionrUser(self, asymPeer).getGeneratedForwardKeys().reverse()
meta['newFSKey'] = fsKey meta['newFSKey'] = fsKey
jsonMeta = json.dumps(meta) jsonMeta = json.dumps(meta)
plaintextMeta = jsonMeta plaintextMeta = jsonMeta
@ -196,6 +195,8 @@ def insert_block(data: Union[str, bytes], header: str = 'txt',
logger.error(allocationReachedMessage) logger.error(allocationReachedMessage)
retData = False retData = False
else: else:
if disableForward:
logger.warn(f'{retData} asym encrypted block created w/o forward secrecy')
# Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult # Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult
spawn( spawn(
localcommand.local_command, localcommand.local_command,

View File

@ -17,7 +17,9 @@ QUOTES = [
("Like a black hole, NSA pulls in every signal that comes near, but no electron is ever allowed to escape", ("Like a black hole, NSA pulls in every signal that comes near, but no electron is ever allowed to escape",
"James Bamford"), "James Bamford"),
("Freedom of the press is guaranteed only to those who own one", ("Freedom of the press is guaranteed only to those who own one",
"A. J. Liebling") "A. J. Liebling"),
("We kill people based on metadata",
"Authoritarians")
] ]
shuffle(QUOTES) shuffle(QUOTES)
QUOTE = QUOTES[0] QUOTE = QUOTES[0]

View File

@ -72,7 +72,8 @@ def open_home():
'Onionr seems to not be running (could not get api host)', 'Onionr seems to not be running (could not get api host)',
terminal=True) terminal=True)
else: else:
_wait_for_ui_to_be_ready() _wait_for_ui_to_be_ready() # wait for Tor/transports to start
sleep(3) # Sleep a little longer to wait for web UI to init some vars it needs
url = get_url() url = get_url()
logger.info( logger.info(
'If Onionr does not open automatically, use this URL: ' + url, 'If Onionr does not open automatically, use this URL: ' + url,

View File

@ -1,7 +1,6 @@
""" """Onionr - Private P2P Communication.
Onionr - Private P2P Communication
module to get static directory and read static data files get static directory and read static data files
""" """
""" """
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -20,9 +19,12 @@
from typing import Union from typing import Union
import os import os
def get_static_dir()->str: def get_static_dir()->str:
return os.path.dirname(os.path.realpath(__file__)) + '/../../static-data/' return os.path.dirname(os.path.realpath(__file__)) + '/../../static-data/'
def read_static(file:str, ret_bin:bool=False)->Union[str, bytes]: def read_static(file:str, ret_bin:bool=False)->Union[str, bytes]:
static_file = get_static_dir() + file static_file = get_static_dir() + file

View File

@ -70,4 +70,4 @@ def on_processblocks(api, data=None):
signer = signer[:5] signer = signer[:5]
if data['block'].decrypted: if data['block'].decrypted:
notifier.notify(title="Onionr Mail - New Message", message="From: %s\n\nSubject: %s" % (signer, metadata['subject'])) notifier.notification_with_sound(title="Onionr Mail - New Message", message="From: %s\n\nSubject: %s" % (signer, metadata['subject']))

View File

@ -18,6 +18,7 @@
<script defer src="/shared/main/apicheck.js"></script> <script defer src="/shared/main/apicheck.js"></script>
<script defer src="/shared/misc.js"></script> <script defer src="/shared/misc.js"></script>
<script defer src="/mail/sethumanreadable.js"></script> <script defer src="/mail/sethumanreadable.js"></script>
<script defer src="/mail/loadsettings.js"></script>
<script defer src="/mail/mail.js"></script> <script defer src="/mail/mail.js"></script>
<script defer src="/mail/sendmail.js"></script> <script defer src="/mail/sendmail.js"></script>
<script defer src="/mail/closesettings.js"></script> <script defer src="/mail/closesettings.js"></script>
@ -141,7 +142,8 @@
<section class="modal-card-body"> <section class="modal-card-body">
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
Use forward secrecy <div>Ask senders to use forward-secrecy</div>
<small>Only turn off if you use multiple devices with 1 ID or have Onionr data erasure on exit enabled.</small>
</div> </div>
<div class="column is-2"> <div class="column is-2">
<div class="field"> <div class="field">

View File

@ -24,7 +24,9 @@ subject = document.getElementById('draftSubject')
friendPicker = document.getElementById('friendSelect') friendPicker = document.getElementById('friendSelect')
function sendMail(toData, message, subject){ function sendMail(toData, message, subject){
postData = {'message': message, 'to': toData, 'type': 'pm', 'encrypt': true, 'meta': JSON.stringify({'subject': subject})} postData = {'message': message, 'to': toData, 'type': 'pm', 'encrypt': true, 'meta': JSON.stringify({'subject': subject})}
postData.forward = document.getElementById('forwardSecrecySetting').checked
postData = JSON.stringify(postData) postData = JSON.stringify(postData)
sendForm.style.display = 'none' sendForm.style.display = 'none'
fetch('/insertblock', { fetch('/insertblock', {

View File

@ -28,6 +28,7 @@ document.getElementById('forwardSecrecySetting').onchange = function(e){
}}) }})
.then((resp) => resp.text()) .then((resp) => resp.text())
.then(function(data) { .then(function(data) {
mailSettings['forwardSecrecy'] = document.getElementById('forwardSecrecySetting').checked
PNotify.success({ PNotify.success({
text: 'Successfully toggled default forward secrecy' text: 'Successfully toggled default forward secrecy'
}) })