diff --git a/README.md b/README.md index 8b0de5c2..ebae2e10 100755 --- a/README.md +++ b/README.md @@ -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. +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) ## Main Features diff --git a/docs/api.md b/docs/http-api.md similarity index 100% rename from docs/api.md rename to docs/http-api.md diff --git a/docs/block-spec.md b/docs/specs/block-spec.md similarity index 96% rename from docs/block-spec.md rename to docs/specs/block-spec.md index 0a5f1491..f9cd3509 100644 --- a/docs/block-spec.md +++ b/docs/specs/block-spec.md @@ -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. -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 diff --git a/onionr/api.py b/onionr/api.py index bba548c5..415707e5 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -26,7 +26,7 @@ import core from onionrblockapi import Block import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config import httpapi -from httpapi import friendsapi, simplecache +from httpapi import friendsapi, simplecache, profilesapi from onionrservices import httpheaders import onionr @@ -256,7 +256,8 @@ class API: self.bindPort = bindPort # 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.timeBypassToken = base64.b16encode(os.urandom(32)).decode() @@ -272,6 +273,7 @@ class API: onionrInst.setClientAPIInst(self) app.register_blueprint(friendsapi.friends) app.register_blueprint(simplecache.simplecache) + app.register_blueprint(profilesapi.profile_BP) httpapi.load_plugin_blueprints(app) @app.before_request @@ -318,6 +320,14 @@ class API: @app.route('/friends/', endpoint='friendsindex') def loadContacts(): return send_from_directory('static-data/www/friends/', 'index.html') + + @app.route('/profiles/', 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/') def serviceActive(pubkey): diff --git a/onionr/httpapi/profilesapi/__init__.py b/onionr/httpapi/profilesapi/__init__.py new file mode 100644 index 00000000..f3c3ba2f --- /dev/null +++ b/onionr/httpapi/profilesapi/__init__.py @@ -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 . +''' +import core +from flask import Blueprint, Response, request, abort +from . import profiles + +profile_BP = Blueprint('profile_BP', __name__) + +@profile_BP.route('/profile/get/', endpoint='profiles') +def get_profile_page(pubkey): + return Response(pubkey) \ No newline at end of file diff --git a/onionr/httpapi/profilesapi/profiles.py b/onionr/httpapi/profilesapi/profiles.py new file mode 100644 index 00000000..11a73b13 --- /dev/null +++ b/onionr/httpapi/profilesapi/profiles.py @@ -0,0 +1,2 @@ +def get_latest_user_profile(pubkey): + return '' \ No newline at end of file diff --git a/onionr/static-data/bootstrap-nodes.txt b/onionr/static-data/bootstrap-nodes.txt index 374ea7b4..52622b12 100755 --- a/onionr/static-data/bootstrap-nodes.txt +++ b/onionr/static-data/bootstrap-nodes.txt @@ -1 +1 @@ -huei7fugyuesltkf3yzj27an36skz2f2u55g7ganyaq6yjhauwicwfyd.onion +ecaufnpxx67xmvzwcriohapmmnqbj665h3ynemvwrr2juxl5oa5g7cad.onion diff --git a/onionr/static-data/default-plugins/pms/mailapi.py b/onionr/static-data/default-plugins/pms/mailapi.py index 87cdb678..0a60e67c 100644 --- a/onionr/static-data/default-plugins/pms/mailapi.py +++ b/onionr/static-data/default-plugins/pms/mailapi.py @@ -42,6 +42,7 @@ def mail_delete(block): if block not in existing: existing.append(block) kv.put('deleted_mail', existing) + kv.flush() return 'success' @flask_blueprint.route('/mail/getinbox') @@ -50,16 +51,30 @@ def list_inbox(): @flask_blueprint.route('/mail/getsentbox') def list_sentbox(): + kv.refresh() sentbox_list = sentboxdb.SentBox(c).listSent() - sentbox_list_copy = list(sentbox_list) + list_copy = list(sentbox_list) deleted = kv.get('deleted_mail') if deleted is None: 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: - x -= 1 - sentbox_list.pop(x) + sentbox_list.remove(sentbox_list_copy[x]['hash']) else: sentbox_list[x]['name'] = contactmanager.ContactManager(c, sentbox_list_copy[x]['peer'], saveUser=False).get_info('name') - return json.dumps(sentbox_list) \ No newline at end of file + return json.dumps(sentbox_list) +''' \ No newline at end of file diff --git a/onionr/static-data/default_config.json b/onionr/static-data/default_config.json index 2b9d47df..988e91f0 100755 --- a/onionr/static-data/default_config.json +++ b/onionr/static-data/default_config.json @@ -4,12 +4,12 @@ "display_header" : false, "minimum_block_pow": 4, "minimum_send_pow": 4, - "socket_servers": true, + "socket_servers": false, "security_level": 0, "max_block_age": 2678400, "bypass_tor_check": false, "public_key": "", - "random_bind_ip": true + "random_bind_ip": false }, "www" : { diff --git a/onionr/static-data/www/mail/index.html b/onionr/static-data/www/mail/index.html index 8af6f035..f3f337bd 100644 --- a/onionr/static-data/www/mail/index.html +++ b/onionr/static-data/www/mail/index.html @@ -36,8 +36,11 @@
From: Signature:
+
+ Subject: +
- +
diff --git a/onionr/static-data/www/mail/mail.css b/onionr/static-data/www/mail/mail.css index af80deb1..88afc0b9 100644 --- a/onionr/static-data/www/mail/mail.css +++ b/onionr/static-data/www/mail/mail.css @@ -92,7 +92,7 @@ input{ color: black; } -#replyBtn{ +.break-up{ margin-top: 1em; } diff --git a/onionr/static-data/www/mail/mail.js b/onionr/static-data/www/mail/mail.js index 302c84f6..cfbb7e89 100644 --- a/onionr/static-data/www/mail/mail.js +++ b/onionr/static-data/www/mail/mail.js @@ -26,7 +26,7 @@ threadContent = {} myPub = httpGet('/getActivePubkey') replyBtn = document.getElementById('replyBtn') -function openReply(bHash){ +function openReply(bHash, quote, subject){ var inbox = document.getElementsByClassName('threadEntry') var entry = '' var friendName = '' @@ -41,13 +41,23 @@ function openReply(bHash){ } key = entry.getAttribute('data-pubkey') 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') } -function openThread(bHash, sender, date, sigBool, pubkey){ +function openThread(bHash, sender, date, sigBool, pubkey, subjectLine){ var messageDisplay = document.getElementById('threadDisplay') var blockContent = httpGet('/getblockbody/' + bHash) document.getElementById('fromUser').value = sender + document.getElementById('subjectView').innerText = subjectLine messageDisplay.innerText = blockContent var sigEl = document.getElementById('sigValid') var sigMsg = 'signature' @@ -64,7 +74,7 @@ function openThread(bHash, sender, date, sigBool, pubkey){ sigEl.innerText = sigMsg overlay('messageDisplay') replyBtn.onclick = function(){ - openReply(bHash) + openReply(bHash, messageDisplay.innerText, subjectLine) } } @@ -174,7 +184,7 @@ function loadInboxEntries(bHash){ if (event.target.classList.contains('deleteBtn')){ 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(){ @@ -216,7 +226,7 @@ function getSentbox(){ if (keys.length == 0){ 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 obj = resp[i] var toLabel = document.createElement('span') @@ -245,19 +255,18 @@ function getSentbox(){ entry.appendChild(toEl) entry.appendChild(preview) 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) - } + + 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) }.bind(threadPart)) } @@ -304,7 +313,6 @@ for (var i = 0; i < document.getElementsByClassName('refresh').length; i++){ document.getElementsByClassName('refresh')[i].style.float = 'right' } - fetch('/friends/list', { headers: { "token": webpass diff --git a/onionr/static-data/www/profiles/index.html b/onionr/static-data/www/profiles/index.html new file mode 100644 index 00000000..a4dad9b7 --- /dev/null +++ b/onionr/static-data/www/profiles/index.html @@ -0,0 +1,20 @@ + + + + + + Onionr Profiles + + + + + + +
+

+
+ + + + + \ No newline at end of file diff --git a/onionr/static-data/www/profiles/profiles.js b/onionr/static-data/www/profiles/profiles.js new file mode 100644 index 00000000..e69de29b