fixes for mail, work on specs, and added files for profile viewer
This commit is contained in:
parent
ad94c8a4ef
commit
45ddbe5e69
@ -27,6 +27,8 @@ Users are identified by ed25519 public keys, which can be used to sign blocks or
|
|||||||
|
|
||||||
Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion.
|
Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion.
|
||||||
|
|
||||||
|
The whitepaper (subject to change prior to first alpha release) is available [here](docs/whitepaper.md).
|
||||||
|
|
||||||
![Tor stinks slide image](docs/tor-stinks-02.png)
|
![Tor stinks slide image](docs/tor-stinks-02.png)
|
||||||
|
|
||||||
## Main Features
|
## Main Features
|
||||||
|
@ -6,8 +6,7 @@ Onionr 'Blocks' are the primary means of sharing information in Onionr. Blocks a
|
|||||||
|
|
||||||
They contain a JSON metadata section followed by a line break, with the main data following.
|
They contain a JSON metadata section followed by a line break, with the main data following.
|
||||||
|
|
||||||
In the future, the spec will be updated to use flags and MessagePack instead of JSON with english keys.
|
In the future, the specification will likely be updated to use flags and MessagePack instead of JSON with english keys.
|
||||||
|
|
||||||
|
|
||||||
# Encryption and Signatures
|
# Encryption and Signatures
|
||||||
|
|
@ -26,7 +26,7 @@ import core
|
|||||||
from onionrblockapi import Block
|
from onionrblockapi import Block
|
||||||
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config
|
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config
|
||||||
import httpapi
|
import httpapi
|
||||||
from httpapi import friendsapi, simplecache
|
from httpapi import friendsapi, simplecache, profilesapi
|
||||||
from onionrservices import httpheaders
|
from onionrservices import httpheaders
|
||||||
import onionr
|
import onionr
|
||||||
|
|
||||||
@ -256,7 +256,8 @@ class API:
|
|||||||
self.bindPort = bindPort
|
self.bindPort = bindPort
|
||||||
|
|
||||||
# Be extremely mindful of this. These are endpoints available without a password
|
# Be extremely mindful of this. These are endpoints available without a password
|
||||||
self.whitelistEndpoints = ('site', 'www', 'onionrhome', 'board', 'boardContent', 'sharedContent', 'mail', 'mailindex', 'friends', 'friendsindex')
|
self.whitelistEndpoints = ('site', 'www', 'onionrhome', 'board', 'profiles', 'profilesindex',
|
||||||
|
'boardContent', 'sharedContent', 'mail', 'mailindex', 'friends', 'friendsindex')
|
||||||
|
|
||||||
self.clientToken = config.get('client.webpassword')
|
self.clientToken = config.get('client.webpassword')
|
||||||
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
|
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
|
||||||
@ -272,6 +273,7 @@ class API:
|
|||||||
onionrInst.setClientAPIInst(self)
|
onionrInst.setClientAPIInst(self)
|
||||||
app.register_blueprint(friendsapi.friends)
|
app.register_blueprint(friendsapi.friends)
|
||||||
app.register_blueprint(simplecache.simplecache)
|
app.register_blueprint(simplecache.simplecache)
|
||||||
|
app.register_blueprint(profilesapi.profile_BP)
|
||||||
httpapi.load_plugin_blueprints(app)
|
httpapi.load_plugin_blueprints(app)
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
@ -319,6 +321,14 @@ class API:
|
|||||||
def loadContacts():
|
def loadContacts():
|
||||||
return send_from_directory('static-data/www/friends/', 'index.html')
|
return send_from_directory('static-data/www/friends/', 'index.html')
|
||||||
|
|
||||||
|
@app.route('/profiles/<path:path>', endpoint='profiles')
|
||||||
|
def loadContacts(path):
|
||||||
|
return send_from_directory('static-data/www/profiles/', path)
|
||||||
|
|
||||||
|
@app.route('/profiles/', endpoint='profilesindex')
|
||||||
|
def loadContacts():
|
||||||
|
return send_from_directory('static-data/www/profiles/', 'index.html')
|
||||||
|
|
||||||
@app.route('/serviceactive/<pubkey>')
|
@app.route('/serviceactive/<pubkey>')
|
||||||
def serviceActive(pubkey):
|
def serviceActive(pubkey):
|
||||||
try:
|
try:
|
||||||
|
28
onionr/httpapi/profilesapi/__init__.py
Normal file
28
onionr/httpapi/profilesapi/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
'''
|
||||||
|
Onionr - P2P Anonymous Storage Network
|
||||||
|
|
||||||
|
This file creates http endpoints for user profile pages
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
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
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
'''
|
||||||
|
import core
|
||||||
|
from flask import Blueprint, Response, request, abort
|
||||||
|
from . import profiles
|
||||||
|
|
||||||
|
profile_BP = Blueprint('profile_BP', __name__)
|
||||||
|
|
||||||
|
@profile_BP.route('/profile/get/<pubkey>', endpoint='profiles')
|
||||||
|
def get_profile_page(pubkey):
|
||||||
|
return Response(pubkey)
|
2
onionr/httpapi/profilesapi/profiles.py
Normal file
2
onionr/httpapi/profilesapi/profiles.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
def get_latest_user_profile(pubkey):
|
||||||
|
return ''
|
@ -1 +1 @@
|
|||||||
huei7fugyuesltkf3yzj27an36skz2f2u55g7ganyaq6yjhauwicwfyd.onion
|
ecaufnpxx67xmvzwcriohapmmnqbj665h3ynemvwrr2juxl5oa5g7cad.onion
|
||||||
|
@ -42,6 +42,7 @@ def mail_delete(block):
|
|||||||
if block not in existing:
|
if block not in existing:
|
||||||
existing.append(block)
|
existing.append(block)
|
||||||
kv.put('deleted_mail', existing)
|
kv.put('deleted_mail', existing)
|
||||||
|
kv.flush()
|
||||||
return 'success'
|
return 'success'
|
||||||
|
|
||||||
@flask_blueprint.route('/mail/getinbox')
|
@flask_blueprint.route('/mail/getinbox')
|
||||||
@ -50,16 +51,30 @@ def list_inbox():
|
|||||||
|
|
||||||
@flask_blueprint.route('/mail/getsentbox')
|
@flask_blueprint.route('/mail/getsentbox')
|
||||||
def list_sentbox():
|
def list_sentbox():
|
||||||
|
kv.refresh()
|
||||||
sentbox_list = sentboxdb.SentBox(c).listSent()
|
sentbox_list = sentboxdb.SentBox(c).listSent()
|
||||||
sentbox_list_copy = list(sentbox_list)
|
list_copy = list(sentbox_list)
|
||||||
deleted = kv.get('deleted_mail')
|
deleted = kv.get('deleted_mail')
|
||||||
if deleted is None:
|
if deleted is None:
|
||||||
deleted = []
|
deleted = []
|
||||||
for x in range(len(sentbox_list_copy) - 1):
|
for x in list_copy:
|
||||||
|
if x['hash'] in deleted:
|
||||||
|
sentbox_list.remove(x)
|
||||||
|
return json.dumps(sentbox_list)
|
||||||
|
'''
|
||||||
|
@flask_blueprint.route('/mail/getsentbox')
|
||||||
|
def list_sentbox():
|
||||||
|
sentbox_list = sentboxdb.SentBox(c).listSent()
|
||||||
|
sentbox_list_copy = list(sentbox_list)
|
||||||
|
kv.refresh()
|
||||||
|
deleted = kv.get('deleted_mail')
|
||||||
|
if deleted is None:
|
||||||
|
deleted = []
|
||||||
|
for x in range(len(sentbox_list_copy)):
|
||||||
if sentbox_list_copy[x]['hash'] in deleted:
|
if sentbox_list_copy[x]['hash'] in deleted:
|
||||||
x -= 1
|
sentbox_list.remove(sentbox_list_copy[x]['hash'])
|
||||||
sentbox_list.pop(x)
|
|
||||||
else:
|
else:
|
||||||
sentbox_list[x]['name'] = contactmanager.ContactManager(c, sentbox_list_copy[x]['peer'], saveUser=False).get_info('name')
|
sentbox_list[x]['name'] = contactmanager.ContactManager(c, sentbox_list_copy[x]['peer'], saveUser=False).get_info('name')
|
||||||
|
|
||||||
return json.dumps(sentbox_list)
|
return json.dumps(sentbox_list)
|
||||||
|
'''
|
@ -4,12 +4,12 @@
|
|||||||
"display_header" : false,
|
"display_header" : false,
|
||||||
"minimum_block_pow": 4,
|
"minimum_block_pow": 4,
|
||||||
"minimum_send_pow": 4,
|
"minimum_send_pow": 4,
|
||||||
"socket_servers": true,
|
"socket_servers": false,
|
||||||
"security_level": 0,
|
"security_level": 0,
|
||||||
"max_block_age": 2678400,
|
"max_block_age": 2678400,
|
||||||
"bypass_tor_check": false,
|
"bypass_tor_check": false,
|
||||||
"public_key": "",
|
"public_key": "",
|
||||||
"random_bind_ip": true
|
"random_bind_ip": false
|
||||||
},
|
},
|
||||||
|
|
||||||
"www" : {
|
"www" : {
|
||||||
|
@ -36,8 +36,11 @@
|
|||||||
<div>
|
<div>
|
||||||
From: <input type='text' id='fromUser' readonly> Signature: <span id='sigValid'></span>
|
From: <input type='text' id='fromUser' readonly> Signature: <span id='sigValid'></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class='break-up'>
|
||||||
|
Subject: <span id='subjectView'></span>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button id='replyBtn' class='primaryBtn'>Reply</button>
|
<button id='replyBtn' class='primaryBtn break-up'>Reply</button>
|
||||||
</div>
|
</div>
|
||||||
<div id='signatureValidity'></div>
|
<div id='signatureValidity'></div>
|
||||||
<div id='threadDisplay' class='pre messageContent'>
|
<div id='threadDisplay' class='pre messageContent'>
|
||||||
|
@ -92,7 +92,7 @@ input{
|
|||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#replyBtn{
|
.break-up{
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ threadContent = {}
|
|||||||
myPub = httpGet('/getActivePubkey')
|
myPub = httpGet('/getActivePubkey')
|
||||||
replyBtn = document.getElementById('replyBtn')
|
replyBtn = document.getElementById('replyBtn')
|
||||||
|
|
||||||
function openReply(bHash){
|
function openReply(bHash, quote, subject){
|
||||||
var inbox = document.getElementsByClassName('threadEntry')
|
var inbox = document.getElementsByClassName('threadEntry')
|
||||||
var entry = ''
|
var entry = ''
|
||||||
var friendName = ''
|
var friendName = ''
|
||||||
@ -41,13 +41,23 @@ function openReply(bHash){
|
|||||||
}
|
}
|
||||||
key = entry.getAttribute('data-pubkey')
|
key = entry.getAttribute('data-pubkey')
|
||||||
document.getElementById('draftID').value = key
|
document.getElementById('draftID').value = key
|
||||||
|
document.getElementById('draftSubject').value = 'RE: ' + subject
|
||||||
|
|
||||||
|
// Add quoted reply
|
||||||
|
var splitQuotes = quote.split('\n')
|
||||||
|
for (var x = 0; x < splitQuotes.length; x++){
|
||||||
|
splitQuotes[x] = '>' + splitQuotes[x]
|
||||||
|
}
|
||||||
|
quote = splitQuotes.join('\n')
|
||||||
|
document.getElementById('draftText').value = quote
|
||||||
setActiveTab('send message')
|
setActiveTab('send message')
|
||||||
}
|
}
|
||||||
|
|
||||||
function openThread(bHash, sender, date, sigBool, pubkey){
|
function openThread(bHash, sender, date, sigBool, pubkey, subjectLine){
|
||||||
var messageDisplay = document.getElementById('threadDisplay')
|
var messageDisplay = document.getElementById('threadDisplay')
|
||||||
var blockContent = httpGet('/getblockbody/' + bHash)
|
var blockContent = httpGet('/getblockbody/' + bHash)
|
||||||
document.getElementById('fromUser').value = sender
|
document.getElementById('fromUser').value = sender
|
||||||
|
document.getElementById('subjectView').innerText = subjectLine
|
||||||
messageDisplay.innerText = blockContent
|
messageDisplay.innerText = blockContent
|
||||||
var sigEl = document.getElementById('sigValid')
|
var sigEl = document.getElementById('sigValid')
|
||||||
var sigMsg = 'signature'
|
var sigMsg = 'signature'
|
||||||
@ -64,7 +74,7 @@ function openThread(bHash, sender, date, sigBool, pubkey){
|
|||||||
sigEl.innerText = sigMsg
|
sigEl.innerText = sigMsg
|
||||||
overlay('messageDisplay')
|
overlay('messageDisplay')
|
||||||
replyBtn.onclick = function(){
|
replyBtn.onclick = function(){
|
||||||
openReply(bHash)
|
openReply(bHash, messageDisplay.innerText, subjectLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +184,7 @@ function loadInboxEntries(bHash){
|
|||||||
if (event.target.classList.contains('deleteBtn')){
|
if (event.target.classList.contains('deleteBtn')){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
openThread(entry.getAttribute('data-hash'), senderInput.value, dateStr.innerText, resp['meta']['validSig'], entry.getAttribute('data-pubkey'))
|
openThread(entry.getAttribute('data-hash'), senderInput.value, dateStr.innerText, resp['meta']['validSig'], entry.getAttribute('data-pubkey'), subjectLine.innerText)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteBtn.onclick = function(){
|
deleteBtn.onclick = function(){
|
||||||
@ -216,7 +226,7 @@ function getSentbox(){
|
|||||||
if (keys.length == 0){
|
if (keys.length == 0){
|
||||||
threadPart.innerHTML = "nothing to show here yet."
|
threadPart.innerHTML = "nothing to show here yet."
|
||||||
}
|
}
|
||||||
for (var i = 0; i < keys.length; i++){
|
for (var i = 0; i < keys.length; i++) (function(i, resp){
|
||||||
var entry = document.createElement('div')
|
var entry = document.createElement('div')
|
||||||
var obj = resp[i]
|
var obj = resp[i]
|
||||||
var toLabel = document.createElement('span')
|
var toLabel = document.createElement('span')
|
||||||
@ -245,19 +255,18 @@ function getSentbox(){
|
|||||||
entry.appendChild(toEl)
|
entry.appendChild(toEl)
|
||||||
entry.appendChild(preview)
|
entry.appendChild(preview)
|
||||||
entry.appendChild(sentDate)
|
entry.appendChild(sentDate)
|
||||||
entry.onclick = (function(tree, el, msg) {return function() {
|
|
||||||
console.log(resp)
|
|
||||||
if (! entry.classList.contains('deleteBtn')){
|
|
||||||
showSentboxWindow(el.value, msg)
|
|
||||||
}
|
|
||||||
};})(entry, toEl, message);
|
|
||||||
|
|
||||||
deleteBtn.onclick = function(){
|
|
||||||
entry.parentNode.removeChild(entry);
|
|
||||||
deleteMessage(entry.getAttribute('data-hash'))
|
|
||||||
}
|
|
||||||
threadPart.appendChild(entry)
|
threadPart.appendChild(entry)
|
||||||
}
|
|
||||||
|
entry.onclick = function(e){
|
||||||
|
if (e.target.classList.contains('deleteBtn')){
|
||||||
|
deleteMessage(e.target.parentNode.getAttribute('data-hash'))
|
||||||
|
e.target.parentNode.parentNode.removeChild(e.target.parentNode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showSentboxWindow()
|
||||||
|
}
|
||||||
|
})(i, resp)
|
||||||
threadPart.appendChild(entry)
|
threadPart.appendChild(entry)
|
||||||
}.bind(threadPart))
|
}.bind(threadPart))
|
||||||
}
|
}
|
||||||
@ -304,7 +313,6 @@ for (var i = 0; i < document.getElementsByClassName('refresh').length; i++){
|
|||||||
document.getElementsByClassName('refresh')[i].style.float = 'right'
|
document.getElementsByClassName('refresh')[i].style.float = 'right'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fetch('/friends/list', {
|
fetch('/friends/list', {
|
||||||
headers: {
|
headers: {
|
||||||
"token": webpass
|
"token": webpass
|
||||||
|
20
onionr/static-data/www/profiles/index.html
Normal file
20
onionr/static-data/www/profiles/index.html
Normal file
File diff suppressed because one or more lines are too long
0
onionr/static-data/www/profiles/profiles.js
Normal file
0
onionr/static-data/www/profiles/profiles.js
Normal file
Loading…
Reference in New Issue
Block a user