Moved plugin web files to be in the plugin folder to reduce staticfiles blueprint coupling
This commit is contained in:
parent
14f2d03ebf
commit
37e5dbab4b
23 changed files with 37 additions and 40 deletions
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Auto refresh board posts
|
||||
|
||||
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/>.
|
||||
*/
|
||||
var checkbox = document.getElementById('refreshCheckbox')
|
||||
function autoRefresh(){
|
||||
if (! checkbox.checked || document.hidden){return}
|
||||
getBlocks()
|
||||
}
|
||||
|
||||
function setupInterval(){
|
||||
if (checkbox.checked){
|
||||
refreshInterval = setInterval(autoRefresh, 3000)
|
||||
autoRefresh()
|
||||
return
|
||||
}
|
||||
clearInterval(refreshInterval)
|
||||
}
|
||||
|
||||
var refreshInterval = setInterval(autoRefresh, 3000)
|
||||
setupInterval()
|
||||
|
||||
checkbox.onchange = function(){setupInterval}
|
||||
|
||||
|
||||
document.addEventListener("visibilitychange", function() {
|
||||
if (document.visibilityState === 'visible') {
|
||||
autoRefresh()
|
||||
}
|
||||
})
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
This file handles the boards/circles interface
|
||||
|
||||
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/>.
|
||||
*/
|
||||
requested = []
|
||||
newPostForm = document.getElementById('addMsg')
|
||||
firstLoad = true
|
||||
lastLoadedBoard = 'global'
|
||||
loadingMessage = document.getElementById('loadingBoard')
|
||||
loadedAny = false
|
||||
loadingTimeout = 8000
|
||||
|
||||
let toggleLoadingMessage = function(){
|
||||
switch (loadingMessage.style.display){
|
||||
case "inline-block":
|
||||
loadingMessage.style.display = "none"
|
||||
break;
|
||||
default:
|
||||
loadingMessage.style.display = "initial"
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fetch('/circles/version', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((ver) => ver.text())
|
||||
.then(function(ver) {
|
||||
document.getElementById('circlesVersion').innerText = ver
|
||||
})
|
||||
|
||||
function appendMessages(msg, blockHash, beforeHash, channel) {
|
||||
if (channel !== document.getElementById('feedIDInput').value) return // ignore if channel name isn't matching
|
||||
if (msg.length == 0) return // ignore empty messages
|
||||
|
||||
var humanDate = new Date(0)
|
||||
var msgDate = msg['meta']['time']
|
||||
var feed = document.getElementById("feed")
|
||||
var beforeEl = null
|
||||
|
||||
if (msgDate === undefined){
|
||||
msgDate = 'unknown'
|
||||
} else {
|
||||
humanDate.setUTCSeconds(msgDate)
|
||||
msgDate = humanDate.toLocaleString("en-US", {timeZone: "Etc/GMT"})
|
||||
}
|
||||
|
||||
var el = document.createElement('div')
|
||||
el.innerText = msg['content']
|
||||
|
||||
if (beforeHash !== null) {
|
||||
for (i = 0; i < feed.children.length; i++) {
|
||||
if (feed.children[i].getAttribute('data-bl') === beforeHash) {
|
||||
beforeEl = feed.children[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Template Test */
|
||||
// Test to see if the browser supports the HTML template element by checking
|
||||
// for the presence of the template element's content attribute.
|
||||
if ('content' in document.createElement('template')) {
|
||||
|
||||
// Instantiate the table with the existing HTML tbody
|
||||
// and the row with the template
|
||||
var template = document.getElementById('cMsgTemplate')
|
||||
|
||||
// Clone the new row and insert it into the table
|
||||
var clone = document.importNode(template.content, true)
|
||||
var div = clone.querySelectorAll("div")
|
||||
var identicon = clone.querySelectorAll("img")
|
||||
|
||||
div[0].classList.add('entry')
|
||||
div[0].setAttribute('timestamp', msg['meta']['time'])
|
||||
|
||||
div[0].setAttribute('data-bl', blockHash)
|
||||
div[2].textContent = msg['content']
|
||||
if (typeof msg['meta']['signer'] != 'undefined' && msg['meta']['signer'].length > 0){
|
||||
div[3].textContent = msg['meta']['signer'].substr(0, 5)
|
||||
setHumanReadableIDOnPost(div[3], msg['meta']['signer'])
|
||||
div[3].title = msg['meta']['signer']
|
||||
userIcon(msg['meta']['signer']).then(function(data){
|
||||
identicon[0].src = "data:image/svg+xml;base64," + data
|
||||
})
|
||||
}
|
||||
else{
|
||||
identicon[0].remove()
|
||||
}
|
||||
div[4].textContent = msgDate
|
||||
|
||||
loadingMessage.style.display = "none"
|
||||
loadedAny = true
|
||||
if (firstLoad){
|
||||
//feed.appendChild(clone)
|
||||
feed.prepend(clone)
|
||||
firstLoad = false
|
||||
}
|
||||
else{
|
||||
if (beforeEl === null){
|
||||
feed.prepend(clone)
|
||||
}
|
||||
else{
|
||||
beforeEl.insertAdjacentElement("beforebegin", clone.children[0])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBlocks(){
|
||||
var feed = document.getElementById("feed")
|
||||
var ch = document.getElementById('feedIDInput').value
|
||||
if (lastLoadedBoard !== ch){
|
||||
requested = []
|
||||
|
||||
toggleLoadingMessage()
|
||||
loadedAny = false
|
||||
|
||||
while (feed.firstChild) feed.removeChild(feed.firstChild); // remove all messages from feed
|
||||
|
||||
setTimeout(function(){
|
||||
if (! loadedAny && ch == document.getElementById('feedIDInput').value){
|
||||
PNotify.notice("There are no posts for " + ch + ". You can be the first!")
|
||||
}
|
||||
}, loadingTimeout)
|
||||
}
|
||||
|
||||
lastLoadedBoard = ch
|
||||
if (document.getElementById('none') !== null){
|
||||
document.getElementById('none').remove();
|
||||
|
||||
}
|
||||
|
||||
fetch('/circles/getpostsbyboard/' + ch, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(feedText) {
|
||||
var blockList = feedText.split(',')
|
||||
|
||||
for (i = 0; i < blockList.length; i++){
|
||||
blockList[i] = "0".repeat(64 - blockList[i].length) + blockList[i] // pad hash with zeroes
|
||||
|
||||
if (! requested.includes(blockList[i])){
|
||||
if (blockList[i].length == 0) continue
|
||||
else requested.push(blockList[i])
|
||||
loadMessage(blockList[i], blockList, i, ch);
|
||||
}
|
||||
}
|
||||
sortEntries()
|
||||
})
|
||||
}
|
||||
|
||||
function loadMessage(blockHash, blockList, count, channel){
|
||||
if (blockHash == '0000000000000000000000000000000000000000000000000000000000000000'){
|
||||
return
|
||||
}
|
||||
fetch('/getblockdata/' + blockHash, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}}).then(function(response) {
|
||||
if (!response.ok) {
|
||||
let on404 = function() {
|
||||
if (response.status == 404){
|
||||
fetch('/circles/removefromcache/' + channel + '/' + blockHash, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}
|
||||
})
|
||||
}
|
||||
else{
|
||||
console.log(error)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
response.json().then(function(data){
|
||||
let before = blockList[count - 1]
|
||||
let delay = 2000
|
||||
if (typeof before == "undefined"){
|
||||
before = null
|
||||
} else {
|
||||
let existing = document.getElementsByClassName('cMsgBox')
|
||||
for (x = 0; x < existing.length; x++){
|
||||
if (existing[x].getAttribute('data-bl') === before){
|
||||
delay = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(function(){appendMessages(data, blockHash, before, channel)}, delay)
|
||||
})
|
||||
return response;
|
||||
})
|
||||
}
|
||||
|
||||
document.getElementById('refreshFeed').onclick = function() {
|
||||
getBlocks()
|
||||
}
|
||||
|
||||
newPostForm.onsubmit = function(){
|
||||
var message = document.getElementById('newMsgText').value
|
||||
var channel = document.getElementById('feedIDInput').value
|
||||
var meta = {'ch': channel}
|
||||
let doSign = document.getElementById('postAnon').checked
|
||||
var postData = {'message': message, 'sign': doSign, 'type': 'brd', 'encrypt': false, 'meta': JSON.stringify(meta)}
|
||||
postData = JSON.stringify(postData)
|
||||
newPostForm.style.display = 'none'
|
||||
fetch('/insertblock', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}
|
||||
})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(data) {
|
||||
newPostForm.style.display = 'block'
|
||||
if (data == 'failure due to duplicate insert'){
|
||||
PNotify.error({
|
||||
text: "This message is already queued"
|
||||
})
|
||||
return
|
||||
}
|
||||
PNotify.success({
|
||||
text: "Message queued for posting"
|
||||
})
|
||||
setTimeout(function(){getBlocks()}, 500)
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
resetCirclePickers = function(){
|
||||
document.getElementById('recommendedBoards').value = ""
|
||||
document.getElementById('popularBoards').value = ""
|
||||
}
|
||||
|
||||
document.getElementById('feedIDInput').onchange = resetCirclePickers
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Handle default board picker
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
recommendedIDs = document.getElementById('recommendedBoards')
|
||||
|
||||
recommendedIDs.onchange = function(){
|
||||
document.getElementById('feedIDInput').value = recommendedIDs.value
|
||||
getBlocks()
|
||||
resetCirclePickers()
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
detect for Circles if plaintext insert/storage is enabled
|
||||
|
||||
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/>.
|
||||
*/
|
||||
plaintext_enabled = null
|
||||
|
||||
fetch('/config/get/general.store_plaintext_blocks', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(data) {
|
||||
plaintext_enabled = true
|
||||
if (data == "false"){
|
||||
plaintext_enabled = false
|
||||
PNotify.error({
|
||||
text: "Plaintext storage is disabled. You will not be able to see new posts or make posts yourself"
|
||||
})
|
||||
}
|
||||
})
|
|
@ -1,196 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<!--Mobile responsive-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
Circles
|
||||
</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="/shared/images/favicon.ico">
|
||||
<link rel="stylesheet" href="/shared/main/PNotifyBrightTheme.css">
|
||||
<link rel="stylesheet" href="/shared/fontawesome-free-5.10.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="/gettheme">
|
||||
<link rel="stylesheet" href="theme.css">
|
||||
<script defer src="/shared/base32.js"></script>
|
||||
<script defer src="/shared/identicon.js"></script>
|
||||
<script defer src="/shared/node_modules/pnotify/dist/iife/PNotify.js"></script>
|
||||
<script defer src="/shared/node_modules/pnotify/dist/iife/PNotifyButtons.js"></script>
|
||||
<script defer src="/shared/useridenticons.js"></script>
|
||||
<script defer src="/shared/misc.js"></script>
|
||||
<script defer src="/shared/navbar.js"></script>
|
||||
<script defer src="/shared/main/apicheck.js"></script>
|
||||
<script defer src="detect-plaintext-storage.js"></script>
|
||||
<script defer src="sethumanreadable.js"></script>
|
||||
<script defer src="default-circle-picker.js"></script>
|
||||
<script defer src="sort-posts.js"></script>
|
||||
<script defer src="board.js"></script>
|
||||
<script defer src="autorefresh.js"></script>
|
||||
<script defer src="popular.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar is-dark" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item idLink" href="/">
|
||||
<img src="/shared/images/favicon.ico" class="navbarLogo">
|
||||
</a>
|
||||
|
||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
||||
data-target="navbarBasic">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="navbarBasic" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item idLink" href="/mail/">Mail</a>
|
||||
<a class="navbar-item idLink" href="/friends/">Friends</a>
|
||||
<a class="navbar-item idLink" href="/board/">Circles</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!--Hero (Dark Section)-->
|
||||
<section class="hero is-small is-dark">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<h1 class="title">
|
||||
Circles <span class="is-pulled-right">v<span id='circlesVersion'></span></span>
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
Anonymous message boards
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<br>
|
||||
|
||||
<!--Start Content-->
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<!--Add Friend-->
|
||||
<div class="column is-one-third">
|
||||
<div class="card">
|
||||
<form method='POST' action='/' id='addMsg'>
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">
|
||||
Post message
|
||||
</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<textarea id='newMsgText' class="textarea" name='newMsgText' rows=10 cols=50 required
|
||||
minlength="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item">
|
||||
<input class='button is-primary' type='submit' value='Post'>
|
||||
</a>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!--Feed-->
|
||||
<div class="column">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">
|
||||
Feed
|
||||
</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<div class="field">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">Circle Name</a>
|
||||
</p>
|
||||
<p class="control is-expanded">
|
||||
<input id="feedIDInput" class="input" placeholder="Board name" value="global">
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-success" id="refreshFeed">Refresh Feed</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="columns">
|
||||
<div class="column is-2">
|
||||
<div class="control">
|
||||
<label for="recommendedBoards" class="label">Default Circles:</label>
|
||||
<div class="select">
|
||||
<select id="recommendedBoards">
|
||||
<option value=""></option>
|
||||
<option value="global">Global</option>
|
||||
<option value="onionr">Onionr</option>
|
||||
<option value="games">Games</option>
|
||||
<option value="politics">Politics</option>
|
||||
<option value="tech">Tech</option>
|
||||
<option value="random">Random</option>
|
||||
<option value="privacy">Privacy</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="control">
|
||||
<label for="popularBoards" class="label">Popular Circles:</label>
|
||||
<div class="select">
|
||||
<select id="popularBoards">
|
||||
<option value=""> </option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="control">
|
||||
<br>
|
||||
Note: All posts in Circles are publicly accessible.
|
||||
</p>
|
||||
<input type="checkbox" class="checkbox" id="refreshCheckbox" checked>
|
||||
<label for="refreshCheckbox">Auto refresh feed</label>
|
||||
<br>
|
||||
<input type="checkbox" class="checkbox" id="postAnon" checked>
|
||||
<label for="postAnon">Sign posts</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span id='loadingBoard'><i class="fas fa-yin-yang fa-spin"></i></span>
|
||||
<div id='feed'>
|
||||
<span id='none'>None yet, try refreshing 😃</span>
|
||||
<!--Message Items are appended here based on template-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Template markup for Circle message-->
|
||||
<template id="cMsgTemplate">
|
||||
<div class="box cMsgBox">
|
||||
<div class="columns">
|
||||
<div class="column cMsg">
|
||||
Message
|
||||
</div>
|
||||
<div class="column cAuthor is-narrow"></div>
|
||||
<img class="identicon image is-48x48" alt="user icon" src="/shared/images/anon.svg">
|
||||
<div class="column is-narrow cMsgDate">
|
||||
Date
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Load popular boards and show them in the UI. Handle selections of popular boards.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
fetch('/circles/getpopular/8', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((popular) => popular.text())
|
||||
.then(function(popular) {
|
||||
var popularSelect = document.getElementById('popularBoards')
|
||||
let boards = popular.split(',')
|
||||
for (board of boards){
|
||||
let newOption = document.createElement('option')
|
||||
if (board == ""){continue}
|
||||
newOption.value = board
|
||||
newOption.innerText = board.charAt(0).toUpperCase() + board.slice(1)
|
||||
console.debug(board)
|
||||
popularSelect.appendChild(newOption)
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById('popularBoards').onchange = function(){
|
||||
document.getElementById('feedIDInput').value = document.getElementById('popularBoards').value
|
||||
getBlocks()
|
||||
resetCirclePickers()
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Set human readable public keys onto post author elements
|
||||
|
||||
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/>.
|
||||
*/
|
||||
humanReadableKeys = {}
|
||||
|
||||
function setHumanReadableIDOnPost(el, key){
|
||||
if (typeof humanReadableKeys[key] == "undefined"){
|
||||
fetch('/getHumanReadable/' + key, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text()) // Transform the data into json
|
||||
.then(function(data) {
|
||||
if (data.includes('HTML')){
|
||||
return
|
||||
}
|
||||
humanReadableKeys[key] = data
|
||||
setHumanReadableIDOnPost(el, key)
|
||||
})
|
||||
return
|
||||
}
|
||||
el.innerText = humanReadableKeys[key].split('-').slice(0, 3).join(' ')
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Sort post entries
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
function sortEntries() {
|
||||
var entries = document.getElementsByClassName('entry')
|
||||
|
||||
if (entries.length > 1) {
|
||||
const sortBy = 'timestamp'
|
||||
const parent = entries[0].parentNode
|
||||
|
||||
const sorted = Array.from(entries).sort((a, b) => b.getAttribute(sortBy) - a.getAttribute(sortBy))
|
||||
sorted.forEach(element => parent.appendChild(element))
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
.cMsg{
|
||||
word-wrap:break-word;
|
||||
word-break:break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
body{
|
||||
background-color: #212224;
|
||||
color: white;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Settings modal closing
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
document.getElementById('closeSettingsModalButton').onclick = function(){
|
||||
document.getElementById('settingsModal').classList.remove('is-active')
|
||||
setActiveTab('inbox')
|
||||
}
|
||||
|
||||
document.querySelector("#settingsModal .modal-background").onclick = function(){
|
||||
document.getElementById('settingsModal').classList.remove('is-active')
|
||||
setActiveTab('inbox')
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
Onionr Mail
|
||||
</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="/shared/images/favicon.ico">
|
||||
<link rel="stylesheet" href="/shared/fontawesome-free-5.10.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="/shared/main/PNotifyBrightTheme.css">
|
||||
<link rel="stylesheet" href="/gettheme">
|
||||
<link rel="stylesheet" href="/shared/node_modules/bulma-switch/dist/css/bulma-switch.min.css">
|
||||
<link rel="stylesheet" href="/mail/mail.css">
|
||||
<script defer src="/shared/node_modules/pnotify/dist/iife/PNotify.js"></script>
|
||||
<script defer src="/shared/node_modules/pnotify/dist/iife/PNotifyButtons.js"></script>
|
||||
<script defer src="/shared/main/apicheck.js"></script>
|
||||
<script defer src="/shared/misc.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/sendmail.js"></script>
|
||||
<script defer src="/mail/closesettings.js"></script>
|
||||
<script defer src="/mail/settings.js"></script>
|
||||
<script defer src="/shared/navbar.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar is-dark" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item idLink" href="/">
|
||||
<img src="/shared/images/favicon.ico" class="navbarLogo">
|
||||
</a>
|
||||
|
||||
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
|
||||
data-target="navbarBasic">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="navbarBasic" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item idLink" href="/mail/">Mail</a>
|
||||
<a class="navbar-item idLink" href="/friends/">Friends</a>
|
||||
<a class="navbar-item idLink" href="/board/">Circles</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!--Hero (Dark Section)-->
|
||||
<section class="hero is-small is-dark">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<h1 class="title">
|
||||
Mail
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
Private and safe messages
|
||||
</h2>
|
||||
</div>
|
||||
<div class="column is-7">
|
||||
<div class="field">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">
|
||||
<i class="fas fa-fingerprint"></i>
|
||||
</a>
|
||||
</p>
|
||||
<p class="control is-expanded">
|
||||
<input id="myPub" class="input myPub" type="text" readonly>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a id="myPubCopy" class="button is-primary"><i class="fas fa-copy"></i></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<br>
|
||||
<div id="messageDisplay" class="overlay">
|
||||
<div class="overlayContent">
|
||||
<span class="closeOverlay" overlay="messageDisplay"></span>
|
||||
<div>
|
||||
From: <input type="text" id="fromUser" readonly> Signature: <span id="sigValid"></span> <span
|
||||
id="addUnknownContact"><button class="button is-primary">Add to Contacts</button></span>
|
||||
</div>
|
||||
<div class="break-up">
|
||||
Subject: <span id="subjectView"></span>
|
||||
</div>
|
||||
<div>
|
||||
<button id="replyBtn" class="button is-primary break-up">Reply</button>
|
||||
</div>
|
||||
<div id="signatureValidity"></div>
|
||||
<div id="threadDisplay" class="pre messageContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sentboxDisplay" class="overlay">
|
||||
<div class="overlayContent">
|
||||
<span class="closeOverlay" overlay="sentboxDisplay"></span>
|
||||
To: <input id="toID" readonly type="text">
|
||||
<div id="sentboxDisplayText" class="pre messageContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settingsModal" class="modal">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head">
|
||||
<button id="closeSettingsModalButton" class="closeSettingsModal delete" aria-label="close"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div>Ask senders to use forward-secrecy</div>
|
||||
<small>Turn off if using 1 ID on more than 1 device, or have Onionr data erasure on exit enabled.</small>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="field">
|
||||
<input id="forwardSecrecySetting" type="checkbox"
|
||||
class="switch is-rounded is-danger" checked>
|
||||
<label for="forwardSecrecySetting"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div>Message padding</div>
|
||||
<small>Improves privacy slightly for a small performance hit.</small>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="field">
|
||||
<input id="messagePaddingSetting" type="checkbox"
|
||||
class="switch is-rounded is-warning">
|
||||
<label for="messagePaddingSetting"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
Inbox notifications
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="field">
|
||||
<input id="notificationSetting" type="checkbox"
|
||||
class="switch is-rounded" checked>
|
||||
<label for="notificationSetting"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns notificationSetting">
|
||||
<div class="column">
|
||||
Notifications for stranger's messages
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="field">
|
||||
<input id="strangersNotification" type="checkbox"
|
||||
class="switch is-rounded" checked>
|
||||
<label for="strangersNotification"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns notificationSetting">
|
||||
<div class="column">
|
||||
Notification sound
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<div class="field">
|
||||
<input id="notificationSound" type="checkbox"
|
||||
class="switch is-rounded" checked>
|
||||
<label for="notificationSound"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Signature
|
||||
<textarea id="mailSignatureSetting" class="textarea" placeholder="Signature to add to every message" rows="5"></textarea>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<!--Start of content-->
|
||||
<div class="container">
|
||||
<div class="tabs" id="tabBtns">
|
||||
<ul>
|
||||
<li class="is-active">
|
||||
<a>
|
||||
<span class="icon">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</span>
|
||||
<span id="inboxTab">Inbox</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span class="icon">
|
||||
<i class="fa fa-paper-plane"></i>
|
||||
</span>
|
||||
<span>Sent</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span class="icon">
|
||||
<i class="fa fa-pen"></i>
|
||||
</span>
|
||||
<span>Compose</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
<span class="icon">
|
||||
<i class="fa fa-cog"></i>
|
||||
</span>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content" id="noInbox">No messages to show ¯\_(ツ)_/¯</div>
|
||||
<div class="content">
|
||||
<div class="mailPing">
|
||||
API server either shutdown, has disabled mail, or has experienced a bug.
|
||||
</div>
|
||||
<div id="threads" class="threads">
|
||||
<div id="threadPlaceholder">Nothing here yet 😞</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sendMessage">
|
||||
<div class="container">
|
||||
<div class="field">
|
||||
<label><i class="fas fa-user"></i> Select friend: <select id="friendSelect"></select></label>
|
||||
</div>
|
||||
<form method="post" action="" id="sendForm" enctype="application/x-www-form-urlencoded">
|
||||
<div class="field">
|
||||
To: <input id="draftID" type="text" name="to" placeholder="pubkey or select above" required>
|
||||
</div>
|
||||
Subject: <input name="subject" id="draftSubject" maxlength="25" type="text"
|
||||
placeholder="message subject">
|
||||
<div class="field">
|
||||
<textarea name="message" class="textarea" placeholder="type your message..." id="draftText" required></textarea>
|
||||
</div>
|
||||
<input type="submit" value="Send" class="button is-primary successBtn">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="infoOverlay" class="overlay">
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
mailSettings = {}
|
||||
|
||||
fetch('/config/get/mail', {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.json())
|
||||
.then(function(settings) {
|
||||
mailSettings = settings || {}
|
||||
if (mailSettings.default_forward_secrecy === false){
|
||||
document.getElementById('forwardSecrecySetting').checked = false
|
||||
}
|
||||
if (mailSettings.use_padding === false){
|
||||
document.getElementById('messagePaddingSetting').checked = false
|
||||
}
|
||||
if (mailSettings.notificationSetting === false){
|
||||
document.getElementById('notificationSetting').checked = false
|
||||
}
|
||||
if (mailSettings.notificationSound === false){
|
||||
document.getElementById('notificationSound').checked = false
|
||||
}
|
||||
if (typeof mailSettings.signature != undefined && mailSettings.signature != null && mailSettings.signature != ""){
|
||||
document.getElementById('mailSignatureSetting').value = mailSettings.signature
|
||||
}
|
||||
if (mailSettings.strangersNotification == false){
|
||||
document.getElementById('strangersNotification').checked = false
|
||||
}
|
||||
})
|
|
@ -1,60 +0,0 @@
|
|||
.threadEntry button{
|
||||
margin-right: 1%;
|
||||
}
|
||||
.threadEntry span, .sentboxList span{
|
||||
padding-left: 1%;
|
||||
}
|
||||
.threadEntry, .sentboxList{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.overlayContent{
|
||||
background-color: lightgray;
|
||||
border: 3px solid black;
|
||||
border-radius: 3px;
|
||||
color: black;
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
min-height: 100%;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
#draftText{
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
display: block;
|
||||
width: 50%;
|
||||
height: 75%;
|
||||
min-width: 2%;
|
||||
min-height: 5%;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.sentboxList{
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.messageContent{
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
|
||||
#tabBtns ul .icon {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
#settingsModal .modal-card-body{
|
||||
font-size: 150%;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
#settingsModal textarea{
|
||||
resize: none;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
#settingsModal small{
|
||||
font-size: 0.5em;
|
||||
}
|
|
@ -1,450 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
This file handles the mail interface
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
pms = ''
|
||||
sentbox = ''
|
||||
threadPart = document.getElementById('threads')
|
||||
threadPlaceholder = document.getElementById('threadPlaceholder')
|
||||
tabBtns = document.getElementById('tabBtns')
|
||||
threadContent = {}
|
||||
replyBtn = document.getElementById('replyBtn')
|
||||
addUnknownContact = document.getElementById('addUnknownContact')
|
||||
noInbox = document.getElementById('noInbox')
|
||||
humanReadableCache = {}
|
||||
|
||||
function stripEndZeroes(str){
|
||||
str = str.split("")
|
||||
let zeroCount = 0
|
||||
for (x = str.length - 1; x != 0; x--){
|
||||
if (str[x] == "0"){
|
||||
zeroCount += 1
|
||||
}
|
||||
else{
|
||||
break
|
||||
}
|
||||
}
|
||||
str.splice(str.length - zeroCount, zeroCount)
|
||||
str = str.join("")
|
||||
return str
|
||||
}
|
||||
|
||||
async function addContact(pubkey, friendName){
|
||||
fetch('/friends/add/' + pubkey, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"token": webpass
|
||||
}}).then(function(data) {
|
||||
if (friendName.trim().length > 0){
|
||||
post_to_url('/friends/setinfo/' + pubkey + '/name', {'data': friendName, 'token': webpass})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function openReply(bHash, quote, subject){
|
||||
var inbox = document.getElementsByClassName('threadEntry')
|
||||
var entry = ''
|
||||
var friendName = ''
|
||||
var key = ''
|
||||
for(var i = 0; i < inbox.length; i++) {
|
||||
if (inbox[i].getAttribute('data-hash') === bHash){
|
||||
entry = inbox[i]
|
||||
}
|
||||
}
|
||||
if (entry.getAttribute('data-nameset') == 'true'){
|
||||
document.getElementById('friendSelect').value = document.getElementById('fromUser').value
|
||||
}
|
||||
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]
|
||||
}
|
||||
|
||||
if (typeof humanReadableCache[key] != 'undefined'){
|
||||
document.getElementById('draftID').value = humanReadableCache[key]
|
||||
quote = '\n' + humanReadableCache[key].split('-').slice(0,3).join('-') + ' wrote:\n' + splitQuotes.join('\n')
|
||||
}
|
||||
else{
|
||||
quote = '\n' + key.substring(0, 12) + ' wrote:' + '\n' + splitQuotes.join('\n')
|
||||
}
|
||||
document.getElementById('draftText').value = quote
|
||||
setActiveTab('compose')
|
||||
}
|
||||
|
||||
function openThread(bHash, sender, date, sigBool, pubkey, subjectLine){
|
||||
addUnknownContact.style.display = 'none'
|
||||
var messageDisplay = document.getElementById('threadDisplay')
|
||||
|
||||
fetch('/getblockbody/' + bHash, {
|
||||
"method": "get",
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(resp) {
|
||||
document.getElementById('fromUser').value = sender || 'Anonymous'
|
||||
document.getElementById('fromUser').value = pubkey || ''
|
||||
document.getElementById('subjectView').innerText = subjectLine
|
||||
|
||||
resp = stripEndZeroes(resp)
|
||||
|
||||
messageDisplay.innerText = resp
|
||||
var sigEl = document.getElementById('sigValid')
|
||||
var sigMsg = 'signature'
|
||||
|
||||
// show add unknown contact button if peer is unknown
|
||||
if (sender !== myPub && sigBool){
|
||||
addUnknownContact.style.display = 'inline'
|
||||
}
|
||||
|
||||
if (sigBool){
|
||||
sigMsg = 'Good ' + sigMsg
|
||||
sigEl.classList.remove('danger')
|
||||
}
|
||||
else{
|
||||
sigMsg = 'Bad/no ' + sigMsg + ' (message could be impersonating someone)'
|
||||
sigEl.classList.add('danger')
|
||||
replyBtn.style.display = 'none'
|
||||
}
|
||||
sigEl.innerText = sigMsg
|
||||
overlay('messageDisplay')
|
||||
replyBtn.onclick = function(){
|
||||
document.getElementById('messageDisplay').style.visibility = 'hidden'
|
||||
openReply(bHash, messageDisplay.innerText, subjectLine)
|
||||
}
|
||||
addUnknownContact.onclick = function(){
|
||||
var friendName = prompt("Enter an alias for this contact:")
|
||||
if (friendName === null || friendName.length == 0){
|
||||
return
|
||||
}
|
||||
addContact(pubkey, friendName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setActiveTab(tabName){
|
||||
threadPart.innerHTML = ""
|
||||
noInbox.style.display = 'none'
|
||||
window.inboxActive = false
|
||||
document.getElementById('sendMessage').classList.add('is-hidden')
|
||||
switch(tabName){
|
||||
case 'inbox':
|
||||
window.inboxActive = true
|
||||
refreshPms()
|
||||
getInbox()
|
||||
break
|
||||
case 'sent':
|
||||
getSentbox()
|
||||
break
|
||||
case 'compose':
|
||||
document.getElementById('sendMessage').classList.remove('is-hidden')
|
||||
break
|
||||
case 'settings':
|
||||
document.getElementById('settingsModal').classList.add('is-active')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function deleteMessage(bHash){
|
||||
fetch('/mail/deletemsg/' + bHash, {
|
||||
"method": "post",
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
}
|
||||
|
||||
function mailPing(){
|
||||
fetch('/mail/ping', {
|
||||
"method": "get",
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(resp) {
|
||||
var pings = document.getElementsByClassName('mailPing')
|
||||
if (resp.ok){
|
||||
for (var i=0; i < pings.length; i++){
|
||||
pings[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (var i=0; i < pings.length; i++){
|
||||
pings[i].style.display = 'block';
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function loadInboxEntries(bHash){
|
||||
fetch('/getblockheader/' + bHash, {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.json()) // Transform the data into json
|
||||
.then(function(resp) {
|
||||
//console.log(resp)
|
||||
var entry = document.createElement('div')
|
||||
var bHashDisplay = document.createElement('span')
|
||||
//var senderInput = document.createElement('input')
|
||||
var senderInput = document.createElement('span')
|
||||
var subjectLine = document.createElement('span')
|
||||
var dateStr = document.createElement('span')
|
||||
var validSig = document.createElement('span')
|
||||
var deleteBtn = document.createElement('button')
|
||||
var humanDate = new Date(0)
|
||||
var metadata = resp['metadata']
|
||||
humanDate.setUTCSeconds(resp['meta']['time'])
|
||||
humanDate = humanDate.toString()
|
||||
validSig.style.display = 'none'
|
||||
|
||||
if (typeof resp['meta']['signer'] != 'undefined' && resp['meta']['signer'] != ''){
|
||||
fetch('/friends/getinfo/' + resp['meta']['signer'] + '/name', {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(resp2){
|
||||
if (!resp2.ok){
|
||||
setHumanReadableValue(senderInput, resp['meta']['signer'])
|
||||
entry.setAttribute('data-nameSet', false)
|
||||
}
|
||||
else{
|
||||
resp2.text().then(function(resp2){
|
||||
loadHumanReadableToCache(resp['meta']['signer'])
|
||||
senderInput.innerText = resp2
|
||||
entry.setAttribute('data-nameSet', true)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
else{
|
||||
senderInput.innerText = 'Anonymous'
|
||||
entry.setAttribute('data-nameSet', false)
|
||||
}
|
||||
if (! resp['meta']['validSig']){
|
||||
validSig.style.display = 'inline'
|
||||
validSig.innerText = 'Signature Validity: Bad'
|
||||
validSig.style.color = 'red'
|
||||
}
|
||||
//bHashDisplay.innerText = bHash.substring(0, 10)
|
||||
entry.setAttribute('data-hash', bHash)
|
||||
entry.setAttribute('data-pubkey', resp['meta']['signer'])
|
||||
senderInput.readOnly = true
|
||||
dateStr.innerText = humanDate.substring(0, humanDate.indexOf('('))
|
||||
deleteBtn.classList.add('delete', 'deleteBtn')
|
||||
if (metadata['subject'] === undefined || metadata['subject'] === null) {
|
||||
subjectLine.innerText = '()'
|
||||
}
|
||||
else{
|
||||
subjectLine.innerText = '(' + metadata['subject'] + ')'
|
||||
}
|
||||
//entry.innerHTML = 'sender ' + resp['meta']['signer'] + ' - ' + resp['meta']['time']
|
||||
threadPart.appendChild(entry)
|
||||
entry.appendChild(deleteBtn)
|
||||
entry.appendChild(bHashDisplay)
|
||||
entry.appendChild(senderInput)
|
||||
entry.appendChild(subjectLine)
|
||||
entry.appendChild(dateStr)
|
||||
entry.appendChild(validSig)
|
||||
entry.classList.add('threadEntry')
|
||||
|
||||
entry.onclick = function(event){
|
||||
if (event.target.classList.contains('deleteBtn')){
|
||||
return
|
||||
}
|
||||
openThread(entry.getAttribute('data-hash'), senderInput.innerText, dateStr.innerText, resp['meta']['validSig'], entry.getAttribute('data-pubkey'), subjectLine.innerText)
|
||||
}
|
||||
|
||||
deleteBtn.onclick = function(){
|
||||
entry.parentNode.removeChild(entry);
|
||||
deleteMessage(entry.getAttribute('data-hash'))
|
||||
}
|
||||
|
||||
}.bind(bHash))
|
||||
}
|
||||
|
||||
function getInbox(){
|
||||
if (! window.inboxActive){
|
||||
return
|
||||
}
|
||||
var els = document.getElementsByClassName('threadEntry')
|
||||
var showed = false
|
||||
for(var i = 0; i < pms.length; i++) {
|
||||
var add = true
|
||||
if (pms[i].trim().length == 0){
|
||||
noInbox.style.display = 'block'
|
||||
continue
|
||||
}
|
||||
else{
|
||||
threadPlaceholder.style.display = 'none'
|
||||
showed = true
|
||||
}
|
||||
for (var x = 0; x < els.length; x++){
|
||||
if (pms[i] === els[x].getAttribute('data-hash')){
|
||||
add = false
|
||||
}
|
||||
}
|
||||
if (add && window.inboxActive) {
|
||||
loadInboxEntries(pms[i])
|
||||
}
|
||||
}
|
||||
if (! showed){
|
||||
threadPlaceholder.style.display = 'block'
|
||||
}
|
||||
}
|
||||
|
||||
function getSentbox(){
|
||||
fetch('/mail/getsentbox', {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.json()) // Transform the data into json
|
||||
.then(function(resp) {
|
||||
var keys = [];
|
||||
var entry = document.createElement('div')
|
||||
for(var k in resp) keys.push(k);
|
||||
if (keys.length == 0){
|
||||
threadPart.innerHTML = "nothing to show here yet."
|
||||
}
|
||||
for (var i = keys.length - 1; i > -1; i--) (function(i, resp){
|
||||
var entry = document.createElement('div')
|
||||
var toLabel = document.createElement('span')
|
||||
toLabel.innerText = 'To: '
|
||||
var toEl = document.createElement('span')
|
||||
toEl.classList.add('toElement')
|
||||
var sentDate = document.createElement('span')
|
||||
var humanDate = new Date(0)
|
||||
humanDate.setUTCSeconds(resp[i]['date'])
|
||||
humanDate = humanDate.toString()
|
||||
var preview = document.createElement('span')
|
||||
var deleteBtn = document.createElement('button')
|
||||
var message = resp[i]['message']
|
||||
deleteBtn.classList.add('deleteBtn', 'delete')
|
||||
|
||||
sentDate.innerText = humanDate.substring(0, humanDate.indexOf('('))
|
||||
if (resp[i]['name'] == null || resp[i]['name'].toLowerCase() == 'anonymous'){
|
||||
toEl.innerText = resp[i]['peer']
|
||||
setHumanReadableValue(toEl, resp[i]['peer'])
|
||||
}
|
||||
else{
|
||||
toEl.innerText = resp[i]['name']
|
||||
}
|
||||
preview.innerText = '(' + resp[i]['subject'] + ')'
|
||||
entry.classList.add('sentboxList')
|
||||
entry.setAttribute('data-hash', resp[i]['hash'])
|
||||
entry.appendChild(deleteBtn)
|
||||
entry.appendChild(toLabel)
|
||||
entry.appendChild(toEl)
|
||||
entry.appendChild(preview)
|
||||
entry.appendChild(sentDate)
|
||||
|
||||
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(toEl.innerText, message)
|
||||
}
|
||||
})(i, resp)
|
||||
threadPart.appendChild(entry)
|
||||
}.bind(threadPart))
|
||||
}
|
||||
|
||||
function showSentboxWindow(to, content){
|
||||
content = stripEndZeroes(content)
|
||||
document.getElementById('toID').value = to
|
||||
document.getElementById('sentboxDisplayText').innerText = content
|
||||
overlay('sentboxDisplay')
|
||||
}
|
||||
|
||||
function refreshPms(callNext){
|
||||
if (! window.inboxActive){
|
||||
return
|
||||
}
|
||||
fetch('/mail/getinbox', {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(data) {
|
||||
pms = data.split(',')
|
||||
if (pms.length > 0){
|
||||
noInbox.style.display = 'none'
|
||||
}
|
||||
if (callNext){
|
||||
getInbox()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
tabBtns.onclick = function(event){
|
||||
var children = tabBtns.children[0].children
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var btn = children[i]
|
||||
btn.classList.remove('is-active')
|
||||
}
|
||||
event.target.parentElement.parentElement.classList.add('is-active')
|
||||
setActiveTab(event.target.innerText.toLowerCase())
|
||||
}
|
||||
|
||||
for (var i = 0; i < document.getElementsByClassName('refresh').length; i++){
|
||||
document.getElementsByClassName('refresh')[i].style.float = 'right'
|
||||
}
|
||||
|
||||
fetch('/friends/list', {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.json()) // Transform the data into json
|
||||
.then(function(resp) {
|
||||
var friendSelectParent = document.getElementById('friendSelect')
|
||||
var keys = [];
|
||||
for(var k in resp) keys.push(k);
|
||||
|
||||
friendSelectParent.appendChild(document.createElement('option'))
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var option = document.createElement("option")
|
||||
var name = resp[keys[i]]['name'] || ""
|
||||
option.value = keys[i]
|
||||
if (name.length == 0){
|
||||
option.text = keys[i]
|
||||
}
|
||||
else{
|
||||
option.text = name
|
||||
}
|
||||
friendSelectParent.appendChild(option)
|
||||
}
|
||||
})
|
||||
setActiveTab('inbox')
|
||||
|
||||
setInterval(function(){mailPing()}, 10000)
|
||||
mailPing()
|
||||
window.inboxInterval = setInterval(function(){refreshPms(true)}, 3000)
|
||||
refreshPms(true)
|
||||
|
||||
document.addEventListener("visibilitychange", function() {
|
||||
if (document.visibilityState === 'visible') {
|
||||
refreshPms()
|
||||
}
|
||||
})
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
This file handles the mail interface
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
var sendbutton = document.getElementById('sendMail')
|
||||
messageContent = document.getElementById('draftText')
|
||||
to = document.getElementById('draftID')
|
||||
subject = document.getElementById('draftSubject')
|
||||
friendPicker = document.getElementById('friendSelect')
|
||||
|
||||
function utf8Length(s) {
|
||||
var size = encodeURIComponent(s).match(/%[89ABab]/g);
|
||||
return s.length + (size ? size.length : 0);
|
||||
}
|
||||
|
||||
function padString(string_data, round_nearest_byte_exponent = 3){
|
||||
if (utf8Length(string_data) === 0){
|
||||
string_data += '0'
|
||||
}
|
||||
let round_size = 10 ** round_nearest_byte_exponent
|
||||
while (utf8Length(string_data) % round_size > 0){
|
||||
string_data += '0'
|
||||
}
|
||||
return string_data
|
||||
}
|
||||
|
||||
function sendMail(toData, message, subject){
|
||||
let meta = {'subject': subject}
|
||||
|
||||
if (document.getElementById('messagePaddingSetting').checked){
|
||||
message = padString(message)
|
||||
}
|
||||
|
||||
if (document.getElementById('mailSignatureSetting').value !== false){
|
||||
message += "\n"
|
||||
message += document.getElementById('mailSignatureSetting').value
|
||||
}
|
||||
|
||||
postData = {'message': message, 'to': toData, 'type': 'pm', 'encrypt': true, 'meta': JSON.stringify(meta)}
|
||||
postData.forward = document.getElementById('forwardSecrecySetting').checked
|
||||
postData = JSON.stringify(postData)
|
||||
sendForm.style.display = 'none'
|
||||
|
||||
fetch('/insertblock', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text()) // Transform the data into text
|
||||
.then(function(data) {
|
||||
sendForm.style.display = 'block'
|
||||
PNotify.success({
|
||||
text: 'Queued for sending!',
|
||||
delay: 3500,
|
||||
mouseReset: false
|
||||
})
|
||||
to.value = subject.value = messageContent.value = ""
|
||||
friendPicker.value = ""
|
||||
subject.value = ""
|
||||
})
|
||||
}
|
||||
|
||||
var friendPicker = document.getElementById('friendSelect')
|
||||
friendPicker.onchange = function(){
|
||||
to.value = friendPicker.value
|
||||
}
|
||||
|
||||
sendForm.onsubmit = function(){
|
||||
if (! to.value.includes("-") && to.value.length !== 56 && to.value.length !== 52){
|
||||
PNotify.error({
|
||||
text: 'User ID is not valid'
|
||||
})
|
||||
}
|
||||
else{
|
||||
sendMail(to.value, messageContent.value, subject.value)
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Load human readable public keys into a cache
|
||||
|
||||
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/>.
|
||||
*/
|
||||
function loadHumanReadableToCache(key){
|
||||
fetch('/getHumanReadable/' + key, {
|
||||
headers: {
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(resp) {
|
||||
humanReadableCache[key] = resp
|
||||
})
|
||||
}
|
||||
|
||||
function setHumanReadableValue(el, key){
|
||||
if (typeof humanReadableCache[key] != 'undefined'){
|
||||
el.innerText = humanReadableCache[key].split('-').slice(0,3).join('-')
|
||||
return
|
||||
}
|
||||
else{
|
||||
loadHumanReadableToCache(key)
|
||||
setTimeout(function(){setHumanReadableValue(el, key)}, 100)
|
||||
return
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Handle mail settings
|
||||
|
||||
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/>.
|
||||
*/
|
||||
var notificationSetting = document.getElementById('notificationSetting')
|
||||
var friendOnlyNotification = document.getElementById('strangersNotification')
|
||||
var notificationSound = document.getElementById('notificationSound')
|
||||
var sigSetting = document.getElementById('mailSignatureSetting')
|
||||
|
||||
document.getElementById('forwardSecrecySetting').onchange = function(e){
|
||||
postData = JSON.stringify({"default_forward_secrecy": e.target.checked})
|
||||
fetch('/config/set/mail', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then((resp) => resp.text())
|
||||
.then(function(data) {
|
||||
mailSettings['forwardSecrecy'] = document.getElementById('forwardSecrecySetting').checked
|
||||
PNotify.success({
|
||||
text: 'Successfully toggled default forward secrecy'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
notificationSound.onchange = function(e){
|
||||
var postData = JSON.stringify({"notificationSound": e.target.checked})
|
||||
fetch('/config/set/mail', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(data) {
|
||||
mailSettings['notificationSound'] = notificationSound.checked
|
||||
PNotify.success({
|
||||
text: 'Successfully notification sound'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
friendOnlyNotification.onchange = function(e){
|
||||
var postData = JSON.stringify({"strangersNotification": e.target.checked})
|
||||
fetch('/config/set/mail', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(data) {
|
||||
mailSettings['strangersNotification'] = friendOnlyNotification.checked
|
||||
PNotify.success({
|
||||
text: 'Successfully toggled notifications from strangers'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
notificationSetting.onchange = function(e){
|
||||
var notificationSettings = document.getElementsByClassName('notificationSetting')
|
||||
if (e.target.checked){
|
||||
for (i = 0; i < notificationSettings.length; i++){
|
||||
notificationSettings[i].style.display = "flex"
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (i = 0; i < notificationSettings.length; i++){
|
||||
notificationSettings[i].style.display = "none"
|
||||
}
|
||||
}
|
||||
var postData = JSON.stringify({"notificationSetting": e.target.checked})
|
||||
fetch('/config/set/mail', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(data) {
|
||||
mailSettings['notificationSetting'] = notificationSetting.checked
|
||||
PNotify.success({
|
||||
text: 'Successfully toggled default mail notifications'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
sigSetting.onchange = function(){
|
||||
var postData = JSON.stringify({"signature": sigSetting.value})
|
||||
fetch('/config/set/mail', {
|
||||
method: 'POST',
|
||||
body: postData,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"token": webpass
|
||||
}})
|
||||
.then(function(data) {
|
||||
mailSettings['signature'] = sigSetting.value
|
||||
PNotify.success({
|
||||
text: 'Set mail signature'
|
||||
})
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue